/* sound_open.c -- Opens aiff & wave SoundStream's for writing only. */ /* Always writes a fixed aiff or wave header. */ #include #include #include #include #include #include #include #include "sound.h" SoundStream *sound_open_stream_r( FILE *byte_stream, char *format ); SoundStream *sound_open_stream_w( FILE *byte_stream, char *format ); SoundStream *sound_open_stream( FILE *byte_stream, char *mode, char *format ) { SoundStream *pSS; char *header; size_t size, wrote; if( strcmp( mode, "w" ) == 0 ) { return( sound_open_stream_w( byte_stream, format ) ); } else if( strcmp( mode, "r" ) == 0 ) { return( sound_open_stream_r( byte_stream, format ) ); } else { fprintf( stderr, "sound_open_stream: unknown mode \"%s\"\n", mode ); return( NULL ); } } static int confirm( FILE *byte_stream, char *str ) { size_t size, readed; char *buf; int result; size = strlen( str ); buf = (char *) malloc( size + 1 ); if( buf == NULL ) { fprintf( stderr, "confirm \"%s\" in sound_open.c: malloc problem\n", str ); return( FALSE ); } readed = fread( buf, sizeof(char), size, byte_stream ); if( readed != size ) { fprintf( stderr, "confirm \"%s\" in sound_open.c: read error or end of file.\n", str ); free( buf ); return( FALSE ); } buf[ size ] = '\0'; result = strcmp( buf, str ); free( buf ); return( result == 0 ); } static int find( FILE *byte_stream, char *str ) { size_t size, readed; char *buf; int result; size = strlen( str ); buf = (char *) malloc( size + 1 ); if( buf == NULL ) { fprintf( stderr, "find in sound_open.c: malloc problem\n" ); return( FALSE ); } readed = fread( buf, sizeof(char), size, byte_stream ); if( readed != size ) { fprintf( stderr, "find 1 in sound_open.c: read error or end of file.\n" ); free( buf ); return( FALSE ); } buf[ size ] = '\0'; while( strcmp( buf, str ) != 0 ) { memcpy( buf, buf+1, size-1 ); readed = fread( buf+size-1, sizeof(char), 1, byte_stream ); if( readed != 1 ) { fprintf( stderr, "find 2 in sound_open.c: read error or end of file.\n" ); free( buf ); return( FALSE ); } } buf[ size ] = '\0'; free( buf ); return( result == 0 ); } SoundStream *sound_open_stream_r( FILE *byte_stream, char *format ) { SoundStream *pSS; char buf[ 5 ]; size_t size, readed; /* Do all computer people hate the word "read?" */ long file_size, data_size; pSS = (SoundStream *) malloc( sizeof( SoundStream ) ); if( pSS == NULL ) { fprintf( stderr, "sound_fdopen: couldn't malloc SoundStream\n" ); return( NULL ); } if( strcmp( format, "aiff" ) == 0 ) { pSS->little_endian = FALSE; } else if( strcmp( format, "wave" ) == 0 || strcmp( format, "wav" ) == 0 ) { pSS->little_endian = TRUE; fprintf( stderr, "sound_open_stream_r: Don't know how to read WAVE files yet.\n" ); free( pSS ); return( NULL ); } else { fprintf( stderr, "sound_open_stream_r: \"%s\": unknown sound file format.\n", format ); free( pSS ); return( NULL ); } /* Do some readin' stuff. */ pSS->byte_stream = byte_stream; if( confirm( byte_stream, "FORM" ) && sound_read_32bit( pSS, &file_size ) == 4 && confirm( byte_stream, "AIFF" ) && find( byte_stream, "SSND" ) && sound_read_32bit( pSS, &data_size ) == 4 ) { return( pSS ); } else { fprintf( stderr, "sound_open_stream_r: problem in header.\n" ); free( pSS ); return( NULL ); } } SoundStream *sound_open_stream_w( FILE *byte_stream, char *format ) { SoundStream *pSS; char *header; size_t size, wrote; char aiff_header [] = { /* In AIFF, all numbers are MSB first. */ 'F', 'O', 'R', 'M', 0x40, 0x00, 0x00, 0x2e, /* total file size */ /* Since I don't know the size in advance, this is a bluff. */ /* Making size too big seems to work better than making it too small. */ 'A', 'I', 'F', 'F', 'C', 'O', 'M', 'M', 0x00, 0x00, 0x00, 0x12, /* size of the following COMM (format) chunk */ 0x00, 0x02, /* number of channels */ 0x10, 0x00, 0x00, 0x00, /* total number of sample frames (bluff) */ 0x00, 0x10, /* bits per sample */ 0x40, 0x0e, 0xac, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*sample rate*/ /* sgn+exp, mantissa with m.s.bit (44100 = 0xAC44) << 48 */ 'S', 'S', 'N', 'D', 0x40, 0x00, 0x00, 0x00 /* size of the following SSND chunk (bluff) */ }; char wave_header [] = { /* In WAVE, all numbers are LSB first. */ 'R', 'I', 'F', 'F', 0x40, 0x00, 0x00, 0x24, /* total file size minus 8 */ /* Since I don't know the size in advance, this is a bluff. */ /* Making size too big seems to work better than making it too small. */ 'W', 'A', 'V', 'E', 'f', 'm', 't', ' ', 0x10, 0x00, 0x00, 0x00, /* size of the following fmt chunk */ 0x01, 0x00, /* compression code, 1 = PCM */ 0x02, 0x00, /* number of channels */ 0x44, 0xac, 0x00, 0x00, /* samples per second (0xAC44 = 44100) */ 0x10, 0xb1, 0x02, 0x00, /* average bytes per second (176400) */ 0x04, 0x00, /* block alignment */ 0x10, 0x00, /* significant bits per sample */ 'd', 'a', 't', 'a', 0x00, 0x00, 0x00, 0x40 /* size of the following data (bluff) */ }; pSS = (SoundStream *) malloc( sizeof( SoundStream ) ); if( pSS == NULL ) { fprintf( stderr, "sound_fdopen: couldn't malloc SoundStream\n" ); return( NULL ); } if( strcmp( format, "aiff" ) == 0 ) { header = aiff_header; size = sizeof( aiff_header ); pSS->little_endian = FALSE; } else if( strcmp( format, "wave" ) == 0 || strcmp( format, "wav" ) == 0 ) { header = wave_header; size = sizeof( wave_header ); pSS->little_endian = TRUE; } else { fprintf( stderr, "sound_open_stream: \"%s\": unknown sound file format.\n", format ); free( pSS ); return( NULL ); } pSS->byte_stream = byte_stream; wrote = fwrite( header, sizeof(char), size, byte_stream ); if( wrote != size ) { fprintf( stderr, "sound_open_stream: failed to write header (wrote %d)\n", wrote ); free( pSS ); return( NULL ); } return( pSS ); } // sound_close does NOT close the byte_stream. void sound_close( SoundStream *pSS ) { free( pSS ); }