1 /*
2 TiMidity++ -- MIDI to WAVE converter and player
3 Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4 Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 vorbis_a.c
21
22 Functions to output Ogg Vorbis (*.ogg).
23 */
24
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif /* HAVE_CONFIG_H */
28 #include "interface.h"
29 #include <stdio.h>
30 #include <string.h>
31
32 #ifdef AU_VORBIS
33
34 #ifdef AU_VORBIS_DLL
35 #include <stdlib.h>
36 #include <io.h>
37 #include <ctype.h>
38 extern int load_ogg_dll(void);
39 extern void free_ogg_dll(void);
40 extern int load_vorbis_dll(void);
41 extern void free_vorbis_dll(void);
42 extern int load_vorbisenc_dll(void);
43 extern void free_vorbisenc_dll(void);
44 #endif
45
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif /* HAVE_UNISTD_H */
49
50 #ifdef STDC_HEADERS
51 #include <string.h>
52 #include <stdlib.h>
53 #include <ctype.h>
54 #include <time.h>
55 #elif HAVE_STRINGS_H
56 #include <strings.h>
57 #endif
58 #ifdef HAVE_FCNTL_H
59 #include <fcntl.h>
60 #endif
61
62 #ifdef __W32__
63 #include <windows.h>
64 #include <winnls.h>
65 #endif
66
67 #include <vorbis/vorbisenc.h>
68
69 #include "timidity.h"
70 #include "common.h"
71 #include "output.h"
72 #include "controls.h"
73 #include "instrum.h"
74 #include "playmidi.h"
75 #include "readmidi.h"
76
77 static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
78 static void close_output(void);
79 static int output_data(char *buf, int32 bytes);
80 static int acntl(int request, void *arg);
81
82 /* export the playback mode */
83 #define dpm vorbis_play_mode
84
85 PlayMode dpm = {
86 44100, PE_16BIT|PE_SIGNED, PF_PCM_STREAM|PF_FILE_OUTPUT,
87 -1,
88 {0,0,0,0,0},
89 "Ogg Vorbis", 'v',
90 NULL,
91 open_output,
92 close_output,
93 output_data,
94 acntl
95 };
96 static char *tag_title = NULL;
97
98 static ogg_stream_state os; /* take physical pages, weld into a logical
99 stream of packets */
100 static vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
101 static vorbis_block vb; /* local working space for packet->PCM decode */
102 static vorbis_info vi; /* struct that stores all the static vorbis bitstream
103 settings */
104 static vorbis_comment vc; /* struct that stores all the user comments */
105
106 #if defined ( IA_W32GUI ) || defined ( IA_W32G_SYN )
107 extern char *w32g_output_dir;
108 extern int w32g_auto_output_mode;
109 extern int vorbis_ConfigDialogInfoApply(void);
110 int ogg_vorbis_mode = 8; /* initial mode. */
111 #endif
112
113 /*************************************************************************/
114
115 #if defined ( IA_W32GUI ) || defined ( IA_W32G_SYN )
116 static int
choose_bitrate(int nch,int rate)117 choose_bitrate(int nch, int rate)
118 {
119 int bitrate;
120
121 #if 0
122 /* choose an encoding mode */
123 /* (mode 0: -> mode2 */
124 /* (mode 1: 44kHz stereo uncoupled, N/A\n */
125 /* (mode 2: 44kHz stereo uncoupled, roughly 128kbps VBR) */
126 /* (mode 3: 44kHz stereo uncoupled, roughly 160kbps VBR) */
127 /* (mode 4: 44kHz stereo uncoupled, roughly 192kbps VBR) */
128 /* (mode 5: 44kHz stereo uncoupled, roughly 256kbps VBR) */
129 /* (mode 6: 44kHz stereo uncoupled, roughly 350kbps VBR) */
130
131 switch (ogg_vorbis_mode) {
132 case 0:
133 bitrate = 128 * 1000; break;
134 case 1:
135 bitrate = 112 * 1000; break;
136 case 2:
137 bitrate = 128 * 1000; break;
138 case 3:
139 bitrate = 160 * 1000; break;
140 case 4:
141 bitrate = 192 * 1000; break;
142 case 5:
143 bitrate = 256 * 1000; break;
144 case 6:
145 bitrate = 350 * 1000; break;
146 default:
147 bitrate = 160 * 1000; break;
148 }
149 return bitrate;
150 #else
151 if (ogg_vorbis_mode < 1 || ogg_vorbis_mode > 1000)
152 bitrate = 8;
153 else
154 bitrate = ogg_vorbis_mode;
155 return bitrate;
156 #endif
157 return (int)(nch * rate * (128000.0 / (2.0 * 44100.0)) + 0.5); /* +0.5 for rounding */
158 }
159 #else
160 static int
choose_bitrate(int nch,int rate)161 choose_bitrate(int nch, int rate)
162 {
163 int target;
164
165 /* 44.1kHz 2ch --> 128kbps */
166 target = (int)(nch * rate * (128000.0 / (2.0 * 44100.0)) + 0.5); /* +0.5 for rounding */
167
168 return target;
169 }
170 #endif
171
172 #ifdef __W32__
w32_mbs_to_utf8(const char * str)173 static char *w32_mbs_to_utf8(const char* str)
174 {
175 int str_size = strlen(str);
176 int buff16_size = str_size;
177 wchar_t* buff16;
178 int buff8_size = 0;
179 char* buff8;
180 char* buff8_p;
181 int i;
182 if ( str_size == 0 ) {
183 return strdup ( str );
184 }
185 buff16 = (wchar_t*) malloc (sizeof(wchar_t)*buff16_size + 1);
186 if ( buff16 == NULL ) return NULL;
187 buff16_size = MultiByteToWideChar(CP_OEMCP, MB_PRECOMPOSED, str, str_size, buff16, buff16_size ) ;
188 if ( buff16_size == 0 ) {
189 free ( buff16 );
190 return NULL;
191 }
192 for ( i = 0; i < buff16_size; ++i ) {
193 wchar_t w = buff16[i];
194 if ( w < 0x0080 ) buff8_size += 1;
195 else if ( w < 0x0800 ) buff8_size += 2;
196 else buff8_size += 3;
197 }
198 buff8 = (char*) malloc ( sizeof(char)*buff8_size + 1 );
199 if ( buff8 == NULL ) {
200 free ( buff16 );
201 return NULL;
202 }
203 for ( i = 0, buff8_p = buff8; i < buff16_size; ++i ) {
204 wchar_t w = buff16[i];
205 if ( w < 0x0080 ) {
206 *(buff8_p++) = (char)w;
207 } else if ( buff16[i] < 0x0800 ) {
208 *(buff8_p++) = 0xc0 | (w >> 6);
209 *(buff8_p++) = 0x80 | (w & 0x3f);
210 } else {
211 *(buff8_p++) = 0xe0 | (w >> 12);
212 *(buff8_p++) = 0x80 | ((w >>6 ) & 0x3f);
213 *(buff8_p++) = 0x80 | (w & 0x3f);
214 }
215 }
216 *buff8_p = '\0';
217 free ( buff16 );
218 return buff8;
219 }
220 #endif
221
ogg_output_open(const char * fname,const char * comment)222 static int ogg_output_open(const char *fname, const char *comment)
223 {
224 int fd;
225 int nch;
226 #if !defined ( IA_W32GUI ) && !defined ( IA_W32G_SYN )
227 int bitrate;
228 #endif
229
230 #ifdef AU_VORBIS_DLL
231 {
232 int flag = 0;
233 if(!load_ogg_dll())
234 if(!load_vorbis_dll())
235 if(!load_vorbisenc_dll())
236 flag = 1;
237 if(!flag){
238 free_ogg_dll();
239 free_vorbis_dll();
240 free_vorbisenc_dll();
241 return -1;
242 }
243 }
244 #endif
245
246 if(strcmp(fname, "-") == 0) {
247 fd = 1; /* data to stdout */
248 if(comment == NULL)
249 comment = "(stdout)";
250 } else {
251 /* Open the audio file */
252 fd = open(fname, FILE_OUTPUT_MODE);
253 if(fd < 0) {
254 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
255 fname, strerror(errno));
256 return -1;
257 }
258 if(comment == NULL)
259 comment = fname;
260 }
261
262 #if defined ( IA_W32GUI ) || defined ( IA_W32G_SYN )
263 vorbis_ConfigDialogInfoApply();
264 #endif
265
266 nch = (dpm.encoding & PE_MONO) ? 1 : 2;
267
268 /* choose an encoding mode */
269 vorbis_info_init(&vi);
270 #if !defined ( IA_W32GUI ) && !defined ( IA_W32G_SYN )
271 bitrate = choose_bitrate(nch, dpm.rate);
272 ctl->cmsg(CMSG_INFO,VERB_NOISY,"Target encoding bitrate: %dbps", bitrate);
273 vorbis_encode_init(&vi, nch, dpm.rate, -1, bitrate, -1);
274 #else
275 {
276 float bitrate_f = (float)choose_bitrate(nch, dpm.rate);
277 if (bitrate_f <= 10.0 )
278 bitrate_f /= 10.0;
279 if (bitrate_f > 10 )
280 bitrate_f /= 1000.0;
281 ctl->cmsg(CMSG_INFO,VERB_NOISY,"Target encoding VBR quality: %d", bitrate_f);
282 vorbis_encode_init_vbr(&vi, nch, dpm.rate, bitrate_f);
283 }
284 #endif
285
286 {
287 /* add a comment */
288 char *location_string;
289
290 vorbis_comment_init(&vc);
291
292 location_string =
293 (char *)safe_malloc(strlen(comment) + sizeof("LOCATION=") + 2);
294 strcpy(location_string, "LOCATION=");
295 strcat(location_string, comment);
296 #ifndef __W32__
297 vorbis_comment_add(&vc, (char *)location_string);
298 free(location_string);
299 #else
300 {
301 char* location_string_utf8 = w32_mbs_to_utf8 ( location_string );
302 if ( location_string_utf8 == NULL ) {
303 vorbis_comment_add(&vc, (char *)location_string);
304 } else {
305 vorbis_comment_add(&vc, (char *)location_string_utf8);
306 if ( location_string_utf8 != location_string )
307 free ( location_string_utf8 );
308 }
309 free(location_string);
310 }
311 #endif
312 }
313 /* add default tag */
314 if (tag_title != NULL) {
315 #ifndef __W32__
316 vorbis_comment_add_tag(&vc, "title", (char *)tag_title);
317 #else
318 {
319 char* tag_title_utf8 = w32_mbs_to_utf8 ( tag_title );
320 if ( tag_title_utf8 == NULL ) {
321 vorbis_comment_add_tag(&vc, "title", (char *)tag_title);
322 } else {
323 vorbis_comment_add_tag(&vc, "title", (char *)tag_title_utf8);
324 if ( tag_title_utf8 != tag_title )
325 free ( tag_title_utf8 );
326 }
327 }
328 #endif
329 }
330
331 /* set up the analysis state and auxiliary encoding storage */
332 vorbis_analysis_init(&vd, &vi);
333 vorbis_block_init(&vd, &vb);
334
335 /* set up our packet->stream encoder */
336 /* pick a random serial number; that way we can more likely build
337 chained streams just by concatenation */
338 srand(time(NULL));
339 ogg_stream_init(&os, rand());
340
341 /* Vorbis streams begin with three headers; the initial header (with
342 most of the codec setup parameters) which is mandated by the Ogg
343 bitstream spec. The second header holds any comment fields. The
344 third header holds the bitstream codebook. We merely need to
345 make the headers, then pass them to libvorbis one at a time;
346 libvorbis handles the additional Ogg bitstream constraints */
347
348 {
349 ogg_packet header;
350 ogg_packet header_comm;
351 ogg_packet header_code;
352
353 vorbis_analysis_headerout(&vd, &vc, &header, &header_comm, &header_code);
354 ogg_stream_packetin(&os, &header); /* automatically placed in its own
355 page */
356 ogg_stream_packetin(&os, &header_comm);
357 ogg_stream_packetin(&os, &header_code);
358
359 /* no need to write out here. We'll get to that in the main loop */
360 }
361
362 return fd;
363 }
364
365 /* mode
366 0,1: Default mode.
367 2: Remove the directory path of input_filename, then add output_dir.
368 3: Replace directory separator characters ('/','\',':') with '_', then add output_dir.
369 */
370 extern char *create_auto_output_name(const char *input_filename, char *ext_str, char *output_dir, int mode);
371
auto_ogg_output_open(const char * input_filename,const char * title)372 static int auto_ogg_output_open(const char *input_filename, const char *title)
373 {
374 char *output_filename;
375
376 #if !defined ( IA_W32GUI ) && !defined ( IA_W32G_SYN )
377 output_filename = create_auto_output_name(input_filename,"ogg",NULL,0);
378 #else
379 output_filename = create_auto_output_name(input_filename,"ogg",w32g_output_dir,w32g_auto_output_mode);
380 #endif
381 if(output_filename==NULL){
382 return -1;
383 }
384 if (tag_title != NULL) {
385 free(tag_title);
386 tag_title = NULL;
387 }
388 if (title != NULL) {
389 tag_title = (char *)safe_malloc(sizeof(char)*(strlen(title)+1));
390 strcpy(tag_title, title);
391 }
392 if((dpm.fd = ogg_output_open(output_filename, input_filename)) == -1) {
393 free(output_filename);
394 return -1;
395 }
396 if(dpm.name != NULL)
397 free(dpm.name);
398 dpm.name = output_filename;
399 ctl->cmsg(CMSG_INFO, VERB_NORMAL, "Output %s", dpm.name);
400 return 0;
401 }
402
open_output(void)403 static int open_output(void)
404 {
405 int include_enc, exclude_enc;
406
407 /********** Encode setup ************/
408
409 include_enc = exclude_enc = 0;
410
411 /* only 16 bit is supported */
412 include_enc |= PE_16BIT|PE_SIGNED;
413 exclude_enc |= PE_BYTESWAP|PE_24BIT;
414 dpm.encoding = validate_encoding(dpm.encoding, include_enc, exclude_enc);
415
416 #if !defined ( IA_W32GUI ) && !defined ( IA_W32G_SYN )
417 if(dpm.name == NULL) {
418 dpm.flag |= PF_AUTO_SPLIT_FILE;
419 } else {
420 dpm.flag &= ~PF_AUTO_SPLIT_FILE;
421 if((dpm.fd = ogg_output_open(dpm.name, NULL)) == -1)
422 return -1;
423 }
424 #else
425 if(w32g_auto_output_mode>0){
426 dpm.flag |= PF_AUTO_SPLIT_FILE;
427 dpm.name = NULL;
428 } else {
429 dpm.flag &= ~PF_AUTO_SPLIT_FILE;
430 if((dpm.fd = ogg_output_open(dpm.name,NULL)) == -1)
431 return -1;
432 }
433 #endif
434
435 return 0;
436 }
437
output_data(char * readbuffer,int32 bytes)438 static int output_data(char *readbuffer, int32 bytes)
439 {
440 int i, j, ch = ((dpm.encoding & PE_MONO) ? 1 : 2);
441 float **buffer;
442 int16 *samples = (int16 *)readbuffer;
443 int nsamples = bytes / (2 * ch);
444 ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
445 ogg_packet op; /* one raw packet of data for decode */
446
447 if (dpm.fd<0)
448 return 0;
449
450 /* data to encode */
451
452 /* expose the buffer to submit data */
453 buffer = vorbis_analysis_buffer(&vd, nsamples);
454
455 /* uninterleave samples */
456 for(j = 0; j < ch; j++)
457 for(i = 0; i < nsamples; i++)
458 buffer[j][i] = (float)(samples[i*ch+j] * (1.0/32768.0));
459
460 /* tell the library how much we actually submitted */
461 vorbis_analysis_wrote(&vd, nsamples);
462
463 /* vorbis does some data preanalysis, then divvies up blocks for
464 more involved (potentially parallel) processing. Get a single
465 block for encoding now */
466 while(vorbis_analysis_blockout(&vd, &vb) == 1) {
467
468 /* analysis */
469 vorbis_analysis(&vb, NULL);
470 vorbis_bitrate_addblock(&vb);
471
472 while (vorbis_bitrate_flushpacket(&vd, &op)) {
473 /* weld the packet into the bitstream */
474 ogg_stream_packetin(&os, &op);
475
476 /* write out pages (if any) */
477 while(ogg_stream_pageout(&os, &og) != 0) {
478 std_write(dpm.fd, og.header, og.header_len);
479 std_write(dpm.fd, og.body, og.body_len);
480 }
481 }
482 }
483 return 0;
484 }
485
close_output(void)486 static void close_output(void)
487 {
488 int eos = 0;
489 ogg_page og; /* one Ogg bitstream page. Vorbis packets are inside */
490 ogg_packet op; /* one raw packet of data for decode */
491
492 if(dpm.fd < 0)
493 return;
494
495 /* end of file. this can be done implicitly in the mainline,
496 but it's easier to see here in non-clever fashion.
497 Tell the library we're at end of stream so that it can handle
498 the last frame and mark end of stream in the output properly */
499 vorbis_analysis_wrote(&vd, 0);
500
501 /* vorbis does some data preanalysis, then divvies up blocks for
502 more involved (potentially parallel) processing. Get a single
503 block for encoding now */
504 while(vorbis_analysis_blockout(&vd, &vb) == 1) {
505
506 /* analysis */
507 vorbis_analysis(&vb, NULL);
508 vorbis_bitrate_addblock(&vb);
509
510 while(vorbis_bitrate_flushpacket(&vd,&op)) {
511
512 /* weld the packet into the bitstream */
513 ogg_stream_packetin(&os, &op);
514
515 /* write out pages (if any) */
516 while(!eos){
517 int result = ogg_stream_pageout(&os,&og);
518 if(result == 0)
519 break;
520 std_write(dpm.fd, og.header, og.header_len);
521 std_write(dpm.fd, og.body, og.body_len);
522
523 /* this could be set above, but for illustrative purposes, I do
524 it here (to show that vorbis does know where the stream ends) */
525
526 if(ogg_page_eos(&og))
527 eos = 1;
528 }
529 }
530 }
531
532 /* clean up and exit. vorbis_info_clear() must be called last */
533
534 ogg_stream_clear(&os);
535 vorbis_block_clear(&vb);
536 vorbis_dsp_clear(&vd);
537 vorbis_comment_clear(&vc);
538 vorbis_info_clear(&vi);
539 close(dpm.fd);
540
541 #ifdef AU_VORBIS_DLL
542 free_vorbisenc_dll();
543 free_vorbis_dll();
544 free_ogg_dll();
545 #endif
546
547 dpm.fd = -1;
548 }
549
acntl(int request,void * arg)550 static int acntl(int request, void *arg)
551 {
552 switch(request) {
553 case PM_REQ_PLAY_START:
554 if(dpm.flag & PF_AUTO_SPLIT_FILE){
555 if( ( NULL == current_file_info ) || (NULL == current_file_info->filename ) )
556 return auto_ogg_output_open("Output.mid",NULL);
557 return auto_ogg_output_open(current_file_info->filename, current_file_info->seq_name);
558 }
559 return 0;
560 case PM_REQ_PLAY_END:
561 if(dpm.flag & PF_AUTO_SPLIT_FILE)
562 close_output();
563 return 0;
564 case PM_REQ_DISCARD:
565 return 0;
566 }
567 return -1;
568 }
569
570 #endif
571