rlm@0
|
1 /* snes_spc 0.9.0. http://www.slack.net/~ant/ */
|
rlm@0
|
2
|
rlm@0
|
3 #include "wave_writer.h"
|
rlm@0
|
4
|
rlm@0
|
5 #include <assert.h>
|
rlm@0
|
6 #include <stdlib.h>
|
rlm@0
|
7 #include <stdio.h>
|
rlm@0
|
8
|
rlm@0
|
9 /* Copyright (C) 2003-2007 Shay Green. This module is free software; you
|
rlm@0
|
10 can redistribute it and/or modify it under the terms of the GNU Lesser
|
rlm@0
|
11 General Public License as published by the Free Software Foundation; either
|
rlm@0
|
12 version 2.1 of the License, or (at your option) any later version. This
|
rlm@0
|
13 module is distributed in the hope that it will be useful, but WITHOUT ANY
|
rlm@0
|
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
rlm@0
|
15 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
rlm@0
|
16 details. You should have received a copy of the GNU Lesser General Public
|
rlm@0
|
17 License along with this module; if not, write to the Free Software Foundation,
|
rlm@0
|
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
rlm@0
|
19
|
rlm@0
|
20 enum { buf_size = 32768 * 2 };
|
rlm@0
|
21 enum { header_size = 0x2C };
|
rlm@0
|
22
|
rlm@0
|
23 typedef short sample_t;
|
rlm@0
|
24
|
rlm@0
|
25 static unsigned char* buf;
|
rlm@0
|
26 static FILE* file;
|
rlm@0
|
27 static long sample_count_;
|
rlm@0
|
28 static long sample_rate_;
|
rlm@0
|
29 static long buf_pos;
|
rlm@0
|
30 static int chan_count;
|
rlm@0
|
31
|
rlm@0
|
32 static void exit_with_error( const char* str )
|
rlm@0
|
33 {
|
rlm@0
|
34 printf( "Error: %s\n", str ); getchar();
|
rlm@0
|
35 exit( EXIT_FAILURE );
|
rlm@0
|
36 }
|
rlm@0
|
37
|
rlm@0
|
38 void wave_open( long sample_rate, const char* filename )
|
rlm@0
|
39 {
|
rlm@0
|
40 sample_count_ = 0;
|
rlm@0
|
41 sample_rate_ = sample_rate;
|
rlm@0
|
42 buf_pos = header_size;
|
rlm@0
|
43 chan_count = 1;
|
rlm@0
|
44
|
rlm@0
|
45 buf = (unsigned char*) malloc( buf_size * sizeof *buf );
|
rlm@0
|
46 if ( !buf )
|
rlm@0
|
47 exit_with_error( "Out of memory" );
|
rlm@0
|
48
|
rlm@0
|
49 file = fopen( filename, "wb" );
|
rlm@0
|
50 if ( !file )
|
rlm@0
|
51 exit_with_error( "Couldn't open WAVE file for writing" );
|
rlm@0
|
52
|
rlm@0
|
53 setvbuf( file, 0, _IOFBF, 32 * 1024L );
|
rlm@0
|
54 }
|
rlm@0
|
55
|
rlm@0
|
56 void wave_enable_stereo( void )
|
rlm@0
|
57 {
|
rlm@0
|
58 chan_count = 2;
|
rlm@0
|
59 }
|
rlm@0
|
60
|
rlm@0
|
61 static void flush_()
|
rlm@0
|
62 {
|
rlm@0
|
63 if ( buf_pos && !fwrite( buf, buf_pos, 1, file ) )
|
rlm@0
|
64 exit_with_error( "Couldn't write WAVE data" );
|
rlm@0
|
65 buf_pos = 0;
|
rlm@0
|
66 }
|
rlm@0
|
67
|
rlm@0
|
68 void wave_write( short const* in, long remain )
|
rlm@0
|
69 {
|
rlm@0
|
70 sample_count_ += remain;
|
rlm@0
|
71 while ( remain )
|
rlm@0
|
72 {
|
rlm@0
|
73 if ( buf_pos >= buf_size )
|
rlm@0
|
74 flush_();
|
rlm@0
|
75
|
rlm@0
|
76 {
|
rlm@0
|
77 unsigned char* p = &buf [buf_pos];
|
rlm@0
|
78 long n = (buf_size - buf_pos) / sizeof (sample_t);
|
rlm@0
|
79 if ( n > remain )
|
rlm@0
|
80 n = remain;
|
rlm@0
|
81 remain -= n;
|
rlm@0
|
82
|
rlm@0
|
83 /* convert to LSB first format */
|
rlm@0
|
84 while ( n-- )
|
rlm@0
|
85 {
|
rlm@0
|
86 int s = *in++;
|
rlm@0
|
87 *p++ = (unsigned char) s;
|
rlm@0
|
88 *p++ = (unsigned char) (s >> 8);
|
rlm@0
|
89 }
|
rlm@0
|
90
|
rlm@0
|
91 buf_pos = p - buf;
|
rlm@0
|
92 assert( buf_pos <= buf_size );
|
rlm@0
|
93 }
|
rlm@0
|
94 }
|
rlm@0
|
95 }
|
rlm@0
|
96
|
rlm@0
|
97 long wave_sample_count( void )
|
rlm@0
|
98 {
|
rlm@0
|
99 return sample_count_;
|
rlm@0
|
100 }
|
rlm@0
|
101
|
rlm@0
|
102 static void set_le32( void* p, unsigned long n )
|
rlm@0
|
103 {
|
rlm@0
|
104 ((unsigned char*) p) [0] = (unsigned char) n;
|
rlm@0
|
105 ((unsigned char*) p) [1] = (unsigned char) (n >> 8);
|
rlm@0
|
106 ((unsigned char*) p) [2] = (unsigned char) (n >> 16);
|
rlm@0
|
107 ((unsigned char*) p) [3] = (unsigned char) (n >> 24);
|
rlm@0
|
108 }
|
rlm@0
|
109
|
rlm@0
|
110 void wave_close( void )
|
rlm@0
|
111 {
|
rlm@0
|
112 if ( file )
|
rlm@0
|
113 {
|
rlm@0
|
114 /* generate header */
|
rlm@0
|
115 unsigned char h [header_size] =
|
rlm@0
|
116 {
|
rlm@0
|
117 'R','I','F','F',
|
rlm@0
|
118 0,0,0,0, /* length of rest of file */
|
rlm@0
|
119 'W','A','V','E',
|
rlm@0
|
120 'f','m','t',' ',
|
rlm@0
|
121 0x10,0,0,0, /* size of fmt chunk */
|
rlm@0
|
122 1,0, /* uncompressed format */
|
rlm@0
|
123 0,0, /* channel count */
|
rlm@0
|
124 0,0,0,0, /* sample rate */
|
rlm@0
|
125 0,0,0,0, /* bytes per second */
|
rlm@0
|
126 0,0, /* bytes per sample frame */
|
rlm@0
|
127 16,0, /* bits per sample */
|
rlm@0
|
128 'd','a','t','a',
|
rlm@0
|
129 0,0,0,0, /* size of sample data */
|
rlm@0
|
130 /* ... */ /* sample data */
|
rlm@0
|
131 };
|
rlm@0
|
132 long ds = sample_count_ * sizeof (sample_t);
|
rlm@0
|
133 int frame_size = chan_count * sizeof (sample_t);
|
rlm@0
|
134
|
rlm@0
|
135 set_le32( h + 0x04, header_size - 8 + ds );
|
rlm@0
|
136 h [0x16] = chan_count;
|
rlm@0
|
137 set_le32( h + 0x18, sample_rate_ );
|
rlm@0
|
138 set_le32( h + 0x1C, sample_rate_ * frame_size );
|
rlm@0
|
139 h [0x20] = frame_size;
|
rlm@0
|
140 set_le32( h + 0x28, ds );
|
rlm@0
|
141
|
rlm@0
|
142 flush_();
|
rlm@0
|
143
|
rlm@0
|
144 /* write header */
|
rlm@0
|
145 fseek( file, 0, SEEK_SET );
|
rlm@0
|
146 fwrite( h, sizeof h, 1, file );
|
rlm@0
|
147
|
rlm@0
|
148 fclose( file );
|
rlm@0
|
149 file = 0;
|
rlm@0
|
150 free( buf );
|
rlm@0
|
151 buf = 0;
|
rlm@0
|
152 }
|
rlm@0
|
153 }
|