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