1/* http://www.slack.net/~ant/ */
2
3#include "wave_writer.h"
4
5#include <stdlib.h>
6#include <stdio.h>
7
8/* Copyright (C) 2003-2009 Shay Green. This module is free software; you
9can redistribute it and/or modify it under the terms of the GNU Lesser
10General Public License as published by the Free Software Foundation; either
11version 2.1 of the License, or (at your option) any later version. This
12module is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15details. You should have received a copy of the GNU Lesser General Public
16License along with this module; if not, write to the Free Software Foundation,
17Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
18
19enum { sample_size = 2 };
20
21static FILE* file;
22static int sample_count;
23static int sample_rate;
24static int chan_count;
25
26static void write_header( void );
27
28#if defined(_MSC_VER) || defined(__MINGW32__)
29
30#include <windows.h>
31
32static wchar_t* str2wstr(const char *str) {
33 int len = strlen(str) + 1;
34 wchar_t* wstr = malloc(len * sizeof(wchar_t));
35 MultiByteToWideChar(CP_UTF8, 0, str, len * sizeof(char), wstr, len);
36 return wstr;
37}
38
39static FILE *ww_fopen(const char *filename, const char *mode)
40{
41 wchar_t* wFilename = str2wstr(filename);
42 wchar_t* wMode = str2wstr(mode);
43 FILE *pFile = _wfopen(wFilename, wMode);
44 free(wFilename);
45 free(wMode);
46
47 return pFile;
48}
49
50#else
51#define ww_fopen fopen
52#endif
53
54int wave_open( int new_sample_rate, char const filename [] )
55{
56 wave_close();
57
58 file = ww_fopen( filename, "wb" );
59 if (file )
60 {
61 sample_rate = new_sample_rate;
62 write_header();
63 }
64
65 return file != NULL;
66}
67
68int wave_close( void )
69{
70 if ( file )
71 {
72 if (!fflush(file))
73 {
74 rewind( file );
75 write_header();
76
77 if(!fclose(file))
78 file = NULL;
79 }
80 }
81
82 sample_count = 0;
83 chan_count = 1;
84
85 return file != NULL;
86}
87
88static int write_data( void const* in, unsigned size )
89{
90 return !fwrite( in, size, 1, file );
91}
92
93static void set_le32( unsigned char p [4], unsigned n )
94{
95 p [0] = (unsigned char) (n );
96 p [1] = (unsigned char) (n >> 8);
97 p [2] = (unsigned char) (n >> 16);
98 p [3] = (unsigned char) (n >> 24);
99}
100
101static void write_header( void )
102{
103 int data_size = sample_size * sample_count;
104 int frame_size = sample_size * chan_count;
105 unsigned char h [0x2C] =
106 {
107 'R','I','F','F',
108 0,0,0,0, /* length of rest of file */
109 'W','A','V','E',
110 'f','m','t',' ',
111 16,0,0,0, /* size of fmt chunk */
112 1,0, /* uncompressed format */
113 0,0, /* channel count */
114 0,0,0,0, /* sample rate */
115 0,0,0,0, /* bytes per second */
116 0,0, /* bytes per sample frame */
117 sample_size*8,0,/* bits per sample */
118 'd','a','t','a',
119 0,0,0,0 /* size of sample data */
120 /* ... */ /* sample data */
121 };
122
123 set_le32( h + 0x04, sizeof h - 8 + data_size );
124 h [0x16] = chan_count;
125 set_le32( h + 0x18, sample_rate );
126 set_le32( h + 0x1C, sample_rate * frame_size );
127 h [0x20] = frame_size;
128 set_le32( h + 0x28, data_size );
129
130 write_data( h, sizeof h );
131}
132
133void wave_enable_stereo( void )
134{
135 chan_count = 2;
136}
137
138void wave_write( short const in [], int remain )
139{
140 sample_count += remain;
141
142 while ( remain )
143 {
144 unsigned char buf [4096];
145
146 int n = sizeof buf / sample_size;
147 if ( n > remain )
148 n = remain;
149 remain -= n;
150
151 /* Convert to little-endian */
152 {
153 unsigned char* out = buf;
154 short const* end = in + n;
155 do
156 {
157 unsigned s = *in++;
158 out [0] = (unsigned char) (s );
159 out [1] = (unsigned char) (s >> 8);
160 out += sample_size;
161 }
162 while ( in != end );
163
164 write_data( buf, out - buf );
165 }
166 }
167}
168
169int wave_sample_count( void )
170{
171 return sample_count;
172}
173