1 // Game_Music_Emu 0.6.0. http://www.slack.net/~ant/
2
3 #include "Wave_Writer.h"
4
5 #include <assert.h>
6 #include <stdlib.h>
7
8 /* Copyright (C) 2003-2006 by Shay Green. Permission is hereby granted, free
9 of charge, to any person obtaining a copy of this software and associated
10 documentation files (the "Software"), to deal in the Software without
11 restriction, including without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell copies of the Software, and
13 to permit persons to whom the Software is furnished to do so, subject to the
14 following conditions: The above copyright notice and this permission notice
15 shall be included in all copies or substantial portions of the Software. THE
16 SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
17 INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
18 PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
22
23 const int header_size = 0x2C;
24
exit_with_error(const char * str)25 static void exit_with_error( const char* str )
26 {
27 printf( "Error: %s\n", str ); getchar();
28 exit( EXIT_FAILURE );
29 }
30
Wave_Writer(long sample_rate,const char * filename)31 Wave_Writer::Wave_Writer( long sample_rate, const char* filename )
32 {
33 sample_count_ = 0;
34 rate = sample_rate;
35 buf_pos = header_size;
36 chan_count = 1;
37
38 buf = (unsigned char*) malloc( buf_size * sizeof *buf );
39 if ( !buf )
40 exit_with_error( "Out of memory" );
41
42 file = fopen( filename, "wb" );
43 if ( !file )
44 exit_with_error( "Couldn't open WAVE file for writing" );
45
46 setvbuf( file, 0, _IOFBF, 32 * 1024L );
47 }
48
flush()49 void Wave_Writer::flush()
50 {
51 if ( buf_pos && !fwrite( buf, buf_pos, 1, file ) )
52 exit_with_error( "Couldn't write WAVE data" );
53 buf_pos = 0;
54 }
55
write(const sample_t * in,long remain,int skip)56 void Wave_Writer::write( const sample_t* in, long remain, int skip )
57 {
58 sample_count_ += remain;
59 while ( remain )
60 {
61 if ( buf_pos >= buf_size )
62 flush();
63
64 long n = (buf_size - buf_pos) / sizeof (sample_t);
65 if ( n > remain )
66 n = remain;
67 remain -= n;
68
69 // convert to lsb first format
70 unsigned char* p = &buf [buf_pos];
71 while ( n-- )
72 {
73 int s = *in;
74 in += skip;
75 *p++ = (unsigned char) s;
76 *p++ = (unsigned char) (s >> 8);
77 }
78
79 buf_pos = p - buf;
80 assert( buf_pos <= buf_size );
81 }
82 }
83
84
write(const float * in,long remain,int skip)85 void Wave_Writer::write( const float* in, long remain, int skip )
86 {
87 sample_count_ += remain;
88 while ( remain )
89 {
90 if ( buf_pos >= buf_size )
91 flush();
92
93 long n = (buf_size - buf_pos) / sizeof (sample_t);
94 if ( n > remain )
95 n = remain;
96 remain -= n;
97
98 // convert to lsb first format
99 unsigned char* p = &buf [buf_pos];
100 while ( n-- )
101 {
102 long s = (long) (*in * 0x7FFF);
103 in += skip;
104 if ( (short) s != s )
105 s = 0x7FFF - (s >> 24); // clamp to 16 bits
106 *p++ = (unsigned char) s;
107 *p++ = (unsigned char) (s >> 8);
108 }
109
110 buf_pos = p - buf;
111 assert( buf_pos <= buf_size );
112 }
113 }
114
close()115 void Wave_Writer::close()
116 {
117 if ( file )
118 {
119 flush();
120
121 // generate header
122 long ds = sample_count_ * sizeof (sample_t);
123 long rs = header_size - 8 + ds;
124 int frame_size = chan_count * sizeof (sample_t);
125 long bps = rate * frame_size;
126 unsigned char header [header_size] =
127 {
128 'R','I','F','F',
129 rs,rs>>8, // length of rest of file
130 rs>>16,rs>>24,
131 'W','A','V','E',
132 'f','m','t',' ',
133 0x10,0,0,0, // size of fmt chunk
134 1,0, // uncompressed format
135 chan_count,0, // channel count
136 rate,rate >> 8, // sample rate
137 rate>>16,rate>>24,
138 bps,bps>>8, // bytes per second
139 bps>>16,bps>>24,
140 frame_size,0, // bytes per sample frame
141 16,0, // bits per sample
142 'd','a','t','a',
143 ds,ds>>8,ds>>16,ds>>24// size of sample data
144 // ... // sample data
145 };
146
147 // write header
148 fseek( file, 0, SEEK_SET );
149 fwrite( header, sizeof header, 1, file );
150
151 fclose( file );
152 file = 0;
153 free( buf );
154 }
155 }
156
~Wave_Writer()157 Wave_Writer::~Wave_Writer()
158 {
159 close();
160 }
161
162 // C interface
163
164 static Wave_Writer* ww;
165
wave_open(long sample_rate,const char * filename)166 void wave_open( long sample_rate, const char* filename )
167 {
168 ww = new Wave_Writer( sample_rate, filename );
169 assert( ww );
170 }
171
wave_enable_stereo()172 void wave_enable_stereo() { ww->enable_stereo(); }
173
wave_sample_count()174 long wave_sample_count() { return ww->sample_count(); }
175
wave_write(const short * buf,long count)176 void wave_write( const short* buf, long count ) { ww->write( buf, count ); }
177
wave_close()178 void wave_close()
179 {
180 delete ww;
181 ww = 0;
182 }
183