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