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