1 
2 /*
3 #    Sfront, a SAOL to C translator
4 #    This file: WAV audio driver for sfront
5 #
6 # Copyright (c) 1999-2006, Regents of the University of California
7 # All rights reserved.
8 #
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that the following conditions are
11 # met:
12 #
13 #  Redistributions of source code must retain the above copyright
14 #  notice, this list of conditions and the following disclaimer.
15 #
16 #  Redistributions in binary form must reproduce the above copyright
17 #  notice, this list of conditions and the following disclaimer in the
18 #  documentation and/or other materials provided with the distribution.
19 #
20 #  Neither the name of the University of California, Berkeley nor the
21 #  names of its contributors may be used to endorse or promote products
22 #  derived from this software without specific prior written permission.
23 #
24 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #
36 #    Maintainer: John Lazzaro, lazzaro@cs.berkeley.edu
37 */
38 
39 
40 /****************************************************************/
41 /****************************************************************/
42 /*             wav file audio driver for sfront                 */
43 /****************************************************************/
44 
45 #include <stdio.h>
46 #include <string.h>
47 
48 #if defined(ASYS_HASOUTPUT)
49 
50 /* default name for output audio file */
51 #define ASYSO_DEFAULTNAME "output.wav"
52 
53 /* global variables, must start with asyso_ */
54 
55 FILE * asyso_fd;     /* output file pointer */
56 char * asyso_name;   /* name of file  */
57 int asyso_srate;    /* sampling rate */
58 int asyso_channels; /* number of channels */
59 int asyso_size;     /* number of float samples _buf */
60 int asyso_nsamp;    /* total number of samples written */
61 int asyso_bps;      /* number of bytes per sample, 1-3 */
62 int asyso_doswap;   /* needs byteswap on write */
63 float * asyso_buf;   /* output floats from sfront */
64 unsigned char * asyso_cbuf;  /* output chars to file */
65 #endif
66 
67 #if defined(ASYS_HASINPUT)
68 
69 /* default name for input audio file */
70 
71 #define ASYSI_DEFAULTNAME "input.wav"
72 
73 /* only used for asysi_soundtypecheck */
74 
75 #define ASYSI_MATCH  0
76 #define ASYSI_EOF 1
77 #define ASYSI_NOMATCH 2
78 
79 /* global variables, must start with asysi_ */
80 
81 FILE * asysi_fd;     /* input file pointer */
82 char * asysi_name;   /* name of file  */
83 int asysi_srate;    /* sampling rate */
84 int asysi_channels; /* number of channels */
85 int asysi_bytes;     /* number of bytes in a buffer */
86 int asysi_nsamp;    /* total number of samples read */
87 int asysi_bps;      /* number of bytes per sample, 1-3 */
88 int asysi_doswap;   /* needs byteswap on read */
89 unsigned char * asysi_cbuf;  /* buffer of WAV file bytes */
90 float * asysi_buf;   /* float buffer for sfront */
91 
92 #endif
93 
94 #if defined(ASYS_HASOUTPUT)
95 
96 /*********************************************************/
97 /*        writes next block of WAV/AIFF bytes            */
98 /*********************************************************/
99 
100 int asyso_putbytes(unsigned char * c, int numbytes)
101 
102 {
103   if (rwrite(c, sizeof(char), numbytes, asyso_fd) != numbytes)
104     return ASYS_ERROR;
105   return ASYS_DONE;
106 }
107 
108 /*********************************************************/
109 /*        writes unsigned int to a WAV files             */
110 /*********************************************************/
111 
112 int asyso_putint(unsigned int val, int numbytes)
113 
114 {
115   unsigned char c[4];
116 
117   if (numbytes > 4)
118     return ASYS_ERROR;
119   switch (numbytes) {
120   case 4:
121     c[0] = (unsigned char) (val&0x000000FF);
122     c[1] = (unsigned char)((val >> 8)&0x000000FF);
123     c[2] = (unsigned char)((val >> 16)&0x000000FF);
124     c[3] = (unsigned char)((val >> 24)&0x000000FF);
125     return asyso_putbytes(c, 4);
126   case 3:
127     c[0] = (unsigned char) (val&0x000000FF);
128     c[1] = (unsigned char)((val >> 8)&0x000000FF);
129     c[2] = (unsigned char)((val >> 16)&0x000000FF);
130     return asyso_putbytes(c, 3);
131   case 2:
132     c[0] = (unsigned char) (val&0x000000FF);
133     c[1] = (unsigned char)((val >> 8)&0x000000FF);
134     return asyso_putbytes(c, 2);
135   case 1:
136     c[0] = (unsigned char) (val&0x000000FF);
137     return asyso_putbytes(c,1);
138   default:
139     return ASYS_ERROR;
140   }
141 
142 }
143 
144 /****************************************************************/
145 /*        core routine for audio output setup                   */
146 /****************************************************************/
147 
148 int asyso_setup(int srate, int ochannels, int osize, char * name)
149 
150 
151 {
152   short swaptest = 0x0100;
153   char * val;
154 
155   asyso_doswap = *((char *)&swaptest);
156   if (name == NULL)
157     val = ASYSO_DEFAULTNAME;
158   else
159     val = name;
160 
161   switch (ASYS_OUTFILE_WORDSIZE) {
162   case ASYS_OUTFILE_WORDSIZE_8BIT:
163     asyso_bps = 1;
164     break;
165   case ASYS_OUTFILE_WORDSIZE_16BIT:
166     asyso_bps = 2;
167     break;
168   case ASYS_OUTFILE_WORDSIZE_24BIT:
169     asyso_bps = 3;
170     break;
171   }
172 
173   asyso_name = strcpy((char *) calloc((strlen(val)+1),sizeof(char)), val);
174   asyso_fd = fopen(asyso_name,"wb");
175   if (asyso_fd == NULL)
176     return ASYS_ERROR;
177 
178   /* preamble for wav file */
179 
180   asyso_putbytes((unsigned char *) "RIFF",4);
181   asyso_putint(0,4);       /* patched later */
182   asyso_putbytes((unsigned char *) "WAVEfmt ",8);
183   asyso_putint(16,4);
184   asyso_putint(1,2);                          /* PCM  */
185   asyso_putint(ochannels,2);                  /* number of channels */
186   asyso_putint(srate,4);                      /* srate */
187   asyso_putint(srate*ochannels*asyso_bps, 4); /* bytes/sec */
188   asyso_putint(ochannels*asyso_bps, 2);       /* block align */
189   asyso_putint(8*asyso_bps, 2);               /* bits per sample */
190   asyso_putbytes((unsigned char *) "data",4);
191   asyso_putint(0,4);                          /* patched later */
192 
193   asyso_srate = srate;
194   asyso_channels = ochannels;
195   asyso_size = osize;
196   asyso_nsamp = 0;
197   asyso_cbuf = (unsigned char *) malloc(osize*asyso_bps);
198 
199   if (asyso_cbuf == NULL)
200     {
201       fprintf(stderr, "Can't allocate WAV byte output buffer (%s).\n",
202 	      strerror(errno));
203       return ASYS_ERROR;
204     }
205 
206   asyso_buf = (float *)calloc(osize, sizeof(float));
207 
208   if (asyso_buf == NULL)
209     {
210       fprintf(stderr, "Can't allocate WAV float output buffer (%s).\n",
211 	      strerror(errno));
212       return ASYS_ERROR;
213     }
214 
215   return ASYS_DONE;
216 }
217 
218 #endif
219 
220 #if defined(ASYS_HASINPUT)
221 
222 /*********************************************************/
223 /*            gets next block of WAV bytes               */
224 /*********************************************************/
225 
226 int asysi_getbytes(unsigned char * c, int numbytes)
227 
228 {
229   if ((int)rread(c, sizeof(char), numbytes, asysi_fd) != numbytes)
230     return ASYS_ERROR;
231   return ASYS_DONE;
232 }
233 
234 /*********************************************************/
235 /*        flushes next block of WAV bytes                */
236 /*********************************************************/
237 
238 int asysi_flushbytes(int numbytes)
239 
240 {
241   unsigned char c;
242 
243   while (numbytes > 0)
244     {
245       if (rread(&c, sizeof(char), 1, asysi_fd) != 1)
246 	return ASYS_ERROR;
247       numbytes--;
248     }
249   return ASYS_DONE;
250 
251 }
252 
253 /*********************************************************/
254 /*     converts byte stream to an unsigned int           */
255 /*********************************************************/
256 
257 int asysi_getint(int numbytes, unsigned int * ret)
258 
259 {
260   unsigned char c[4];
261 
262   if (numbytes > 4)
263     return ASYS_ERROR;
264   if (ASYS_DONE != asysi_getbytes(&c[0],numbytes))
265     return ASYS_ERROR;
266   switch (numbytes) {
267   case 4:
268     *ret  =  (unsigned int)c[0];
269     *ret |=  (unsigned int)c[1] << 8;
270     *ret |=  (unsigned int)c[2] << 16;
271     *ret |=  (unsigned int)c[3] << 24;
272     return ASYS_DONE;
273   case 3:
274     *ret  =  (unsigned int)c[0];
275     *ret |=  (unsigned int)c[1] << 8;
276     *ret |=  (unsigned int)c[2] << 16;
277     return ASYS_DONE;
278   case 2:
279     *ret  =  (unsigned int)c[0];
280     *ret |=  (unsigned int)c[1] << 8;
281     return ASYS_DONE;
282   case 1:
283     *ret = (unsigned int)c[0];
284     return ASYS_DONE;
285   default:
286     return ASYS_ERROR;
287   }
288 
289 }
290 
291 /***********************************************************/
292 /*  checks byte stream for AIFF/WAV cookie --              */
293 /***********************************************************/
294 
295 int asysi_soundtypecheck(char * d)
296 
297 {
298   char c[4];
299 
300   if (rread(c, sizeof(char), 4, asysi_fd) != 4)
301     return ASYSI_EOF;
302   if (strncmp(c,d,4))
303     return ASYSI_NOMATCH;
304   return ASYSI_MATCH;
305 }
306 
307 /****************************************************************/
308 /*        core routine for audio input setup                   */
309 /****************************************************************/
310 
311 int asysi_setup(int srate, int ichannels, int isize, char * name)
312 
313 
314 {
315   short swaptest = 0x0100;
316   unsigned int i, cookie;
317   int len;
318   char * val;
319 
320   asysi_doswap = *((char *)&swaptest);
321 
322   if (name == NULL)
323     val = ASYSI_DEFAULTNAME;
324   else
325     val = name;
326   asysi_name = strcpy((char *) calloc((strlen(val)+1),sizeof(char)), val);
327   asysi_fd = fopen(asysi_name,"rb");
328   if (asysi_fd == NULL)
329     return ASYS_ERROR;
330 
331   if (asysi_soundtypecheck("RIFF")!= ASYSI_MATCH)
332     return ASYS_ERROR;
333   if (asysi_flushbytes(4)!= ASYS_DONE)
334     return ASYS_ERROR;
335   if (asysi_soundtypecheck("WAVE")!= ASYSI_MATCH)
336     return ASYS_ERROR;
337   while ((cookie = asysi_soundtypecheck("fmt "))!=ASYSI_MATCH)
338     {
339       if (cookie == ASYSI_EOF)
340 	return ASYS_ERROR;
341       if (asysi_getint(4, &i) != ASYS_DONE)
342 	return ASYS_ERROR;
343       if (asysi_flushbytes(i + (i % 2))!= ASYS_DONE)
344 	return ASYS_ERROR;
345     }
346   if (asysi_getint(4, &i) != ASYS_DONE)
347     return ASYS_ERROR;
348   len = i;
349   if ((len -= 16) < 0)
350     return ASYS_ERROR;
351   if (asysi_getint(2, &i) != ASYS_DONE)
352     return ASYS_ERROR;
353   if (i != 1)
354     {
355       fprintf(stderr,"Error: Can only handle PCM WAV files\n");
356       return ASYS_ERROR;
357     }
358   if (asysi_getint(2, &i) != ASYS_DONE)
359     return ASYS_ERROR;
360   if (i != ichannels)
361     {
362       fprintf(stderr,"Error: Inchannels doesn't match WAV file\n");
363       return ASYS_ERROR;
364     }
365   if (asysi_getint(4, &i) != ASYS_DONE)
366     return ASYS_ERROR;
367   if (srate != i)
368     fprintf(stderr,"Warning: SAOL srate %i mismatches WAV file srate %i\n",
369 	    srate,i);
370   asysi_flushbytes(6);
371   if (asysi_getint(2, &i) != ASYS_DONE)
372     return ASYS_ERROR;
373   if ((i < 8) || (i > 24))
374     {
375       fprintf(stderr,"Error: Can't handle %i bit data\n",i);
376       return ASYS_ERROR;
377     }
378   asysi_bps = i/8;
379   asysi_flushbytes(len + (len % 2));
380 
381   while ((cookie = asysi_soundtypecheck("data"))!=ASYSI_MATCH)
382     {
383       if (cookie == ASYSI_EOF)
384 	return ASYS_ERROR;
385       if (asysi_getint(4, &i) != ASYS_DONE)
386 	return ASYS_ERROR;
387       if (asysi_flushbytes(i + (i % 2))!= ASYS_DONE)
388 	return ASYS_ERROR;
389     }
390   if (asysi_getint(4, &i) != ASYS_DONE)
391     return ASYS_ERROR;
392 
393   asysi_nsamp = i/asysi_bps;
394   asysi_srate = srate;
395   asysi_channels = ichannels;
396   asysi_bytes = isize*asysi_bps;
397   asysi_cbuf = (unsigned char *) malloc(asysi_bytes);
398 
399   if (asysi_cbuf == NULL)
400     {
401       fprintf(stderr, "Can't allocate WAV input byte buffer (%s).\n",
402 	      strerror(errno));
403       return ASYS_ERROR;
404     }
405 
406   asysi_buf = (float *) malloc(sizeof(float)*isize);
407 
408   if (asysi_buf == NULL)
409     {
410       fprintf(stderr, "Can't allocate WAV input float buffer (%s).\n",
411 	      strerror(errno));
412       return ASYS_ERROR;
413     }
414 
415   return ASYS_DONE;
416 }
417 
418 #endif
419 
420 #if (defined(ASYS_HASOUTPUT) && !defined(ASYS_HASINPUT))
421 
422 /****************************************************************/
423 /*        sets up audio output for a given srate/channels       */
424 /****************************************************************/
425 
426 int asys_osetup(int srate, int ochannels, int osample,
427 		char * oname, int toption)
428 
429 {
430   return asyso_setup(srate, ochannels, ASYS_OCHAN*EV(ACYCLE), oname);
431 }
432 
433 #endif
434 
435 
436 #if (!defined(ASYS_HASOUTPUT) && defined(ASYS_HASINPUT))
437 
438 /****************************************************************/
439 /*        sets up audio input for a given srate/channels       */
440 /****************************************************************/
441 
442 int asys_isetup(int srate, int ichannels, int isample,
443 		char * iname, int toption)
444 
445 {
446   return asysi_setup(srate, ichannels, ASYS_ICHAN*EV(ACYCLE), iname);
447 }
448 
449 #endif
450 
451 
452 #if (defined(ASYS_HASOUTPUT) && defined(ASYS_HASINPUT))
453 
454 /****************************************************************/
455 /*   sets up audio input and output for a given srate/channels  */
456 /****************************************************************/
457 
458 int asys_iosetup(int srate, int ichannels, int ochannels,
459 		 int isample, int osample,
460 		 char * iname, char * oname, int toption)
461 
462 {
463 
464   if (asysi_setup(srate, ichannels, ASYS_ICHAN*EV(ACYCLE), iname) != ASYS_DONE)
465     return ASYS_ERROR;
466   return asyso_setup(srate, ochannels, ASYS_OCHAN*EV(ACYCLE), oname);
467 
468 }
469 
470 #endif
471 
472 #if defined(ASYS_HASOUTPUT)
473 
474 /****************************************************************/
475 /*             shuts down audio output system                   */
476 /****************************************************************/
477 
478 void asyso_shutdown(void)
479 
480 {
481 
482   fseek(asyso_fd, 4, SEEK_SET);
483   asyso_putint(asyso_bps*(unsigned int)asyso_nsamp+36,4);
484   fseek(asyso_fd, 32, SEEK_CUR);
485   asyso_putint(asyso_bps*(unsigned int)asyso_nsamp,4);
486   fclose(asyso_fd);
487 
488 }
489 
490 #endif
491 
492 #if defined(ASYS_HASINPUT)
493 
494 /****************************************************************/
495 /*               shuts down audio input system                  */
496 /****************************************************************/
497 
498 void asysi_shutdown(void)
499 
500 {
501 
502   fclose(asysi_fd);
503 }
504 
505 #endif
506 
507 
508 #if (defined(ASYS_HASOUTPUT)&&(!defined(ASYS_HASINPUT)))
509 
510 /****************************************************************/
511 /*                    shuts down audio output                   */
512 /****************************************************************/
513 
514 void asys_oshutdown(void)
515 
516 {
517   asyso_shutdown();
518 }
519 
520 #endif
521 
522 #if (!defined(ASYS_HASOUTPUT)&&(defined(ASYS_HASINPUT)))
523 
524 /****************************************************************/
525 /*              shuts down audio input device                   */
526 /****************************************************************/
527 
528 void asys_ishutdown(void)
529 
530 {
531   asysi_shutdown();
532 }
533 
534 #endif
535 
536 #if (defined(ASYS_HASOUTPUT)&&(defined(ASYS_HASINPUT)))
537 
538 /****************************************************************/
539 /*              shuts down audio input and output device        */
540 /****************************************************************/
541 
542 void asys_ioshutdown(void)
543 
544 {
545   asysi_shutdown();
546   asyso_shutdown();
547 }
548 
549 #endif
550 
551 
552 #if defined(ASYS_HASOUTPUT)
553 
554 
555 /****************************************************************/
556 /*        creates buffer, and generates starting silence        */
557 /****************************************************************/
558 
559 int asys_preamble(ASYS_OTYPE * asys_obuf[], int * osize)
560 
561 {
562   *asys_obuf = asyso_buf;
563   *osize = asyso_size;
564   return ASYS_DONE;
565 }
566 
567 /****************************************************************/
568 /*               sends one frame of audio to output             */
569 /****************************************************************/
570 
571 int asys_putbuf(ASYS_OTYPE * asys_obuf[], int * osize)
572 
573 {
574   float * buf = *asys_obuf;
575   float fval;
576   int val;
577   int i = 0;
578   int j = 0;
579 
580   switch (asyso_bps) {
581   case 3:
582     while (i < *osize)
583       {
584 	fval = ((float)(pow(2, 23) - 1))*buf[i++];
585 	val = (int)((fval >= 0.0F) ? (fval + 0.5F) : (fval - 0.5F));
586 	asyso_cbuf[j++] = (unsigned char) (val & 0x000000FF);
587 	asyso_cbuf[j++] = (unsigned char)((val >> 8) & 0x000000FF);
588 	asyso_cbuf[j++] = (unsigned char)((val >> 16) & 0x000000FF);
589       }
590     break;
591   case 2:
592     while (i < *osize)
593       {
594 	fval = ((float)(pow(2, 15) - 1))*buf[i++];
595 	val = (int)((fval >= 0.0F) ? (fval + 0.5F) : (fval - 0.5F));
596 	asyso_cbuf[j++] = (unsigned char) (val & 0x000000FF);
597 	asyso_cbuf[j++] = (unsigned char)((val >> 8) & 0x000000FF);
598       }
599     break;
600   case 1:
601     while (i < *osize)
602       {
603 	fval = ((float)(pow(2, 7) - 1))*buf[i++];
604 	asyso_cbuf[j++] = (unsigned char)
605 	  (128 + ((char)((fval >= 0.0F) ? (fval + 0.5F) : (fval - 0.5F))));
606       }
607     break;
608   }
609 
610   if (rwrite(asyso_cbuf, sizeof(char), j, asyso_fd) != j)
611     return ASYS_ERROR;
612 
613   asyso_nsamp += *osize;
614   *osize = asyso_size;
615   return ASYS_DONE;
616 }
617 
618 #endif
619 
620 
621 #if defined(ASYS_HASINPUT)
622 
623 /****************************************************************/
624 /*               get one frame of audio from input              */
625 /****************************************************************/
626 
627 int asys_getbuf(ASYS_ITYPE * asys_ibuf[], int * isize)
628 
629 {
630   int i = 0;
631   int j = 0;
632 
633   if (*asys_ibuf == NULL)
634     *asys_ibuf = asysi_buf;
635 
636   if (asysi_nsamp <= 0)
637     {
638       *isize = 0;
639       return ASYS_DONE;
640     }
641 
642   *isize = (int)rread(asysi_cbuf, sizeof(unsigned char), asysi_bytes, asysi_fd);
643 
644   switch (asysi_bps) {
645   case 1:                              /* 8-bit  */
646     while (i < *isize)
647       {
648 	asysi_buf[i] = ((float)pow(2, -7))*(((short) asysi_cbuf[i]) - 128);
649 	i++;
650       }
651     break;
652   case 2:                              /* 9-16 bit */
653     *isize = (*isize) / 2;
654     while (i < *isize)
655       {
656 	asysi_buf[i] = ((float)pow(2, -15))*((int)(asysi_cbuf[j]) +
657 				    (((int)((char)(asysi_cbuf[j+1]))) << 8));
658 	i++;
659 	j += 2;
660       }
661     break;
662   case 3:                            /* 17-24 bit */
663     *isize = (*isize) / 3;
664     while (i < *isize)
665       {
666 	asysi_buf[i] = ((float)pow(2, -23))*((int)(asysi_cbuf[j]) +
667 				    (((int)(asysi_cbuf[j+1])) << 8) +
668 				    (((int)((char) asysi_cbuf[j+2])) << 16));
669 	i++;
670 	j += 3;
671       }
672     break;
673   }
674 
675   asysi_nsamp -= *isize;
676   return ASYS_DONE;
677 }
678 
679 #endif
680 
681 
682