rlm@0: /* snes_spc 0.9.0. http://www.slack.net/~ant/ */ rlm@0: rlm@0: #include "wave_writer.h" rlm@0: rlm@0: #include rlm@0: #include rlm@0: #include rlm@0: rlm@0: /* Copyright (C) 2003-2007 Shay Green. This module is free software; you rlm@0: can redistribute it and/or modify it under the terms of the GNU Lesser rlm@0: General Public License as published by the Free Software Foundation; either rlm@0: version 2.1 of the License, or (at your option) any later version. This rlm@0: module is distributed in the hope that it will be useful, but WITHOUT ANY rlm@0: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS rlm@0: FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more rlm@0: details. You should have received a copy of the GNU Lesser General Public rlm@0: License along with this module; if not, write to the Free Software Foundation, rlm@0: Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ rlm@0: rlm@0: enum { buf_size = 32768 * 2 }; rlm@0: enum { header_size = 0x2C }; rlm@0: rlm@0: typedef short sample_t; rlm@0: rlm@0: static unsigned char* buf; rlm@0: static FILE* file; rlm@0: static long sample_count_; rlm@0: static long sample_rate_; rlm@0: static long buf_pos; rlm@0: static int chan_count; rlm@0: rlm@0: static void exit_with_error( const char* str ) rlm@0: { rlm@0: printf( "Error: %s\n", str ); getchar(); rlm@0: exit( EXIT_FAILURE ); rlm@0: } rlm@0: rlm@0: void wave_open( long sample_rate, const char* filename ) rlm@0: { rlm@0: sample_count_ = 0; rlm@0: sample_rate_ = sample_rate; rlm@0: buf_pos = header_size; rlm@0: chan_count = 1; rlm@0: rlm@0: buf = (unsigned char*) malloc( buf_size * sizeof *buf ); rlm@0: if ( !buf ) rlm@0: exit_with_error( "Out of memory" ); rlm@0: rlm@0: file = fopen( filename, "wb" ); rlm@0: if ( !file ) rlm@0: exit_with_error( "Couldn't open WAVE file for writing" ); rlm@0: rlm@0: setvbuf( file, 0, _IOFBF, 32 * 1024L ); rlm@0: } rlm@0: rlm@0: void wave_enable_stereo( void ) rlm@0: { rlm@0: chan_count = 2; rlm@0: } rlm@0: rlm@0: static void flush_() rlm@0: { rlm@0: if ( buf_pos && !fwrite( buf, buf_pos, 1, file ) ) rlm@0: exit_with_error( "Couldn't write WAVE data" ); rlm@0: buf_pos = 0; rlm@0: } rlm@0: rlm@0: void wave_write( short const* in, long remain ) rlm@0: { rlm@0: sample_count_ += remain; rlm@0: while ( remain ) rlm@0: { rlm@0: if ( buf_pos >= buf_size ) rlm@0: flush_(); rlm@0: rlm@0: { rlm@0: unsigned char* p = &buf [buf_pos]; rlm@0: long n = (buf_size - buf_pos) / sizeof (sample_t); rlm@0: if ( n > remain ) rlm@0: n = remain; rlm@0: remain -= n; rlm@0: rlm@0: /* convert to LSB first format */ rlm@0: while ( n-- ) rlm@0: { rlm@0: int s = *in++; rlm@0: *p++ = (unsigned char) s; rlm@0: *p++ = (unsigned char) (s >> 8); rlm@0: } rlm@0: rlm@0: buf_pos = p - buf; rlm@0: assert( buf_pos <= buf_size ); rlm@0: } rlm@0: } rlm@0: } rlm@0: rlm@0: long wave_sample_count( void ) rlm@0: { rlm@0: return sample_count_; rlm@0: } rlm@0: rlm@0: static void set_le32( void* p, unsigned long n ) rlm@0: { rlm@0: ((unsigned char*) p) [0] = (unsigned char) n; rlm@0: ((unsigned char*) p) [1] = (unsigned char) (n >> 8); rlm@0: ((unsigned char*) p) [2] = (unsigned char) (n >> 16); rlm@0: ((unsigned char*) p) [3] = (unsigned char) (n >> 24); rlm@0: } rlm@0: rlm@0: void wave_close( void ) rlm@0: { rlm@0: if ( file ) rlm@0: { rlm@0: /* generate header */ rlm@0: unsigned char h [header_size] = rlm@0: { rlm@0: 'R','I','F','F', rlm@0: 0,0,0,0, /* length of rest of file */ rlm@0: 'W','A','V','E', rlm@0: 'f','m','t',' ', rlm@0: 0x10,0,0,0, /* size of fmt chunk */ rlm@0: 1,0, /* uncompressed format */ rlm@0: 0,0, /* channel count */ rlm@0: 0,0,0,0, /* sample rate */ rlm@0: 0,0,0,0, /* bytes per second */ rlm@0: 0,0, /* bytes per sample frame */ rlm@0: 16,0, /* bits per sample */ rlm@0: 'd','a','t','a', rlm@0: 0,0,0,0, /* size of sample data */ rlm@0: /* ... */ /* sample data */ rlm@0: }; rlm@0: long ds = sample_count_ * sizeof (sample_t); rlm@0: int frame_size = chan_count * sizeof (sample_t); rlm@0: rlm@0: set_le32( h + 0x04, header_size - 8 + ds ); rlm@0: h [0x16] = chan_count; rlm@0: set_le32( h + 0x18, sample_rate_ ); rlm@0: set_le32( h + 0x1C, sample_rate_ * frame_size ); rlm@0: h [0x20] = frame_size; rlm@0: set_le32( h + 0x28, ds ); rlm@0: rlm@0: flush_(); rlm@0: rlm@0: /* write header */ rlm@0: fseek( file, 0, SEEK_SET ); rlm@0: fwrite( h, sizeof h, 1, file ); rlm@0: rlm@0: fclose( file ); rlm@0: file = 0; rlm@0: free( buf ); rlm@0: buf = 0; rlm@0: } rlm@0: }