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