summaryrefslogtreecommitdiff
path: root/apps/codecs/wav.c
diff options
context:
space:
mode:
authorYoshihisa Uchida <uchida@rockbox.org>2010-02-20 02:04:56 +0000
committerYoshihisa Uchida <uchida@rockbox.org>2010-02-20 02:04:56 +0000
commit3716abba9274f544dd31cdf4e6c83a845bf2a801 (patch)
tree07bca7cdd3e40bb176e938fcb5ea8eb2f7c3e9cb /apps/codecs/wav.c
parent93caf52db5e0afe826278c148936bdfa563724f1 (diff)
downloadrockbox-3716abba9274f544dd31cdf4e6c83a845bf2a801.tar.gz
rockbox-3716abba9274f544dd31cdf4e6c83a845bf2a801.zip
commit FS#10424 and FS#10425
- wav(RIFF) supports Microsoft ADPCM, Dialogic OKI ADPCM, YAMAHA ADPCM, Adobe SWF ADPCM. - AIFF supports QuickTime IMA ADPCM. - DVI ADPCM(IMA ADPCM) reworks. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24782 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/wav.c')
-rw-r--r--apps/codecs/wav.c122
1 files changed, 110 insertions, 12 deletions
diff --git a/apps/codecs/wav.c b/apps/codecs/wav.c
index a642f99a0f..293089a737 100644
--- a/apps/codecs/wav.c
+++ b/apps/codecs/wav.c
@@ -45,27 +45,37 @@ enum
45{ 45{
46 WAVE_FORMAT_UNKNOWN = 0x0000, /* Microsoft Unknown Wave Format */ 46 WAVE_FORMAT_UNKNOWN = 0x0000, /* Microsoft Unknown Wave Format */
47 WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */ 47 WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */
48 WAVE_FORMAT_ADPCM = 0x0002, /* Microsoft ADPCM Format */
48 WAVE_FORMAT_IEEE_FLOAT = 0x0003, /* IEEE Float */ 49 WAVE_FORMAT_IEEE_FLOAT = 0x0003, /* IEEE Float */
49 WAVE_FORMAT_ALAW = 0x0006, /* Microsoft ALAW */ 50 WAVE_FORMAT_ALAW = 0x0006, /* Microsoft ALAW */
50 WAVE_FORMAT_MULAW = 0x0007, /* Microsoft MULAW */ 51 WAVE_FORMAT_MULAW = 0x0007, /* Microsoft MULAW */
51 WAVE_FORMAT_DVI_ADPCM = 0x0011, /* Intel's DVI ADPCM */ 52 WAVE_FORMAT_DVI_ADPCM = 0x0011, /* Intel's DVI ADPCM */
53 WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017, /* Dialogic OKI ADPCM */
54 WAVE_FORMAT_YAMAHA_ADPCM = 0x0020, /* Yamaha ADPCM */
55 WAVE_FORMAT_XBOX_ADPCM = 0x0069, /* XBOX ADPCM */
52 IBM_FORMAT_MULAW = 0x0101, /* same as WAVE_FORMAT_MULAW */ 56 IBM_FORMAT_MULAW = 0x0101, /* same as WAVE_FORMAT_MULAW */
53 IBM_FORMAT_ALAW = 0x0102, /* same as WAVE_FORMAT_ALAW */ 57 IBM_FORMAT_ALAW = 0x0102, /* same as WAVE_FORMAT_ALAW */
58 WAVE_FORMAT_SWF_ADPCM = 0x5346, /* Adobe SWF ADPCM */
54 WAVE_FORMAT_EXTENSIBLE = 0xFFFE 59 WAVE_FORMAT_EXTENSIBLE = 0xFFFE
55}; 60};
56 61
57const struct pcm_entry wave_codecs[] = { 62const struct pcm_entry wave_codecs[] = {
58 { WAVE_FORMAT_UNKNOWN, 0 }, 63 { WAVE_FORMAT_UNKNOWN, 0 },
59 { WAVE_FORMAT_PCM, get_linear_pcm_codec }, 64 { WAVE_FORMAT_PCM, get_linear_pcm_codec },
65 { WAVE_FORMAT_ADPCM, get_ms_adpcm_codec },
60 { WAVE_FORMAT_IEEE_FLOAT, get_ieee_float_codec }, 66 { WAVE_FORMAT_IEEE_FLOAT, get_ieee_float_codec },
61 { WAVE_FORMAT_ALAW, get_itut_g711_alaw_codec }, 67 { WAVE_FORMAT_ALAW, get_itut_g711_alaw_codec },
62 { WAVE_FORMAT_MULAW, get_itut_g711_mulaw_codec }, 68 { WAVE_FORMAT_MULAW, get_itut_g711_mulaw_codec },
63 { WAVE_FORMAT_DVI_ADPCM, get_dvi_adpcm_codec }, 69 { WAVE_FORMAT_DVI_ADPCM, get_dvi_adpcm_codec },
70 { WAVE_FORMAT_DIALOGIC_OKI_ADPCM, get_dialogic_oki_adpcm_codec },
71 { WAVE_FORMAT_YAMAHA_ADPCM, get_yamaha_adpcm_codec },
72 { WAVE_FORMAT_XBOX_ADPCM, get_dvi_adpcm_codec },
64 { IBM_FORMAT_MULAW, get_itut_g711_mulaw_codec }, 73 { IBM_FORMAT_MULAW, get_itut_g711_mulaw_codec },
65 { IBM_FORMAT_ALAW, get_itut_g711_alaw_codec }, 74 { IBM_FORMAT_ALAW, get_itut_g711_alaw_codec },
75 { WAVE_FORMAT_SWF_ADPCM, get_swf_adpcm_codec },
66}; 76};
67 77
68#define NUM_FORMATS 8 78#define NUM_FORMATS 13
69 79
70static const struct pcm_codec *get_wave_codec(uint32_t formattag) 80static const struct pcm_codec *get_wave_codec(uint32_t formattag)
71{ 81{
@@ -83,13 +93,67 @@ static const struct pcm_codec *get_wave_codec(uint32_t formattag)
83 return 0; 93 return 0;
84} 94}
85 95
96static struct pcm_format format;
97static uint32_t bytesdone;
98
99static bool set_msadpcm_coeffs(const uint8_t *buf)
100{
101 int i;
102 int num;
103 int size;
104
105 buf += 4; /* skip 'fmt ' */
106 size = buf[0] | (buf[1] << 8) | (buf[1] << 16) | (buf[1] << 24);
107 if (size < 50)
108 {
109 DEBUGF("CODEC_ERROR: microsoft adpcm 'fmt ' chunk size=%lu < 50\n",
110 (unsigned long)size);
111 return false;
112 }
113
114 /* get nNumCoef */
115 buf += 24;
116 num = buf[0] | (buf[1] << 8);
117
118 /*
119 * In many case, nNumCoef is 7.
120 * Depending upon the encoder, as for this value there is a possibility of
121 * increasing more.
122 * If you found the file where this value exceeds 7, please report.
123 */
124 if (num != MSADPCM_NUM_COEFF)
125 {
126 DEBUGF("CODEC_ERROR: microsoft adpcm nNumCoef=%d != 7\n", num);
127 return false;
128 }
129
130 /* get aCoeffs */
131 buf += 2;
132 for (i = 0; i < MSADPCM_NUM_COEFF; i++)
133 {
134 format.coeffs[i][0] = buf[0] | (SE(buf[1]) << 8);
135 format.coeffs[i][1] = buf[2] | (SE(buf[3]) << 8);
136 buf += 4;
137 }
138
139 return true;
140}
141
142static uint8_t *read_buffer(size_t *realsize)
143{
144 uint8_t *buffer = (uint8_t *)ci->request_buffer(realsize, format.chunksize);
145 if (bytesdone + (*realsize) > format.numbytes)
146 *realsize = format.numbytes - bytesdone;
147 bytesdone += *realsize;
148 ci->advance_buffer(*realsize);
149 return buffer;
150}
86 151
87/* this is the codec entry point */ 152/* this is the codec entry point */
88enum codec_status codec_main(void) 153enum codec_status codec_main(void)
89{ 154{
90 int status = CODEC_OK; 155 int status = CODEC_OK;
91 struct pcm_format format; 156 uint32_t decodedsamples;
92 uint32_t bytesdone, decodedbytes;
93 uint32_t i; 157 uint32_t i;
94 size_t n; 158 size_t n;
95 int bufcount; 159 int bufcount;
@@ -125,6 +189,7 @@ next_track:
125 goto done; 189 goto done;
126 } 190 }
127 if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) { 191 if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) {
192 DEBUGF("CODEC_ERROR: missing riff header\n");
128 status = CODEC_ERROR; 193 status = CODEC_ERROR;
129 goto done; 194 goto done;
130 } 195 }
@@ -137,7 +202,7 @@ next_track:
137 format.is_signed = true; 202 format.is_signed = true;
138 format.is_little_endian = true; 203 format.is_little_endian = true;
139 204
140 decodedbytes = 0; 205 decodedsamples = 0;
141 codec = 0; 206 codec = 0;
142 207
143 /* iterate over WAVE chunks until the 'data' chunk, which should be after the 'fmt ' chunk */ 208 /* iterate over WAVE chunks until the 'data' chunk, which should be after the 'fmt ' chunk */
@@ -200,11 +265,21 @@ next_track:
200 } 265 }
201 } 266 }
202 267
268 /* msadpcm specific */
269 if (format.formattag == WAVE_FORMAT_ADPCM)
270 {
271 if (!set_msadpcm_coeffs(buf))
272 {
273 status = CODEC_ERROR;
274 goto done;
275 }
276 }
277
203 /* get codec */ 278 /* get codec */
204 codec = get_wave_codec(format.formattag); 279 codec = get_wave_codec(format.formattag);
205 if (!codec) 280 if (!codec)
206 { 281 {
207 DEBUGF("CODEC_ERROR: unsupported wave format %x\n", 282 DEBUGF("CODEC_ERROR: unsupported wave format 0x%x\n",
208 (unsigned int) format.formattag); 283 (unsigned int) format.formattag);
209 status = CODEC_ERROR; 284 status = CODEC_ERROR;
210 goto done; 285 goto done;
@@ -215,7 +290,7 @@ next_track:
215 format.is_signed = false; 290 format.is_signed = false;
216 291
217 /* set format, parse codec specific tag, check format, and calculate chunk size */ 292 /* set format, parse codec specific tag, check format, and calculate chunk size */
218 if (!codec->set_format(&format, buf)) 293 if (!codec->set_format(&format))
219 { 294 {
220 status = CODEC_ERROR; 295 status = CODEC_ERROR;
221 goto done; 296 goto done;
@@ -256,12 +331,34 @@ next_track:
256 status = CODEC_ERROR; 331 status = CODEC_ERROR;
257 goto done; 332 goto done;
258 } 333 }
334 if (format.samplesperblock == 0) {
335 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-wSamplesPerBlock file\n");
336 status = CODEC_ERROR;
337 goto done;
338 }
339 if (format.blockalign == 0)
340 {
341 DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-blockalign file\n");
342 i = CODEC_ERROR;
343 goto done;
344 }
259 if (format.numbytes == 0) { 345 if (format.numbytes == 0) {
260 DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n"); 346 DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n");
261 status = CODEC_ERROR; 347 status = CODEC_ERROR;
262 goto done; 348 goto done;
263 } 349 }
264 350
351 /* check chunksize */
352 if ((format.chunksize / format.blockalign) * format.samplesperblock * format.channels
353 > PCM_CHUNK_SIZE)
354 format.chunksize = (PCM_CHUNK_SIZE / format.blockalign) * format.blockalign;
355 if (format.chunksize == 0)
356 {
357 DEBUGF("CODEC_ERROR: chunksize is 0\n");
358 i = CODEC_ERROR;
359 goto done;
360 }
361
265 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency); 362 ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
266 if (format.channels == 2) { 363 if (format.channels == 2) {
267 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED); 364 ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
@@ -295,13 +392,14 @@ next_track:
295 } 392 }
296 393
297 if (ci->seek_time) { 394 if (ci->seek_time) {
298 uint32_t newpos = codec->get_seek_pos(ci->seek_time); 395 struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, &read_buffer);
299 396
300 if (newpos > format.numbytes) 397 decodedsamples = newpos->samples;
398 if (newpos->pos > format.numbytes)
301 break; 399 break;
302 if (ci->seek_buffer(firstblockposn + newpos)) 400 if (ci->seek_buffer(firstblockposn + newpos->pos))
303 { 401 {
304 bytesdone = newpos; 402 bytesdone = newpos->pos;
305 } 403 }
306 ci->seek_complete(); 404 ci->seek_complete();
307 } 405 }
@@ -324,11 +422,11 @@ next_track:
324 ci->pcmbuf_insert(samples, NULL, bufcount); 422 ci->pcmbuf_insert(samples, NULL, bufcount);
325 ci->advance_buffer(n); 423 ci->advance_buffer(n);
326 bytesdone += n; 424 bytesdone += n;
327 decodedbytes += bufcount; 425 decodedsamples += bufcount;
328 426
329 if (bytesdone >= format.numbytes) 427 if (bytesdone >= format.numbytes)
330 endofstream = 1; 428 endofstream = 1;
331 ci->set_elapsed(decodedbytes*1000LL/ci->id3->frequency); 429 ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
332 } 430 }
333 status = CODEC_OK; 431 status = CODEC_OK;
334 432