0
|
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 #include <stdarg.h>
|
|
27 #include <stdio.h>
|
|
28 #include <stdlib.h>
|
|
29 #include <errno.h>
|
|
30 #include <sys/types.h>
|
|
31 #include <unistd.h>
|
|
32 #include <string.h>
|
|
33 #include "wavfile.h"
|
|
34 #include "system/file.h"
|
|
35 #include "music.h"
|
|
36
|
|
37 #define BUFFERSIZE 1024
|
|
38 #define PCM_WAVE_FORMAT 1
|
|
39
|
|
40 /*******************************************************
|
|
41 **
|
|
42 ** WAVE Header
|
|
43 */
|
|
44
|
|
45 inline int LittleEndian_getDW(const char *b,int index) {
|
|
46 int c0, c1, c2, c3;
|
|
47 int d0, d1;
|
|
48 c0 = *(const unsigned char*)(b + index + 0);
|
|
49 c1 = *(const unsigned char*)(b + index + 1);
|
|
50 c2 = *(const unsigned char*)(b + index + 2);
|
|
51 c3 = *(const unsigned char*)(b + index + 3);
|
|
52 d0 = c0 + (c1 << 8);
|
|
53 d1 = c2 + (c3 << 8);
|
|
54 return d0 + (d1 << 16);
|
|
55 }
|
|
56
|
|
57 inline int LittleEndian_get3B(const char *b,int index) {
|
|
58 int c0, c1, c2;
|
|
59 c0 = *(const unsigned char*)(b + index + 0);
|
|
60 c1 = *(const unsigned char*)(b + index + 1);
|
|
61 c2 = *(const unsigned char*)(b + index + 2);
|
|
62 return c0 + (c1 << 8) + (c2 << 16);
|
|
63 }
|
|
64
|
|
65 inline int LittleEndian_getW(const char *b,int index) {
|
|
66 int c0, c1;
|
|
67 c0 = *(const unsigned char*)(b + index + 0);
|
|
68 c1 = *(const unsigned char*)(b + index + 1);
|
|
69 return c0 + (c1 << 8);
|
|
70 }
|
|
71
|
|
72 inline void LittleEndian_putW(int num, char *b, int index) {
|
|
73 int c0, c1;
|
|
74 num %= 65536;
|
|
75 c0 = num % 256;
|
|
76 c1 = num / 256;
|
|
77 b[index] = c0; b[index+1] = c1;
|
|
78 }
|
|
79
|
|
80 typedef struct
|
|
81 { u_long dwSize ;
|
|
82 u_short wFormatTag ;
|
|
83 u_short wChannels ;
|
|
84 u_long dwSamplesPerSec ;
|
|
85 u_long dwAvgBytesPerSec ;
|
|
86 u_short wBlockAlign ;
|
|
87 u_short wBitsPerSample ;
|
|
88 } WAVEFORMAT ;
|
|
89
|
|
90 typedef struct
|
|
91 { char RiffID [4] ;
|
|
92 u_long RiffSize ;
|
|
93 char WaveID [4] ;
|
|
94 char FmtID [4] ;
|
|
95 u_long FmtSize ;
|
|
96 u_short wFormatTag ;
|
|
97 u_short nChannels ;
|
|
98 u_long nSamplesPerSec ;
|
|
99 u_long nAvgBytesPerSec ;
|
|
100 u_short nBlockAlign ;
|
|
101 u_short wBitsPerSample ;
|
|
102 char DataID [4] ;
|
|
103 u_long nDataBytes ;
|
|
104 } WAVE_HEADER ;
|
|
105
|
|
106
|
|
107 static void waveFormatCopy( WAVEFORMAT* wav, char *ptr );
|
|
108 static char* findchunk (char* s1, char* s2, size_t n) ;
|
|
109
|
|
110 static int WaveHeaderCheck (char *wave_buf,int* channels, u_long* samplerate, int* samplebits, u_long* samples,u_long* datastart)
|
|
111 {
|
|
112 static WAVEFORMAT waveformat ;
|
|
113 char* ptr ;
|
|
114 u_long databytes ;
|
|
115
|
|
116 if (findchunk (wave_buf, "RIFF", BUFFERSIZE) != wave_buf) {
|
|
117 fprintf(stderr, "Bad format: Cannot find RIFF file marker");
|
|
118 return WR_BADRIFF ;
|
|
119 }
|
|
120
|
|
121 if (! findchunk (wave_buf, "WAVE", BUFFERSIZE)) {
|
|
122 fprintf(stderr, "Bad format: Cannot find WAVE file marker");
|
|
123 return WR_BADWAVE ;
|
|
124 }
|
|
125
|
|
126 ptr = findchunk (wave_buf, "fmt ", BUFFERSIZE) ;
|
|
127
|
|
128 if (! ptr) {
|
|
129 fprintf(stderr, "Bad format: Cannot find 'fmt' file marker");
|
|
130 return WR_BADFORMAT ;
|
|
131 }
|
|
132
|
|
133 ptr += 4 ; /* Move past "fmt ".*/
|
|
134 waveFormatCopy( &waveformat, ptr );
|
|
135
|
|
136 if (waveformat.dwSize != (sizeof (WAVEFORMAT) - sizeof (u_long))) {
|
|
137 /* fprintf(stderr, "Bad format: Bad fmt size"); */
|
|
138 /* return WR_BADFORMATSIZE ; */
|
|
139 }
|
|
140
|
|
141 if (waveformat.wFormatTag != PCM_WAVE_FORMAT) {
|
|
142 fprintf(stderr, "Only supports PCM wave format");
|
|
143 return WR_NOTPCMFORMAT ;
|
|
144 }
|
|
145
|
|
146 ptr = findchunk (wave_buf, "data", BUFFERSIZE) ;
|
|
147
|
|
148 if (! ptr) {
|
|
149 fprintf(stderr,"Bad format: unable to find 'data' file marker");
|
|
150 return WR_NODATACHUNK ;
|
|
151 }
|
|
152
|
|
153 ptr += 4 ; /* Move past "data".*/
|
|
154 databytes = LittleEndian_getDW(ptr, 0);
|
|
155
|
|
156 /* Everything is now cool, so fill in output data.*/
|
|
157
|
|
158 *channels = waveformat.wChannels;
|
|
159 *samplerate = waveformat.dwSamplesPerSec ;
|
|
160 *samplebits = waveformat.wBitsPerSample ;
|
|
161 *samples = databytes / waveformat.wBlockAlign ;
|
|
162
|
|
163 *datastart = (u_long)(ptr) + 4;
|
|
164
|
|
165 if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wBlockAlign) {
|
|
166 fprintf(stderr, "Bad file format");
|
|
167 return WR_BADFORMATDATA ;
|
|
168 }
|
|
169
|
|
170 if (waveformat.dwSamplesPerSec != waveformat.dwAvgBytesPerSec / waveformat.wChannels / ((waveformat.wBitsPerSample == 16) ? 2 : 1)) {
|
|
171 fprintf(stderr, "Bad file format");
|
|
172 return WR_BADFORMATDATA ;
|
|
173 }
|
|
174
|
|
175 return 0 ;
|
|
176 } ; /* WaveHeaderCheck*/
|
|
177
|
|
178
|
|
179 static char* findchunk (char* pstart, char* fourcc, size_t n)
|
|
180 { char *pend ;
|
|
181 int k, test ;
|
|
182
|
|
183 pend = pstart + n ;
|
|
184
|
|
185 while (pstart < pend)
|
|
186 {
|
|
187 if (*pstart == *fourcc) /* found match for first char*/
|
|
188 { test = 1 ;
|
|
189 for (k = 1 ; fourcc [k] != 0 ; k++)
|
|
190 test = (test ? ( pstart [k] == fourcc [k] ) : 0) ;
|
|
191 if (test)
|
|
192 return pstart ;
|
|
193 } ; /* if*/
|
|
194 pstart ++ ;
|
|
195 } ; /* while lpstart*/
|
|
196
|
|
197 return NULL ;
|
|
198 } ; /* findchuck*/
|
|
199
|
|
200 static void waveFormatCopy( WAVEFORMAT* wav, char *ptr ) {
|
|
201 wav->dwSize = LittleEndian_getDW( ptr, 0 );
|
|
202 wav->wFormatTag = LittleEndian_getW( ptr, 4 );
|
|
203 wav->wChannels = LittleEndian_getW( ptr, 6 );
|
|
204 wav->dwSamplesPerSec = LittleEndian_getDW( ptr, 8 );
|
|
205 wav->dwAvgBytesPerSec = LittleEndian_getDW( ptr, 12 );
|
|
206 wav->wBlockAlign = LittleEndian_getW( ptr, 16 );
|
|
207 wav->wBitsPerSample = LittleEndian_getW( ptr, 18 );
|
|
208 }
|
|
209
|
|
210 static char* WavGetInfo(WAVFILE* wfile, char *data) {
|
|
211 int e; /* Saved errno value */
|
|
212 int channels; /* Channels recorded in this wav file */
|
|
213 u_long samplerate; /* Sampling rate */
|
|
214 int sample_bits; /* data bit size (8/12/16) */
|
|
215 u_long samples; /* The number of samples in this file */
|
|
216 u_long datastart; /* The offset to the wav data */
|
|
217
|
|
218 if ( (e = WaveHeaderCheck(data,
|
|
219 &channels,&samplerate,
|
|
220 &sample_bits,&samples,&datastart) != 0 )) {
|
|
221 fprintf(stderr,"WavGetInfo(): Reading WAV header\n");
|
|
222 return 0;
|
|
223 }
|
|
224
|
|
225 /*
|
|
226 * Copy WAV data over to WAVFILE struct:
|
|
227 */
|
|
228 wfile->wavinfo.Channels = channels;
|
|
229
|
|
230 wfile->wavinfo.SamplingRate = (unsigned int) samplerate;
|
|
231 wfile->wavinfo.DataBits = (unsigned short) sample_bits;
|
|
232
|
|
233 return (char *) datastart;
|
|
234 }
|
|
235
|
|
236 /************************************************************:
|
|
237 **
|
|
238 ** WAVFILE stream reader
|
|
239 */
|
|
240
|
|
241 #include<SDL_mixer.h>
|
|
242 WAVFILE::WAVFILE(void) {
|
|
243 wavinfo.SamplingRate=0;
|
|
244 wavinfo.Channels=1;
|
|
245 wavinfo.DataBits=0;
|
|
246 }
|
|
247
|
|
248 int WAVFILE_Stream::Read(char* in_buf, int blksize, int length) {
|
|
249 /* ¥Õ¥¡¥¤¥ë¤ÎÆɤ߹þ¤ß */
|
|
250 if (data_length == 0 && stream_length == 0) return -1;
|
|
251 /* wf->data ¤Ë¥Ç¡¼¥¿¤Î»Ä¤ê¤¬¤¢¤ì¤Ð¤½¤ì¤âÆɤ߹þ¤à */
|
|
252 if (data_length > blksize*length) {
|
|
253 memcpy(in_buf, data, blksize*length);
|
|
254 data += blksize * length;
|
|
255 data_length -= blksize * length;
|
|
256 return length;
|
|
257 }
|
|
258 memcpy(in_buf, data, data_length);
|
|
259 if (stream_length != -1 && stream_length < blksize*length-data_length) {
|
|
260 length = (stream_length+data_length+blksize-1)/blksize;
|
|
261 }
|
|
262 int read_len = 0;
|
|
263 if (blksize*length-data_length > 0) {
|
|
264 read_len = fread(in_buf+data_length, 1, blksize*length-data_length, stream);
|
|
265 if (stream_length != -1 && stream_length > read_len) stream_length -= read_len;
|
|
266 if (feof(stream)) stream_length = 0; // end of file
|
|
267 } else {
|
|
268 stream_length = 0; // all data were read
|
|
269 }
|
|
270 int blklen = (read_len + data_length) / blksize;
|
|
271 data_length = 0;
|
|
272 return blklen;
|
|
273 }
|
|
274 void WAVFILE_Stream::Seek(int count) {
|
|
275 int blksize = 1;
|
|
276 /* block size ¤ÎÀßÄê */
|
|
277 blksize *= wavinfo.Channels * (wavinfo.DataBits/8);
|
|
278 data_length = 0;
|
|
279 stream_length = stream_length_orig - stream_top - count*blksize;
|
|
280 fseek(stream, count*blksize+stream_top, 0);
|
|
281 }
|
|
282 WAVFILE_Stream::WAVFILE_Stream(FILE* _stream, int _length) {
|
|
283 stream = _stream;
|
|
284 stream_length = _length;
|
|
285 stream_length_orig = _length;
|
|
286 data_orig = new char[1024];
|
|
287 data = data_orig;
|
|
288 data_length = 1024;
|
|
289 if (stream_length != -1 && stream_length < data_length) {
|
|
290 data_length = stream_length;
|
|
291 }
|
|
292 fread(data, data_length, 1, stream);
|
|
293 if (stream_length != -1)
|
|
294 stream_length -= data_length;
|
|
295 data = WavGetInfo(this, data);
|
|
296 if (data == 0) {
|
|
297 stream_length = 0;
|
|
298 data_length = 0;
|
|
299 return;
|
|
300 }
|
|
301 stream_top = data - data_orig;
|
|
302 data_length -= data - data_orig;
|
|
303 return;
|
|
304 }
|
|
305 WAVFILE_Stream::~WAVFILE_Stream() {
|
|
306 if (data_orig) delete data_orig;
|
|
307 if (stream) fclose(stream);
|
|
308 return;
|
|
309 }
|
|
310 /************************************************************:
|
|
311 **
|
|
312 ** WAVE format converter with SDL_audio
|
|
313 */
|
|
314 WAVFILE* WAVFILE::MakeConverter(WAVFILE* new_reader) {
|
|
315 bool need = false;
|
|
316 if (new_reader->wavinfo.SamplingRate != freq) need = true;
|
|
317 if (new_reader->wavinfo.Channels != channels) need = true;
|
|
318 if (format == AUDIO_S8) {
|
|
319 if (new_reader->wavinfo.DataBits != 8) need = true;
|
|
320 } else if (format == AUDIO_S16) {
|
|
321 if (new_reader->wavinfo.DataBits != 16) need = true;
|
|
322 } else {
|
|
323 need = true;
|
|
324 }
|
|
325 if (!need) return new_reader;
|
|
326 /* ÊÑ´¹¤â¤È¤Î¥Õ¥©¡¼¥Þ¥Ã¥È¤òÆÀ¤ë */
|
|
327 int from_format;
|
|
328 if (new_reader->wavinfo.DataBits == 8) from_format = AUDIO_S8;
|
|
329 else from_format = AUDIO_S16;
|
|
330 SDL_AudioCVT* cvt = new SDL_AudioCVT;
|
|
331 int ret = SDL_BuildAudioCVT(cvt, from_format, new_reader->wavinfo.Channels, freq,
|
|
332 format, 2, freq);
|
|
333 if (ret == -1) {
|
|
334 delete cvt;
|
|
335 fprintf(stderr,"Cannot make wave file converter!!!\n");
|
|
336 return new_reader;
|
|
337 }
|
|
338 WAVFILE_Converter* conv = new WAVFILE_Converter(new_reader, cvt);
|
|
339 return conv;
|
|
340 }
|
|
341 WAVFILE_Converter::WAVFILE_Converter(WAVFILE* _orig, SDL_AudioCVT* _cvt) {
|
|
342 original = _orig;
|
|
343 cvt = _cvt;
|
|
344 //datasize = 4096*4;
|
|
345 datasize = 48000;
|
|
346 cvt->buf = new Uint8[datasize*cvt->len_mult];
|
|
347 cvt->len = 0;
|
|
348 tmpbuf = new char[datasize*cvt->len_mult + 1024];
|
|
349 memset(tmpbuf, 0, datasize*cvt->len_mult+1024);
|
|
350 };
|
|
351
|
|
352 static int conv_wave_rate(short* in_buf, int length, int in_rate, int out_rate, char* tmpbuf);
|
|
353 WAVFILE_Converter::~WAVFILE_Converter() {
|
|
354 if (cvt) {
|
7
|
355 if (cvt->buf) delete[] cvt->buf;
|
0
|
356 delete cvt;
|
|
357 cvt = 0;
|
|
358 }
|
8
|
359 delete[] tmpbuf;
|
0
|
360 if (original) delete original;
|
|
361 original = 0;
|
|
362 }
|
|
363 int WAVFILE_Converter::Read(char* buf, int blksize, int blklen) {
|
|
364 if (original == 0 || cvt == 0) return -1;
|
|
365 int copied_length = 0;
|
|
366 if (cvt->len < blksize*blklen) {
|
|
367 memcpy(buf, cvt->buf, cvt->len);
|
|
368 copied_length += cvt->len;
|
|
369 do {
|
|
370 int cnt = original->Read((char*)cvt->buf, 1, datasize);
|
|
371 if (cnt <= 0) {
|
|
372 cvt->len = 0;
|
|
373 break;
|
|
374 }
|
|
375 cvt->len = cnt;
|
|
376 SDL_ConvertAudio(cvt);
|
|
377 if (freq < original->wavinfo.SamplingRate) { // rate conversion ¤Ï SDL_ConvertAudio ¤Ç¤Ï¤¦¤Þ¤¯¹Ô¤«¤Ê¤¤
|
|
378 // 48000Hz -> 44100Hz or 22050Hz ¤Ê¤É¤òÁÛÄê
|
|
379 // Ťµ¤Ïû¤¯¤Ê¤ë¤Ï¤º¤Ê¤Î¤Ç¡¢Æä˽èÍý¤Ï¤Ê¤·
|
|
380 cvt->len = conv_wave_rate( (short*)(cvt->buf), cvt->len_cvt/4, original->wavinfo.SamplingRate, freq, tmpbuf);
|
|
381 cvt->len *= 4;
|
|
382 } else {
|
|
383 cvt->len = cvt->len_cvt;
|
|
384 }
|
|
385 if (cvt->len+copied_length > blksize*blklen) break;
|
|
386 memcpy(buf+copied_length, cvt->buf, cvt->len);
|
|
387 copied_length += cvt->len;
|
|
388 } while(1);
|
|
389 }
|
|
390 if (cvt->len == 0 && copied_length == 0) return -1;
|
|
391 else if (cvt->len > 0) {
|
|
392 int len = blksize * blklen - copied_length;
|
|
393 memcpy(buf+copied_length, cvt->buf, len);
|
|
394 memmove(cvt->buf, cvt->buf+len, cvt->len-len);
|
|
395 copied_length += len;
|
|
396 cvt->len -= len;
|
|
397 }
|
|
398 return copied_length / blksize;
|
|
399 }
|
|
400 /* format ¤Ï signed, 16bit, little endian, stereo ¤È·è¤á¤¦¤Á
|
|
401 ** ¾ì¹ç¤Ë¤è¤Ã¤Æ¤¤¤Ï big endian ¤Ë¤Ê¤ë¤³¤È¤â¤¢¤ë¤«¤â¡£
|
|
402 */
|
|
403 static int conv_wave_rate(short* in_buf, int length, int in_rate, int out_rate, char* tmpbuf) {
|
|
404 int input_rate = in_rate;
|
|
405 int output_rate = out_rate;
|
|
406 double input_rate_d = input_rate, output_rate_d = output_rate;
|
|
407 double dtime; int outlen; short* out, * out_orig; int next_sample1, next_sample2;
|
|
408 short* in_buf_orig = in_buf;
|
|
409 int i; int time;
|
|
410
|
|
411 if (input_rate == output_rate) return length;
|
|
412 if (length <= 0) return 0;
|
|
413 /* °ìÈ̤μþÇÈ¿ôÊÑ´¹¡§Àþ·¿Êä´° */
|
|
414 int& first_flag = *(int*)(tmpbuf);
|
|
415 int& prev_time = *(int*)(tmpbuf+4);
|
|
416 int& prev_sample1 = *(int*)(tmpbuf+8);
|
|
417 int& prev_sample2 = *(int*)(tmpbuf+12);
|
|
418 out = (short*)(tmpbuf+16);
|
|
419 /* ½é¤á¤Æ¤Ê¤é¥Ç¡¼¥¿¤ò½é´ü²½ */
|
|
420 if (first_flag == 0) {
|
|
421 first_flag = 1;
|
|
422 prev_time = 0;
|
|
423 prev_sample1 = short(read_little_endian_short((char*)(in_buf++)));
|
|
424 prev_sample2 = short(read_little_endian_short((char*)(in_buf++)));
|
|
425 length--;
|
|
426 }
|
|
427 /* º£²óºîÀ®¤¹¤ë¥Ç¡¼¥¿Î̤òÆÀ¤ë */
|
|
428 dtime = prev_time + length * output_rate_d;
|
|
429 outlen = (int)(dtime / input_rate_d);
|
|
430 out_orig = out;
|
|
431 if (first_flag == 1) {
|
|
432 write_little_endian_short((char*)out, prev_sample1);
|
|
433 out++;
|
|
434 write_little_endian_short((char*)out, prev_sample2);
|
|
435 out++;
|
|
436 }
|
|
437 dtime -= input_rate_d*outlen; /* ¼¡¤Î prev_time */
|
|
438
|
|
439 time=0;
|
|
440 next_sample1 = short(read_little_endian_short((char*)(in_buf++)));
|
|
441 next_sample2 = short(read_little_endian_short((char*)(in_buf++)));
|
|
442 for (i=0; i<outlen; i++) {
|
|
443 /* double ¤Ç·×»»¤·¤Æ¤ß¤¿¤±¤É¤½¤¦´Êñ¤Ë¤Ï¹â®²½¤Ï̵Íý¤é¤·¤¤ */
|
|
444 /* ¤Ê¤ª¡¢ÊÑ´¹¤Ï 1ʬ¤Î¥Ç¡¼¥¿¤Ë1ÉÃÄøÅÙ¤«¤«¤ë(Celeron 700MHz) */
|
|
445 time += input_rate;
|
|
446 while(time-prev_time>output_rate) {
|
|
447 prev_sample1 = next_sample1;
|
|
448 next_sample1 = short(read_little_endian_short((char*)(in_buf++)));
|
|
449 prev_sample2 = next_sample2;
|
|
450 next_sample2 = short(read_little_endian_short((char*)(in_buf++)));
|
|
451 prev_time += output_rate;
|
|
452 }
|
|
453 write_little_endian_short((char*)out,
|
|
454 ((time-prev_time)*next_sample1 +
|
|
455 (input_rate-time+prev_time)*prev_sample1) / input_rate);
|
|
456 out++;
|
|
457 write_little_endian_short((char*)out,
|
|
458 ((time-prev_time)*next_sample2 +
|
|
459 (input_rate-time+prev_time)*prev_sample2) / input_rate);
|
|
460 *out++;
|
|
461 }
|
|
462 prev_time += output_rate; prev_time -= input_rate * outlen;
|
|
463 prev_sample1 = next_sample1; prev_sample2 = next_sample2;
|
|
464 if (first_flag == 1) {
|
|
465 outlen++; first_flag = 2;
|
|
466 }
|
|
467 memcpy(in_buf_orig, out_orig, outlen*2*sizeof(short));
|
|
468 return outlen;
|
|
469 }
|
|
470
|
|
471
|
|
472 /************************************************************:
|
|
473 **
|
|
474 ** MP3FILE stream reader
|
|
475 */
|
|
476
|
|
477 int WAVFILE::freq = 48000;
|
|
478 int WAVFILE::channels = 2;
|
|
479 int WAVFILE::format = MIX_DEFAULT_FORMAT;
|
|
480
|
|
481 #if HAVE_LIBMAD
|
|
482
|
|
483 #include<mad.h>
|
|
484 #define MPEG_BUFSZ 40000 /* 2.5 s at 128 kbps; 1 s at 320 kbps */
|
|
485 struct MP3FILE_impl {
|
|
486 enum { PREPARE, RUN, WRITE, DONE} status;
|
|
487 struct mad_decoder decoder;
|
|
488 char* data;
|
|
489 int data_len;
|
|
490 char* write_data;
|
|
491 unsigned int write_data_len;
|
|
492 unsigned int write_pointer;
|
|
493 unsigned int src_pointer;
|
|
494 FILE* stream;
|
|
495 MP3FILE_impl(FILE*);
|
|
496 ~MP3FILE_impl();
|
|
497 static enum mad_flow callback_read(void *data, struct mad_stream *stream);
|
|
498 static enum mad_flow callback_error(void *data, struct mad_stream *stream, struct mad_frame *frame);
|
|
499 static enum mad_flow callback_write(void *data, struct mad_header const *header, struct mad_pcm *pcm);
|
|
500 enum mad_flow callback_write_impl(struct mad_pcm *pcm);
|
|
501 void run(void);
|
|
502 };
|
|
503
|
|
504 MP3FILE_impl::MP3FILE_impl(FILE* _stream) {
|
|
505 stream = _stream;
|
|
506 data = new char[MPEG_BUFSZ];
|
|
507 data_len = 0;
|
|
508 src_pointer = 0;
|
|
509 write_data = 0;
|
|
510 write_data_len = 0;
|
|
511 write_pointer = 0;
|
|
512
|
|
513 /* initialize decoder */
|
|
514 mad_decoder_init(&decoder, (void*)this, callback_read, 0 /* header */, 0 /* filter */, callback_write,
|
|
515 callback_error, 0 /* message */);
|
|
516 /* prepare stream */
|
|
517 status = PREPARE;
|
|
518 *(void**)(&decoder.sync) = malloc(sizeof(*decoder.sync));
|
|
519
|
|
520 mad_stream_init(&decoder.sync->stream);
|
|
521 mad_frame_init(&decoder.sync->frame);
|
|
522 mad_synth_init(&decoder.sync->synth);
|
|
523
|
|
524 mad_stream_options(&decoder.sync->stream, decoder.options);
|
|
525
|
|
526 while(status != WRITE && status != DONE) run();
|
|
527 }
|
|
528 MP3FILE_impl::~MP3FILE_impl() {
|
|
529 free(decoder.sync);
|
|
530 mad_decoder_finish(&decoder);
|
|
531 delete[] data;
|
|
532 return;
|
|
533 }
|
|
534
|
|
535 void MP3FILE_impl::run(void) {
|
|
536 if (status == DONE) return;
|
|
537 struct mad_stream *stream = &decoder.sync->stream;
|
|
538 struct mad_frame *frame = &decoder.sync->frame;
|
|
539 struct mad_synth *synth = &decoder.sync->synth;
|
|
540 if (status == PREPARE) {
|
|
541 switch (decoder.input_func(decoder.cb_data, stream)) {
|
|
542 case MAD_FLOW_STOP:
|
|
543 case MAD_FLOW_BREAK:
|
|
544 goto done;
|
|
545 case MAD_FLOW_CONTINUE:
|
|
546 status = RUN;
|
|
547 case MAD_FLOW_IGNORE:
|
|
548 break;
|
|
549 }
|
|
550 return;
|
|
551 }
|
|
552 if (status == RUN) {
|
|
553 if (mad_frame_decode(frame, stream) == -1) {
|
|
554 if (!MAD_RECOVERABLE(stream->error)) {
|
|
555 status = PREPARE;
|
|
556 return;
|
|
557 }
|
|
558 switch (decoder.error_func((void*)this, stream, frame)) {
|
|
559 case MAD_FLOW_STOP:
|
|
560 case MAD_FLOW_BREAK:
|
|
561 goto done;
|
|
562 case MAD_FLOW_IGNORE:
|
|
563 status = PREPARE;
|
|
564 return;
|
|
565 case MAD_FLOW_CONTINUE:
|
|
566 default:
|
|
567 return;
|
|
568 }
|
|
569 }
|
|
570
|
|
571 mad_synth_frame(synth, frame);
|
|
572 src_pointer = 0;
|
|
573 status = WRITE;
|
|
574 return;
|
|
575 }
|
|
576 if (status == WRITE) {
|
|
577 switch (decoder.output_func(decoder.cb_data, &frame->header, &synth->pcm)) {
|
|
578 case MAD_FLOW_STOP:
|
|
579 case MAD_FLOW_BREAK:
|
|
580 goto done;
|
|
581 case MAD_FLOW_IGNORE:
|
|
582 return;
|
|
583 case MAD_FLOW_CONTINUE:
|
|
584 status = RUN;
|
|
585 break;
|
|
586 }
|
|
587 if (stream->error == MAD_ERROR_BUFLEN) {
|
|
588 stream->error = MAD_ERROR_NONE;
|
|
589 status = PREPARE;
|
|
590 }
|
|
591 return;
|
|
592 }
|
|
593 done:
|
|
594 status = DONE;
|
|
595 mad_synth_finish(&decoder.sync->synth);
|
|
596 mad_frame_finish(&decoder.sync->frame);
|
|
597 mad_stream_finish(&decoder.sync->stream);
|
|
598 return;
|
|
599 }
|
|
600
|
|
601 enum mad_flow MP3FILE_impl::callback_read(void *data, struct mad_stream *stream)
|
|
602 {
|
|
603 MP3FILE_impl* impl = (MP3FILE_impl*)data;
|
|
604 if (stream->next_frame) {
|
|
605 impl->data_len -= (char*)stream->next_frame - impl->data;
|
|
606 memmove(impl->data, (char*)stream->next_frame, impl->data_len);
|
|
607 } else {
|
|
608 impl->data_len = 0;
|
|
609 }
|
|
610 int count;
|
|
611 if (feof(impl->stream)) {
|
|
612 if (stream->next_frame && (char*)stream->next_frame - impl->data > 0) {
|
|
613 // There is under processing data
|
|
614 count = 0;
|
|
615 } else {
|
|
616 // all data were processed
|
|
617 return MAD_FLOW_STOP;
|
|
618 }
|
|
619 } else {
|
|
620 count = fread(impl->data + impl->data_len, 1, MPEG_BUFSZ-impl->data_len, impl->stream);
|
|
621 if (count <= 0) {
|
|
622 return MAD_FLOW_BREAK;
|
|
623 }
|
|
624 }
|
|
625 impl->data_len += count;
|
|
626 if (impl->data_len < MPEG_BUFSZ) {
|
|
627 memset(impl->data + impl->data_len, 0, MPEG_BUFSZ-impl->data_len);
|
|
628 }
|
|
629 mad_stream_buffer(stream, (unsigned char*)impl->data, impl->data_len);
|
|
630 return MAD_FLOW_CONTINUE;
|
|
631 }
|
|
632
|
|
633 enum mad_flow MP3FILE_impl::callback_error(void *data, struct mad_stream *stream, struct mad_frame *frame)
|
|
634 {
|
|
635 MP3FILE_impl* impl = (MP3FILE_impl*)data;
|
|
636 fprintf(stdout, "decoding error 0x%04x (%s) at byte offset %u\n",
|
|
637 stream->error, mad_stream_errorstr(stream),
|
|
638 ftell(impl->stream) - ((impl->data+impl->data_len)-(char*)stream->this_frame));
|
|
639 /* return MAD_FLOW_BREAK here to stop decoding (and propagate an error) */
|
|
640 return MAD_FLOW_CONTINUE;
|
|
641 }
|
|
642 signed int scale(mad_fixed_t sample)
|
|
643 {
|
|
644 /* round */
|
|
645 sample += (1L << (MAD_F_FRACBITS - 16));
|
|
646
|
|
647 /* clip */
|
|
648 if (sample >= MAD_F_ONE)
|
|
649 sample = MAD_F_ONE - 1;
|
|
650 else if (sample < -MAD_F_ONE)
|
|
651 sample = -MAD_F_ONE;
|
|
652
|
|
653 /* quantize */
|
|
654 return sample >> (MAD_F_FRACBITS + 1 - 16);
|
|
655 }
|
|
656 enum mad_flow MP3FILE_impl::callback_write(void *data, struct mad_header const *header, struct mad_pcm *pcm)
|
|
657 {
|
|
658 MP3FILE_impl* pimpl = (MP3FILE_impl*)data;
|
|
659 return pimpl->callback_write_impl(pcm);
|
|
660 }
|
|
661 enum mad_flow MP3FILE_impl::callback_write_impl(struct mad_pcm *pcm)
|
|
662 {
|
|
663 if (write_data_len == 0) return MAD_FLOW_IGNORE;
|
|
664 mad_fixed_t const *left_ch = pcm->samples[0] + src_pointer;
|
|
665 mad_fixed_t const *right_ch = pcm->samples[1] + src_pointer;
|
|
666
|
|
667 unsigned int nchannels = pcm->channels;
|
|
668 unsigned int nsamples = pcm->length - src_pointer;
|
|
669 if (write_pointer + nsamples * nchannels * 2 > write_data_len) {
|
|
670 nsamples = (write_data_len - write_pointer) / nchannels / 2;
|
|
671 }
|
|
672 write_data_len &= ~(nchannels*2-1); /* write_data_len ¤Ï¤¢¤é¤«¤¸¤á´Ý¤á¤Æ¤ª¤¯ */
|
|
673 src_pointer += nsamples;
|
|
674 if (write_data == 0) { // skip data write
|
|
675 write_pointer += nsamples*2*2;
|
|
676 } else while(nsamples--) {
|
|
677 signed int sample = scale(*left_ch++);
|
|
678 write_data[write_pointer++] = sample & 0xff;
|
|
679 write_data[write_pointer++] = (sample>>8) & 0xff;
|
|
680 if (nchannels == 2) {
|
|
681 sample = scale(*right_ch++);
|
|
682 }
|
|
683 write_data[write_pointer++] = sample & 0xff;
|
|
684 write_data[write_pointer++] = (sample>>8) & 0xff;
|
|
685 }
|
|
686 if (write_pointer >= write_data_len) return MAD_FLOW_IGNORE;
|
|
687 else return MAD_FLOW_CONTINUE;
|
|
688 }
|
|
689
|
|
690 MP3FILE::MP3FILE(FILE* stream, int len) {
|
|
691 pimpl = new MP3FILE_impl(stream);
|
|
692 if (pimpl->status == MP3FILE_impl::DONE) {
|
|
693 delete pimpl;
|
|
694 pimpl = 0;
|
|
695 fclose(stream);
|
|
696 return;
|
|
697 }
|
|
698 wavinfo.SamplingRate = pimpl->decoder.sync->synth.pcm.samplerate;
|
|
699 wavinfo.Channels = 2;
|
|
700 wavinfo.DataBits = 16;
|
|
701 }
|
|
702 MP3FILE::~MP3FILE() {
|
|
703 if (pimpl) {
|
|
704 FILE* s = pimpl->stream;
|
|
705 delete pimpl;
|
|
706 fclose(s);
|
|
707 }
|
|
708 pimpl = 0;
|
|
709 }
|
|
710 int MP3FILE::Read(char* buf, int blksize, int blklen) {
|
|
711 if (pimpl == 0) return -1;
|
|
712 pimpl->write_data = buf;
|
|
713 pimpl->write_data_len = blksize*blklen;
|
|
714 pimpl->write_pointer = 0;
|
|
715 do {
|
|
716 pimpl->run();
|
|
717 } while(pimpl->status != MP3FILE_impl::DONE && pimpl->write_pointer < pimpl->write_data_len);
|
|
718 return pimpl->write_pointer / blksize;
|
|
719 }
|
|
720 void MP3FILE::Seek(int count) {
|
|
721 FILE* stream = pimpl->stream;
|
|
722 delete pimpl;
|
|
723 fseek(stream,0,0);
|
|
724 pimpl = new MP3FILE_impl(stream);
|
|
725 if (pimpl->status == MP3FILE_impl::DONE) {
|
|
726 delete pimpl;
|
|
727 pimpl = 0;
|
|
728 fclose(stream);
|
|
729 return;
|
|
730 }
|
|
731 int blksize = 1;
|
|
732 blksize *= wavinfo.Channels * (wavinfo.DataBits/8);
|
|
733 pimpl->write_data = 0;
|
|
734 pimpl->write_data_len = count * blksize;
|
|
735 pimpl->write_pointer = 0;
|
|
736 do {
|
|
737 pimpl->run();
|
|
738 } while(pimpl->status != MP3FILE_impl::DONE && pimpl->write_pointer < pimpl->write_data_len);
|
|
739 return;
|
|
740 }
|
|
741 #elif USE_SMPEG
|
|
742 #include<smpeg/smpeg.h>
|
|
743
|
|
744 struct MP3FILE_impl {
|
|
745 SMPEG* info;
|
|
746 FILE* stream;
|
|
747 MP3FILE_impl(FILE*);
|
|
748 };
|
|
749
|
|
750 MP3FILE_impl::MP3FILE_impl(FILE* _stream) {
|
|
751 stream = _stream;
|
|
752 info = SMPEG_new_descr(fileno(stream), NULL, 0);
|
|
753 fprintf(stderr,"mp3 %x\n",info);
|
|
754 if (info && SMPEG_error(info) ) info = 0;
|
|
755 SMPEG_enableaudio(info, 0);
|
|
756 SMPEG_enableaudio(info, 1);
|
|
757 SMPEG_play(info);
|
|
758 }
|
|
759
|
|
760 MP3FILE::MP3FILE(FILE* stream, int len) {
|
|
761 pimpl = new MP3FILE_impl(stream);
|
|
762 if (pimpl->info == 0) {
|
|
763 delete pimpl;
|
|
764 fclose(stream);
|
|
765 return;
|
|
766 }
|
|
767 SDL_AudioSpec fmt;
|
|
768 SMPEG_wantedSpec(pimpl->info, &fmt);
|
|
769 wavinfo.SamplingRate = fmt.freq;
|
|
770 wavinfo.Channels = fmt.channels;
|
|
771 wavinfo.DataBits = (fmt.format == AUDIO_S8) ? 8:16;
|
|
772 }
|
|
773 MP3FILE::~MP3FILE() {
|
|
774 if (pimpl && pimpl->info) {
|
|
775 if (SMPEG_status(pimpl->info) == SMPEG_PLAYING) SMPEG_stop(pimpl->info);
|
|
776 SMPEG_delete(pimpl->info);
|
|
777 }
|
|
778 if (pimpl) {
|
|
779 fclose(pimpl->stream);
|
|
780 delete pimpl;
|
|
781 pimpl = 0;
|
|
782 }
|
|
783 }
|
|
784 int MP3FILE::Read(char* buf, int blksize, int blklen) {
|
|
785 if (pimpl == 0 || pimpl->info == 0) return -1;
|
|
786 int r = SMPEG_playAudio(pimpl->info, (Uint8*)buf, blksize*blklen);
|
|
787 if (r <= 0) { // end of file
|
|
788 return -1;
|
|
789 }
|
|
790 return r / blksize;
|
|
791 }
|
|
792 void MP3FILE::Seek(int count) {
|
|
793 if (pimpl == 0 || pimpl->info == 0) return;
|
|
794 SMPEG_stop(pimpl->info);
|
|
795 SMPEG_rewind(pimpl->info);
|
|
796 SMPEG_play(pimpl->info);
|
|
797 count /= 4;
|
|
798 count *= 4; // reduce noise; possibly SMPEG error
|
|
799 char* d = new char[count*channels*2];
|
|
800 Read(d,count,channels*2);
|
|
801 delete[] d;
|
|
802 return;
|
|
803 }
|
|
804 #else /* SMPEG */
|
|
805 MP3FILE::MP3FILE(FILE* stream, int len) {pimpl = 0;}
|
|
806 MP3FILE::~MP3FILE(){}
|
|
807 void MP3FILE::Seek(int count){}
|
|
808 int MP3FILE::Read(char* buf, int blksize, int blklen){return -1;}
|
|
809 #endif /* SMPEG */
|