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)
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
{
WAVE_FORMAT_UNKNOWN = 0x0000, /* Microsoft Unknown Wave Format */
WAVE_FORMAT_PCM = 0x0001, /* Microsoft PCM Format */
+ WAVE_FORMAT_ADPCM = 0x0002, /* Microsoft ADPCM Format */
WAVE_FORMAT_IEEE_FLOAT = 0x0003, /* IEEE Float */
WAVE_FORMAT_ALAW = 0x0006, /* Microsoft ALAW */
WAVE_FORMAT_MULAW = 0x0007, /* Microsoft MULAW */
WAVE_FORMAT_DVI_ADPCM = 0x0011, /* Intel's DVI ADPCM */
+ WAVE_FORMAT_DIALOGIC_OKI_ADPCM = 0x0017, /* Dialogic OKI ADPCM */
+ WAVE_FORMAT_YAMAHA_ADPCM = 0x0020, /* Yamaha ADPCM */
+ WAVE_FORMAT_XBOX_ADPCM = 0x0069, /* XBOX ADPCM */
IBM_FORMAT_MULAW = 0x0101, /* same as WAVE_FORMAT_MULAW */
IBM_FORMAT_ALAW = 0x0102, /* same as WAVE_FORMAT_ALAW */
+ WAVE_FORMAT_SWF_ADPCM = 0x5346, /* Adobe SWF ADPCM */
WAVE_FORMAT_EXTENSIBLE = 0xFFFE
};
const struct pcm_entry wave_codecs[] = {
{ WAVE_FORMAT_UNKNOWN, 0 },
{ WAVE_FORMAT_PCM, get_linear_pcm_codec },
+ { WAVE_FORMAT_ADPCM, get_ms_adpcm_codec },
{ WAVE_FORMAT_IEEE_FLOAT, get_ieee_float_codec },
{ WAVE_FORMAT_ALAW, get_itut_g711_alaw_codec },
{ WAVE_FORMAT_MULAW, get_itut_g711_mulaw_codec },
{ WAVE_FORMAT_DVI_ADPCM, get_dvi_adpcm_codec },
+ { WAVE_FORMAT_DIALOGIC_OKI_ADPCM, get_dialogic_oki_adpcm_codec },
+ { WAVE_FORMAT_YAMAHA_ADPCM, get_yamaha_adpcm_codec },
+ { WAVE_FORMAT_XBOX_ADPCM, get_dvi_adpcm_codec },
{ IBM_FORMAT_MULAW, get_itut_g711_mulaw_codec },
{ IBM_FORMAT_ALAW, get_itut_g711_alaw_codec },
+ { WAVE_FORMAT_SWF_ADPCM, get_swf_adpcm_codec },
};
-#define NUM_FORMATS 8
+#define NUM_FORMATS 13
static const struct pcm_codec *get_wave_codec(uint32_t formattag)
{
@@ -83,13 +93,67 @@ static const struct pcm_codec *get_wave_codec(uint32_t formattag)
return 0;
}
+static struct pcm_format format;
+static uint32_t bytesdone;
+
+static bool set_msadpcm_coeffs(const uint8_t *buf)
+{
+ int i;
+ int num;
+ int size;
+
+ buf += 4; /* skip 'fmt ' */
+ size = buf[0] | (buf[1] << 8) | (buf[1] << 16) | (buf[1] << 24);
+ if (size < 50)
+ {
+ DEBUGF("CODEC_ERROR: microsoft adpcm 'fmt ' chunk size=%lu < 50\n",
+ (unsigned long)size);
+ return false;
+ }
+
+ /* get nNumCoef */
+ buf += 24;
+ num = buf[0] | (buf[1] << 8);
+
+ /*
+ * In many case, nNumCoef is 7.
+ * Depending upon the encoder, as for this value there is a possibility of
+ * increasing more.
+ * If you found the file where this value exceeds 7, please report.
+ */
+ if (num != MSADPCM_NUM_COEFF)
+ {
+ DEBUGF("CODEC_ERROR: microsoft adpcm nNumCoef=%d != 7\n", num);
+ return false;
+ }
+
+ /* get aCoeffs */
+ buf += 2;
+ for (i = 0; i < MSADPCM_NUM_COEFF; i++)
+ {
+ format.coeffs[i][0] = buf[0] | (SE(buf[1]) << 8);
+ format.coeffs[i][1] = buf[2] | (SE(buf[3]) << 8);
+ buf += 4;
+ }
+
+ return true;
+}
+
+static uint8_t *read_buffer(size_t *realsize)
+{
+ uint8_t *buffer = (uint8_t *)ci->request_buffer(realsize, format.chunksize);
+ if (bytesdone + (*realsize) > format.numbytes)
+ *realsize = format.numbytes - bytesdone;
+ bytesdone += *realsize;
+ ci->advance_buffer(*realsize);
+ return buffer;
+}
/* this is the codec entry point */
enum codec_status codec_main(void)
{
int status = CODEC_OK;
- struct pcm_format format;
- uint32_t bytesdone, decodedbytes;
+ uint32_t decodedsamples;
uint32_t i;
size_t n;
int bufcount;
@@ -125,6 +189,7 @@ next_track:
goto done;
}
if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0)) {
+ DEBUGF("CODEC_ERROR: missing riff header\n");
status = CODEC_ERROR;
goto done;
}
@@ -137,7 +202,7 @@ next_track:
format.is_signed = true;
format.is_little_endian = true;
- decodedbytes = 0;
+ decodedsamples = 0;
codec = 0;
/* iterate over WAVE chunks until the 'data' chunk, which should be after the 'fmt ' chunk */
@@ -200,11 +265,21 @@ next_track:
}
}
+ /* msadpcm specific */
+ if (format.formattag == WAVE_FORMAT_ADPCM)
+ {
+ if (!set_msadpcm_coeffs(buf))
+ {
+ status = CODEC_ERROR;
+ goto done;
+ }
+ }
+
/* get codec */
codec = get_wave_codec(format.formattag);
if (!codec)
{
- DEBUGF("CODEC_ERROR: unsupported wave format %x\n",
+ DEBUGF("CODEC_ERROR: unsupported wave format 0x%x\n",
(unsigned int) format.formattag);
status = CODEC_ERROR;
goto done;
@@ -215,7 +290,7 @@ next_track:
format.is_signed = false;
/* set format, parse codec specific tag, check format, and calculate chunk size */
- if (!codec->set_format(&format, buf))
+ if (!codec->set_format(&format))
{
status = CODEC_ERROR;
goto done;
@@ -256,12 +331,34 @@ next_track:
status = CODEC_ERROR;
goto done;
}
+ if (format.samplesperblock == 0) {
+ DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-wSamplesPerBlock file\n");
+ status = CODEC_ERROR;
+ goto done;
+ }
+ if (format.blockalign == 0)
+ {
+ DEBUGF("CODEC_ERROR: 'fmt ' chunk not found or 0-blockalign file\n");
+ i = CODEC_ERROR;
+ goto done;
+ }
if (format.numbytes == 0) {
DEBUGF("CODEC_ERROR: 'data' chunk not found or has zero-length\n");
status = CODEC_ERROR;
goto done;
}
+ /* check chunksize */
+ if ((format.chunksize / format.blockalign) * format.samplesperblock * format.channels
+ > PCM_CHUNK_SIZE)
+ format.chunksize = (PCM_CHUNK_SIZE / format.blockalign) * format.blockalign;
+ if (format.chunksize == 0)
+ {
+ DEBUGF("CODEC_ERROR: chunksize is 0\n");
+ i = CODEC_ERROR;
+ goto done;
+ }
+
ci->configure(DSP_SWITCH_FREQUENCY, ci->id3->frequency);
if (format.channels == 2) {
ci->configure(DSP_SET_STEREO_MODE, STEREO_INTERLEAVED);
@@ -295,13 +392,14 @@ next_track:
}
if (ci->seek_time) {
- uint32_t newpos = codec->get_seek_pos(ci->seek_time);
+ struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, &read_buffer);
- if (newpos > format.numbytes)
+ decodedsamples = newpos->samples;
+ if (newpos->pos > format.numbytes)
break;
- if (ci->seek_buffer(firstblockposn + newpos))
+ if (ci->seek_buffer(firstblockposn + newpos->pos))
{
- bytesdone = newpos;
+ bytesdone = newpos->pos;
}
ci->seek_complete();
}
@@ -324,11 +422,11 @@ next_track:
ci->pcmbuf_insert(samples, NULL, bufcount);
ci->advance_buffer(n);
bytesdone += n;
- decodedbytes += bufcount;
+ decodedsamples += bufcount;
if (bytesdone >= format.numbytes)
endofstream = 1;
- ci->set_elapsed(decodedbytes*1000LL/ci->id3->frequency);
+ ci->set_elapsed(decodedsamples*1000LL/ci->id3->frequency);
}
status = CODEC_OK;