Mercurial > otakunoraifu
annotate music2/wavfile.cc @ 47:5f548e5957a8
* get rid of the "deprecated conversion from string constant to ‘char*’" warnings
author | thib |
---|---|
date | Wed, 15 Apr 2009 20:26:32 +0000 |
parents | 3a6aaeab7b4e |
children | ed6c21dde840 |
rev | line source |
---|---|
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 * | |
27 | 20 * You should have received a copy of the GNU General Public License along |
21 * with this program; if not, write to the Free Software Foundation, Inc., | |
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
0 | 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 ); | |
47
5f548e5957a8
* get rid of the "deprecated conversion from string constant to ‘char*’" warnings
thib
parents:
27
diff
changeset
|
108 static char* findchunk (char* s1, const char* s2, size_t n) ; |
0 | 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 | |
47
5f548e5957a8
* get rid of the "deprecated conversion from string constant to ‘char*’" warnings
thib
parents:
27
diff
changeset
|
179 static char* findchunk (char* pstart, const char* fourcc, size_t n) |
0 | 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 */ |