1 /*
2 * wavfile.c WAV file check
3 *
4 * Copyright: wavfile.c (c) Erik de Castro Lopo erikd@zip.com.au
5 *
6 * Modified : 1997-1998 Masaki Chikama (Wren) <chikama@kasumi.ipl.mech.nagoya-u.ac.jp>
7 * 1998- <masaki-c@is.aist-nara.ac.jp>
8 * 2000- Kazunori Ueno(JAGARL) <jagarl@createor.club.ne.jp>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <sys/types.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include "wavfile.h"
38 #include "endian.hpp"
39 #include <stdexcept>
40
41 #include <SDL/SDL_mixer.h>
42
43 #define BUFFERSIZE 1024
44 #define PCM_WAVE_FORMAT 1
45
46 /*******************************************************
47 **
48 ** WAVE Header
49 */
50
LittleEndian_getDW(const char * b,int index)51 inline int LittleEndian_getDW(const char *b,int index) {
52 int c0, c1, c2, c3;
53 int d0, d1;
54 c0 = *(const unsigned char*)(b + index + 0);
55 c1 = *(const unsigned char*)(b + index + 1);
56 c2 = *(const unsigned char*)(b + index + 2);
57 c3 = *(const unsigned char*)(b + index + 3);
58 d0 = c0 + (c1 << 8);
59 d1 = c2 + (c3 << 8);
60 return d0 + (d1 << 16);
61 }
62
LittleEndian_get3B(const char * b,int index)63 inline int LittleEndian_get3B(const char *b,int index) {
64 int c0, c1, c2;
65 c0 = *(const unsigned char*)(b + index + 0);
66 c1 = *(const unsigned char*)(b + index + 1);
67 c2 = *(const unsigned char*)(b + index + 2);
68 return c0 + (c1 << 8) + (c2 << 16);
69 }
70
LittleEndian_getW(const char * b,int index)71 inline int LittleEndian_getW(const char *b,int index) {
72 int c0, c1;
73 c0 = *(const unsigned char*)(b + index + 0);
74 c1 = *(const unsigned char*)(b + index + 1);
75 return c0 + (c1 << 8);
76 }
77
LittleEndian_putW(int num,char * b,int index)78 inline void LittleEndian_putW(int num, char *b, int index) {
79 int c0, c1;
80 num %= 65536;
81 c0 = num % 256;
82 c1 = num / 256;
83 b[index] = c0; b[index+1] = c1;
84 }
85
86 typedef struct
87 { u_long dwSize ;
88 u_short wFormatTag ;
89 u_short wChannels ;
90 u_long dwSamplesPerSec ;
91 u_long dwAvgBytesPerSec ;
92 u_short wBlockAlign ;
93 u_short wBitsPerSample ;
94 } WAVEFORMAT ;
95
96 typedef struct
97 { char RiffID [4] ;
98 u_long RiffSize ;
99 char WaveID [4] ;
100 char FmtID [4] ;
101 u_long FmtSize ;
102 u_short wFormatTag ;
103 u_short nChannels ;
104 u_long nSamplesPerSec ;
105 u_long nAvgBytesPerSec ;
106 u_short nBlockAlign ;
107 u_short wBitsPerSample ;
108 char DataID [4] ;
109 u_long nDataBytes ;
110 } WAVE_HEADER ;
111
112
113 static void waveFormatCopy( WAVEFORMAT* wav, char *ptr );
114 static char* findchunk (char* s1, const char* s2, size_t n) ;
115
WaveHeaderCheck(char * wave_buf,int * channels,u_long * samplerate,int * samplebits,u_long * samples,u_long * datastart)116 static int WaveHeaderCheck (char *wave_buf,int* channels, u_long* samplerate, int* samplebits, u_long* samples,u_long* datastart)
117 {
118 static WAVEFORMAT waveformat ;
119 char* ptr ;
120 u_long databytes ;
121
122 if (findchunk (wave_buf, "RIFF", BUFFERSIZE) != wave_buf) {
123 fprintf(stderr, "Bad format: Cannot find RIFF file marker");
124 return WR_BADRIFF ;
125 }
126
127 if (! findchunk (wave_buf, "WAVE", BUFFERSIZE)) {
128 fprintf(stderr, "Bad format: Cannot find WAVE file marker");
129 return WR_BADWAVE ;
130 }
131
132 ptr = findchunk (wave_buf, "fmt ", BUFFERSIZE) ;
133
134 if (! ptr) {
135 fprintf(stderr, "Bad format: Cannot find 'fmt' file marker");
136 return WR_BADFORMAT ;
137 }
138
139 ptr += 4 ; /* Move past "fmt ".*/
140 waveFormatCopy( &waveformat, ptr );
141
142 if (waveformat.dwSize != (sizeof (WAVEFORMAT) - sizeof (u_long))) {
143 /* fprintf(stderr, "Bad format: Bad fmt size"); */
144 /* return WR_BADFORMATSIZE ; */
145 }
146
147 if (waveformat.wFormatTag != PCM_WAVE_FORMAT) {
148 fprintf(stderr, "Only supports PCM wave format");
149 return WR_NOTPCMFORMAT ;
150 }
151
152 ptr = findchunk (wave_buf, "data", BUFFERSIZE) ;
153
154 if (! ptr) {
155 fprintf(stderr,"Bad format: unable to find 'data' file marker");
156 return WR_NODATACHUNK ;
157 }
158
159 ptr += 4 ; /* Move past "data".*/
160 databytes = LittleEndian_getDW(ptr, 0);
161
162 /* Everything is now cool, so fill in output data.*/
163
164 *channels = waveformat.wChannels;
165 *samplerate = waveformat.dwSamplesPerSec ;
166 *samplebits = waveformat.wBitsPerSample ;
167 *samples = databytes / waveformat.wBlockAlign ;
168
169 *datastart = (u_long)(ptr) + 4;
170
171 if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wBlockAlign) {
172 fprintf(stderr, "Bad file format");
173 return WR_BADFORMATDATA ;
174 }
175
176 if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wChannels / ((waveformat.wBitsPerSample == 16) ? 2 : 1)) {
177 fprintf(stderr, "Bad file format");
178 return WR_BADFORMATDATA ;
179 }
180
181 return 0 ;
182 } ; /* WaveHeaderCheck*/
183
184
findchunk(char * pstart,const char * fourcc,size_t n)185 static char* findchunk (char* pstart, const char* fourcc, size_t n)
186 { char *pend ;
187 int k, test ;
188
189 pend = pstart + n ;
190
191 while (pstart < pend)
192 {
193 if (*pstart == *fourcc) /* found match for first char*/
194 { test = 1 ;
195 for (k = 1 ; fourcc [k] != 0 ; k++)
196 test = (test ? ( pstart [k] == fourcc [k] ) : 0) ;
197 if (test)
198 return pstart ;
199 } ; /* if*/
200 pstart ++ ;
201 } ; /* while lpstart*/
202
203 return NULL ;
204 } ; /* findchuck*/
205
waveFormatCopy(WAVEFORMAT * wav,char * ptr)206 static void waveFormatCopy( WAVEFORMAT* wav, char *ptr ) {
207 wav->dwSize = LittleEndian_getDW( ptr, 0 );
208 wav->wFormatTag = LittleEndian_getW( ptr, 4 );
209 wav->wChannels = LittleEndian_getW( ptr, 6 );
210 wav->dwSamplesPerSec = LittleEndian_getDW( ptr, 8 );
211 wav->dwAvgBytesPerSec = LittleEndian_getDW( ptr, 12 );
212 wav->wBlockAlign = LittleEndian_getW( ptr, 16 );
213 wav->wBitsPerSample = LittleEndian_getW( ptr, 18 );
214 }
215
WavGetInfo(WAVFILE * wfile,char * data)216 static char* WavGetInfo(WAVFILE* wfile, char *data) {
217 int e; /* Saved errno value */
218 int channels; /* Channels recorded in this wav file */
219 u_long samplerate; /* Sampling rate */
220 int sample_bits; /* data bit size (8/12/16) */
221 u_long samples; /* The number of samples in this file */
222 u_long datastart; /* The offset to the wav data */
223
224 if ( (e = WaveHeaderCheck(data,
225 &channels,&samplerate,
226 &sample_bits,&samples,&datastart) != 0 )) {
227 fprintf(stderr,"WavGetInfo(): Reading WAV header\n");
228 return 0;
229 }
230
231 /*
232 * Copy WAV data over to WAVFILE struct:
233 */
234 wfile->wavinfo.Channels = channels;
235
236 wfile->wavinfo.SamplingRate = (unsigned int) samplerate;
237 wfile->wavinfo.DataBits = (unsigned short) sample_bits;
238
239 return (char *) datastart;
240 }
241
242 /************************************************************:
243 **
244 ** WAVFILE stream reader
245 */
246
WAVFILE(void)247 WAVFILE::WAVFILE(void) {
248 wavinfo.SamplingRate=0;
249 wavinfo.Channels=1;
250 wavinfo.DataBits=0;
251 }
252
Read(char * in_buf,int blksize,int length)253 int WAVFILE_Stream::Read(char* in_buf, int blksize, int length) {
254 /* ファイルの読み込み */
255 if (data_length == 0 && stream_length == 0) return -1;
256 /* wf->data にデータの残りがあればそれも読み込む */
257 if (data_length > blksize*length) {
258 memcpy(in_buf, data, blksize*length);
259 data += blksize * length;
260 data_length -= blksize * length;
261 return length;
262 }
263 memcpy(in_buf, data, data_length);
264 if (stream_length != -1 && stream_length < blksize*length-data_length) {
265 length = (stream_length+data_length+blksize-1)/blksize;
266 }
267 int read_len = 0;
268 if (blksize*length-data_length > 0) {
269 read_len = fread(in_buf+data_length, 1, blksize*length-data_length, stream);
270 if (stream_length != -1 && stream_length > read_len) stream_length -= read_len;
271 if (feof(stream)) stream_length = 0; // end of file
272 } else {
273 stream_length = 0; // all data were read
274 }
275 int blklen = (read_len + data_length) / blksize;
276 data_length = 0;
277 return blklen;
278 }
Seek(int count)279 void WAVFILE_Stream::Seek(int count) {
280 int blksize = 1;
281 /* block size の設定 */
282 blksize *= wavinfo.Channels * (wavinfo.DataBits/8);
283 data_length = 0;
284 stream_length = stream_length_orig - stream_top - count*blksize;
285 fseek(stream, count*blksize+stream_top, 0);
286 }
WAVFILE_Stream(FILE * _stream,int _length)287 WAVFILE_Stream::WAVFILE_Stream(FILE* _stream, int _length) {
288 stream = _stream;
289 stream_length = _length;
290 stream_length_orig = _length;
291 data_orig = new char[1024];
292 data = data_orig;
293 data_length = 1024;
294 if (stream_length != -1 && stream_length < data_length) {
295 data_length = stream_length;
296 }
297 fread(data, data_length, 1, stream);
298 if (stream_length != -1)
299 stream_length -= data_length;
300 data = WavGetInfo(this, data);
301 if (data == 0) {
302 stream_length = 0;
303 data_length = 0;
304 return;
305 }
306 stream_top = data - data_orig;
307 data_length -= data - data_orig;
308 return;
309 }
~WAVFILE_Stream()310 WAVFILE_Stream::~WAVFILE_Stream() {
311 if (data_orig) delete data_orig;
312 if (stream) fclose(stream);
313 return;
314 }
315 /************************************************************:
316 **
317 ** WAVE format converter with SDL_audio
318 */
MakeConverter(WAVFILE * new_reader)319 WAVFILE* WAVFILE::MakeConverter(WAVFILE* new_reader) {
320 bool need = false;
321 if (new_reader->wavinfo.SamplingRate != freq) need = true;
322 if (new_reader->wavinfo.Channels != channels) need = true;
323 if (format == AUDIO_S8) {
324 if (new_reader->wavinfo.DataBits != 8) need = true;
325 } else if (format == AUDIO_S16) {
326 if (new_reader->wavinfo.DataBits != 16) need = true;
327 } else {
328 need = true;
329 }
330 if (!need) return new_reader;
331 /* 変換もとのフォーマットを得る */
332 int from_format;
333 if (new_reader->wavinfo.DataBits == 8) from_format = AUDIO_S8;
334 else from_format = AUDIO_S16;
335 SDL_AudioCVT* cvt = new SDL_AudioCVT;
336 int ret = SDL_BuildAudioCVT(cvt, from_format, new_reader->wavinfo.Channels, freq,
337 format, 2, freq);
338 if (ret == -1) {
339 delete cvt;
340 fprintf(stderr,"Cannot make wave file converter!!!\n");
341 return new_reader;
342 }
343 WAVFILE_Converter* conv = new WAVFILE_Converter(new_reader, cvt);
344 return conv;
345 }
WAVFILE_Converter(WAVFILE * _orig,SDL_AudioCVT * _cvt)346 WAVFILE_Converter::WAVFILE_Converter(WAVFILE* _orig, SDL_AudioCVT* _cvt) {
347 original = _orig;
348 cvt = _cvt;
349 //datasize = 4096*4;
350 datasize = 48000;
351 cvt->buf = new Uint8[datasize*cvt->len_mult];
352 cvt->len = 0;
353 tmpbuf = new char[datasize*cvt->len_mult + 1024];
354 memset(tmpbuf, 0, datasize*cvt->len_mult+1024);
355 };
356
357 static int conv_wave_rate(short* in_buf, int length, int in_rate, int out_rate, char* tmpbuf);
~WAVFILE_Converter()358 WAVFILE_Converter::~WAVFILE_Converter() {
359 if (cvt) {
360 if (cvt->buf) delete cvt->buf;
361 delete cvt;
362 cvt = 0;
363 }
364 if (original) delete original;
365 original = 0;
366 }
Read(char * buf,int blksize,int blklen)367 int WAVFILE_Converter::Read(char* buf, int blksize, int blklen) {
368 if (original == 0 || cvt == 0) return -1;
369 int copied_length = 0;
370 if (cvt->len < blksize*blklen) {
371 memcpy(buf, cvt->buf, cvt->len);
372 copied_length += cvt->len;
373 do {
374 int cnt = original->Read((char*)cvt->buf, 1, datasize);
375 if (cnt <= 0) {
376 cvt->len = 0;
377 break;
378 }
379 cvt->len = cnt;
380 SDL_ConvertAudio(cvt);
381 if (freq < original->wavinfo.SamplingRate) { // rate conversion は SDL_ConvertAudio ではうまく行かない
382 // 48000Hz -> 44100Hz or 22050Hz などを想定
383 // 長さは短くなるはずなので、特に処理はなし
384 cvt->len = conv_wave_rate( (short*)(cvt->buf), cvt->len_cvt/4, original->wavinfo.SamplingRate, freq, tmpbuf);
385 cvt->len *= 4;
386 } else {
387 cvt->len = cvt->len_cvt;
388 }
389 if (cvt->len+copied_length > blksize*blklen) break;
390 memcpy(buf+copied_length, cvt->buf, cvt->len);
391 copied_length += cvt->len;
392 } while(1);
393 }
394 if (cvt->len == 0 && copied_length == 0) return -1;
395 else if (cvt->len > 0) {
396 int len = blksize * blklen - copied_length;
397 memcpy(buf+copied_length, cvt->buf, len);
398 memmove(cvt->buf, cvt->buf+len, cvt->len-len);
399 copied_length += len;
400 cvt->len -= len;
401 }
402 return copied_length / blksize;
403 }
404 /* format は signed, 16bit, little endian, stereo と決めうち
405 ** 場合によっていは big endian になることもあるかも。
406 */
conv_wave_rate(short * in_buf,int length,int in_rate,int out_rate,char * tmpbuf)407 static int conv_wave_rate(short* in_buf, int length, int in_rate, int out_rate, char* tmpbuf) {
408 int input_rate = in_rate;
409 int output_rate = out_rate;
410 double input_rate_d = input_rate, output_rate_d = output_rate;
411 double dtime; int outlen; short* out, * out_orig; int next_sample1, next_sample2;
412 short* in_buf_orig = in_buf;
413 int i; int time;
414
415 if (input_rate == output_rate) return length;
416 if (length <= 0) return 0;
417 /* 一般の周波数変換:線型補完 */
418 int& first_flag = *(int*)(tmpbuf);
419 int& prev_time = *(int*)(tmpbuf+4);
420 int& prev_sample1 = *(int*)(tmpbuf+8);
421 int& prev_sample2 = *(int*)(tmpbuf+12);
422 out = (short*)(tmpbuf+16);
423 /* 初めてならデータを初期化 */
424 if (first_flag == 0) {
425 first_flag = 1;
426 prev_time = 0;
427 prev_sample1 = short(read_little_endian_short((char*)(in_buf++)));
428 prev_sample2 = short(read_little_endian_short((char*)(in_buf++)));
429 length--;
430 }
431 /* 今回作成するデータ量を得る */
432 dtime = prev_time + length * output_rate_d;
433 outlen = (int)(dtime / input_rate_d);
434 out_orig = out;
435 if (first_flag == 1) {
436 write_little_endian_short((char*)out, prev_sample1);
437 out++;
438 write_little_endian_short((char*)out, prev_sample2);
439 out++;
440 }
441 dtime -= input_rate_d*outlen; /* 次の prev_time */
442
443 time=0;
444 next_sample1 = short(read_little_endian_short((char*)(in_buf++)));
445 next_sample2 = short(read_little_endian_short((char*)(in_buf++)));
446 for (i=0; i<outlen; i++) {
447 /* double で計算してみたけどそう簡単には高速化は無理らしい */
448 /* なお、変換は 1分のデータに1秒程度かかる(Celeron 700MHz) */
449 time += input_rate;
450 while(time-prev_time>output_rate) {
451 prev_sample1 = next_sample1;
452 next_sample1 = short(read_little_endian_short((char*)(in_buf++)));
453 prev_sample2 = next_sample2;
454 next_sample2 = short(read_little_endian_short((char*)(in_buf++)));
455 prev_time += output_rate;
456 }
457 write_little_endian_short((char*)out,
458 ((time-prev_time)*next_sample1 +
459 (input_rate-time+prev_time)*prev_sample1) / input_rate);
460 out++;
461 write_little_endian_short((char*)out,
462 ((time-prev_time)*next_sample2 +
463 (input_rate-time+prev_time)*prev_sample2) / input_rate);
464 out++;
465 }
466 prev_time += output_rate; prev_time -= input_rate * outlen;
467 prev_sample1 = next_sample1; prev_sample2 = next_sample2;
468 if (first_flag == 1) {
469 outlen++; first_flag = 2;
470 }
471 memcpy(in_buf_orig, out_orig, outlen*2*sizeof(short));
472 return outlen;
473 }
474
475 int WAVFILE::freq = 48000;
476 int WAVFILE::channels = 2;
477 int WAVFILE::format = MIX_DEFAULT_FORMAT;
478
479