summaryrefslogtreecommitdiffstats
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
parent93caf52db5e0afe826278c148936bdfa563724f1 (diff)
downloadrockbox-3716abba9274f544dd31cdf4e6c83a845bf2a801.tar.gz
rockbox-3716abba9274f544dd31cdf4e6c83a845bf2a801.tar.bz2
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
-rw-r--r--apps/codecs/aiff.c58
-rw-r--r--apps/codecs/libpcm/SOURCES7
-rw-r--r--apps/codecs/libpcm/adpcm_seek.c101
-rw-r--r--apps/codecs/libpcm/adpcm_seek.h39
-rw-r--r--apps/codecs/libpcm/dialogic_oki_adpcm.c183
-rw-r--r--apps/codecs/libpcm/dvi_adpcm.c444
-rw-r--r--apps/codecs/libpcm/ieee_float.c29
-rw-r--r--apps/codecs/libpcm/ima_adpcm_common.c171
-rw-r--r--apps/codecs/libpcm/ima_adpcm_common.h32
-rw-r--r--apps/codecs/libpcm/itut_g711.c44
-rw-r--r--apps/codecs/libpcm/linear_pcm.c39
-rw-r--r--apps/codecs/libpcm/ms_adpcm.c166
-rw-r--r--apps/codecs/libpcm/pcm_common.h77
-rw-r--r--apps/codecs/libpcm/qt_ima_adpcm.c136
-rw-r--r--apps/codecs/libpcm/support_formats.h21
-rw-r--r--apps/codecs/libpcm/swf_adpcm.c233
-rw-r--r--apps/codecs/libpcm/yamaha_adpcm.c245
-rw-r--r--apps/codecs/wav.c122
-rw-r--r--apps/metadata/aiff.c23
-rw-r--r--apps/metadata/wave.c138
20 files changed, 1968 insertions, 340 deletions
diff --git a/apps/codecs/aiff.c b/apps/codecs/aiff.c
index 2e10d1e416..4b870386c1 100644
--- a/apps/codecs/aiff.c
+++ b/apps/codecs/aiff.c
@@ -36,6 +36,7 @@ enum {
AIFC_FORMAT_MULAW = FOURCC('u', 'l', 'a', 'w'), /* AIFC uLaw compressed */
AIFC_FORMAT_IEEE_FLOAT32 = FOURCC('f', 'l', '3', '2'), /* AIFC IEEE float 32 bit */
AIFC_FORMAT_IEEE_FLOAT64 = FOURCC('f', 'l', '6', '4'), /* AIFC IEEE float 64 bit */
+ AIFC_FORMAT_QT_IMA_ADPCM = FOURCC('i', 'm', 'a', '4'), /* AIFC QuickTime IMA ADPCM */
};
static const struct pcm_entry pcm_codecs[] = {
@@ -44,9 +45,10 @@ static const struct pcm_entry pcm_codecs[] = {
{ AIFC_FORMAT_MULAW, get_itut_g711_mulaw_codec },
{ AIFC_FORMAT_IEEE_FLOAT32, get_ieee_float_codec },
{ AIFC_FORMAT_IEEE_FLOAT64, get_ieee_float_codec },
+ { AIFC_FORMAT_QT_IMA_ADPCM, get_qt_ima_adpcm_codec },
};
-#define NUM_FORMATS 5
+#define NUM_FORMATS 6
static int32_t samples[PCM_CHUNK_SIZE] IBSS_ATTR;
@@ -70,7 +72,7 @@ enum codec_status codec_main(void)
{
int status = CODEC_OK;
struct pcm_format format;
- uint32_t bytesdone, decodedbytes;
+ uint32_t bytesdone, decodedsamples;
uint32_t num_sample_frames = 0;
uint32_t i = CODEC_OK;
size_t n;
@@ -128,7 +130,7 @@ next_track:
format.is_signed = true;
format.is_little_endian = false;
- decodedbytes = 0;
+ decodedsamples = 0;
codec = 0;
/* read until 'SSND' chunk, which typically is last */
@@ -168,8 +170,11 @@ next_track:
* aiff's sample_size is uncompressed sound data size.
* But format.bitspersample is compressed sound data size.
*/
- if (format.formattag == AIFC_FORMAT_ALAW || format.formattag == AIFC_FORMAT_MULAW)
+ if (format.formattag == AIFC_FORMAT_ALAW ||
+ format.formattag == AIFC_FORMAT_MULAW)
format.bitspersample = 8;
+ else if (format.formattag == AIFC_FORMAT_QT_IMA_ADPCM)
+ format.bitspersample = 4;
}
else
format.formattag = AIFC_FORMAT_PCM;
@@ -184,9 +189,9 @@ next_track:
/* offset2snd */
offset2snd = (buf[8]<<24)|(buf[9]<<16)|(buf[10]<<8)|buf[11];
/* block_size */
- format.blockalign = (buf[12]<<24)|(buf[13]<<16)|(buf[14]<<8)|buf[15];
+ format.blockalign = ((buf[12]<<24)|(buf[13]<<16)|(buf[14]<<8)|buf[15]) >> 3;
if (format.blockalign == 0)
- format.blockalign = format.channels*format.bitspersample;
+ format.blockalign = format.channels * format.bitspersample >> 3;
format.numbytes = i - 8 - offset2snd;
i = 8 + offset2snd; /* advance to the beginning of data */
} else if (is_aifc && (memcmp(buf, "FVER", 4)==0)) {
@@ -228,7 +233,7 @@ next_track:
goto done;
}
- if (!codec->set_format(&format, 0))
+ if (!codec->set_format(&format))
{
i = CODEC_ERROR;
goto done;
@@ -246,6 +251,30 @@ next_track:
goto done;
}
+ if (format.samplesperblock == 0)
+ {
+ DEBUGF("CODEC_ERROR: samplesperblock is 0\n");
+ i = CODEC_ERROR;
+ goto done;
+ }
+ if (format.blockalign == 0)
+ {
+ DEBUGF("CODEC_ERROR: blockalign is 0\n");
+ i = 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;
+ }
+
firstblockposn = 1024 - n;
ci->advance_buffer(firstblockposn);
@@ -260,11 +289,14 @@ next_track:
break;
if (ci->seek_time) {
- uint32_t newpos = codec->get_seek_pos(ci->seek_time);
- if (newpos > format.numbytes)
+ /* 2nd args(read_buffer) is unnecessary in the format which AIFF supports. */
+ struct pcm_pos *newpos = codec->get_seek_pos(ci->seek_time, NULL);
+
+ decodedsamples = newpos->samples;
+ if (newpos->pos > format.numbytes)
break;
- if (ci->seek_buffer(firstblockposn + newpos))
- bytesdone = newpos;
+ if (ci->seek_buffer(firstblockposn + newpos->pos))
+ bytesdone = newpos->pos;
ci->seek_complete();
}
aifbuf = (uint8_t *)ci->request_buffer(&n, format.chunksize);
@@ -288,11 +320,11 @@ next_track:
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);
}
i = CODEC_OK;
diff --git a/apps/codecs/libpcm/SOURCES b/apps/codecs/libpcm/SOURCES
index 89be3452b1..356c9cdbb7 100644
--- a/apps/codecs/libpcm/SOURCES
+++ b/apps/codecs/libpcm/SOURCES
@@ -2,3 +2,10 @@ linear_pcm.c
itut_g711.c
dvi_adpcm.c
ieee_float.c
+adpcm_seek.c
+dialogic_oki_adpcm.c
+ms_adpcm.c
+yamaha_adpcm.c
+ima_adpcm_common.c
+qt_ima_adpcm.c
+swf_adpcm.c
diff --git a/apps/codecs/libpcm/adpcm_seek.c b/apps/codecs/libpcm/adpcm_seek.c
new file mode 100644
index 0000000000..ce49d5fcd3
--- /dev/null
+++ b/apps/codecs/libpcm/adpcm_seek.c
@@ -0,0 +1,101 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Yoshihisa Uchida
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "adpcm_seek.h"
+#include "codeclib.h"
+
+/*
+ * The helper functions in order to seek for the adpcm codec
+ * which does not include the header each the data block.
+ */
+
+#define MAX_STORE_COUNT 1000
+
+static struct adpcm_data seek_table[MAX_STORE_COUNT];
+static int seek_count;
+static int cur_count;
+static int max_ratio;
+static int cur_ratio;
+
+void init_seek_table(uint32_t max_count)
+{
+ int i = 0;
+
+ for ( ; i < MAX_STORE_COUNT; i++)
+ {
+ seek_table[i].is_valid = false;
+ }
+ seek_count = max_count / MAX_STORE_COUNT + 1;
+ max_ratio = max_count / seek_count + 1;
+ cur_count = 0;
+ cur_ratio = -1;
+}
+
+void add_adpcm_data(struct adpcm_data *data)
+{
+ if (--cur_count <= 0)
+ {
+ cur_count = seek_count;
+ if (++cur_ratio >= max_ratio)
+ cur_ratio = max_ratio - 1;
+
+ if (!seek_table[cur_ratio].is_valid)
+ {
+ seek_table[cur_ratio].pcmdata[0] = data->pcmdata[0];
+ seek_table[cur_ratio].pcmdata[1] = data->pcmdata[1];
+ seek_table[cur_ratio].step[0] = data->step[0];
+ seek_table[cur_ratio].step[1] = data->step[1];
+ seek_table[cur_ratio].is_valid = true;
+ }
+ }
+}
+
+uint32_t seek(uint32_t count, struct adpcm_data *seek_data,
+ uint8_t *(*read_buffer)(size_t *realsize),
+ int (*decode)(const uint8_t *inbuf, size_t inbufsize))
+{
+ int new_ratio = count / seek_count;
+
+ if (new_ratio >= max_ratio)
+ new_ratio = max_ratio - 1;
+
+ if (!seek_table[new_ratio].is_valid)
+ {
+ uint8_t *buffer;
+ size_t n;
+
+ do
+ {
+ buffer = read_buffer(&n);
+ if (n == 0)
+ break;
+ decode(buffer, n);
+ } while (cur_ratio < new_ratio);
+ }
+
+ seek_data->pcmdata[0] = seek_table[new_ratio].pcmdata[0];
+ seek_data->pcmdata[1] = seek_table[new_ratio].pcmdata[1];
+ seek_data->step[0] = seek_table[new_ratio].step[0];
+ seek_data->step[1] = seek_table[new_ratio].step[1];
+
+ cur_ratio = new_ratio;
+ cur_count = seek_count;
+ return cur_ratio * seek_count;
+}
diff --git a/apps/codecs/libpcm/adpcm_seek.h b/apps/codecs/libpcm/adpcm_seek.h
new file mode 100644
index 0000000000..66ec390097
--- /dev/null
+++ b/apps/codecs/libpcm/adpcm_seek.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Yoshihisa Uchida
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef CODEC_LIBPCM_ADPCM_SEEK_H
+#define CODEC_LIBPCM_ADPCM_SEEK_H
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+struct adpcm_data {
+ int16_t pcmdata[2];
+ uint16_t step[2];
+ bool is_valid;
+};
+
+void init_seek_table(uint32_t max_count);
+void add_adpcm_data(struct adpcm_data *data);
+uint32_t seek(uint32_t seek_time, struct adpcm_data *seek_data,
+ uint8_t *(*read_buffer)(size_t *realsize),
+ int (*decode)(const uint8_t *inbuf, size_t inbufsize));
+#endif
diff --git a/apps/codecs/libpcm/dialogic_oki_adpcm.c b/apps/codecs/libpcm/dialogic_oki_adpcm.c
new file mode 100644
index 0000000000..e12930057b
--- /dev/null
+++ b/apps/codecs/libpcm/dialogic_oki_adpcm.c
@@ -0,0 +1,183 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Yoshihisa Uchida
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "codeclib.h"
+#include "pcm_common.h"
+#include "adpcm_seek.h"
+
+/*
+ * Dialogic OKI ADPCM
+ *
+ * References
+ * [1] Dialogic Corporation, Dialogic ADPCM Algorithm, 1988
+ * [2] MultimediaWiki, Dialogic IMA ADPCM, URL:http://wiki.multimedia.cx/index.php?title=Dialogic_IMA_ADPCM
+ * [3] sox source code, src/adpcms.c
+ * [4] Tetsuya Isaki, NetBSD:/sys/dev/audio.c, http://www.tri-tree.gr.jp/~isaki/NetBSD/src/sys/dev/ic/msm6258.c.html
+ */
+
+static const uint16_t step_table[] ICONST_ATTR = {
+ 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55,
+ 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209,
+ 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
+ 876, 963, 1060, 1166, 1282, 1411, 1552,
+};
+
+static const int index_table[] ICONST_ATTR = {
+ -1, -1, -1, -1, 2, 4, 6, 8
+};
+
+static struct adpcm_data cur_data;
+
+static struct pcm_format *fmt;
+
+static bool set_format(struct pcm_format *format)
+{
+ uint32_t max_chunk_count;
+
+ fmt = format;
+
+ if (fmt->bitspersample != 4)
+ {
+ DEBUGF("CODEC_ERROR: dialogic oki adpcm must be 4 bitspersample: %d\n",
+ fmt->bitspersample);
+ return false;
+ }
+
+ if (fmt->channels != 1)
+ {
+ DEBUGF("CODEC_ERROR: dialogic oki adpcm must be monaural\n");
+ return false;
+ }
+
+ /* blockalign = 2 samples */
+ fmt->blockalign = 1;
+ fmt->samplesperblock = 2;
+
+ /* chunksize = about 1/32[sec] data */
+ fmt->chunksize = ci->id3->frequency >> 6;
+
+ max_chunk_count = (uint64_t)ci->id3->length * ci->id3->frequency
+ / (2000LL * fmt->chunksize);
+
+ /* initialize seek table */
+ init_seek_table(max_chunk_count);
+ /* add first data */
+ add_adpcm_data(&cur_data);
+
+ return true;
+}
+
+static int16_t create_pcmdata(uint8_t nibble)
+{
+ int16_t delta;
+ int16_t index = cur_data.step[0];
+ int16_t step = step_table[index];
+
+ delta = (step >> 3);
+ if (nibble & 4) delta += step;
+ if (nibble & 2) delta += (step >> 1);
+ if (nibble & 1) delta += (step >> 2);
+
+ if (nibble & 0x08)
+ cur_data.pcmdata[0] -= delta;
+ else
+ cur_data.pcmdata[0] += delta;
+
+ CLIP(cur_data.pcmdata[0], -2048, 2047);
+
+ index += index_table[nibble & 0x07];
+ CLIP(index, 0, 48);
+ cur_data.step[0] = index;
+
+ return cur_data.pcmdata[0];
+}
+
+static int decode(const uint8_t *inbuf, size_t inbufsize,
+ int32_t *outbuf, int *outbufcount)
+{
+ size_t nsamples = 0;
+
+ while (inbufsize)
+ {
+ *outbuf++ = create_pcmdata(*inbuf >> 4) << 17;
+ *outbuf++ = create_pcmdata(*inbuf ) << 17;
+ nsamples += 2;
+
+ inbuf++;
+ inbufsize--;
+ }
+
+ *outbufcount = nsamples;
+ add_adpcm_data(&cur_data);
+
+ return CODEC_OK;
+}
+
+static int decode_for_seek(const uint8_t *inbuf, size_t inbufsize)
+{
+ while (inbufsize)
+ {
+ create_pcmdata(*inbuf >> 4);
+ create_pcmdata(*inbuf );
+
+ inbuf++;
+ inbufsize--;
+ }
+
+ add_adpcm_data(&cur_data);
+
+ return CODEC_OK;
+}
+
+static struct pcm_pos *get_seek_pos(long seek_time,
+ uint8_t *(*read_buffer)(size_t *realsize))
+{
+ static struct pcm_pos newpos;
+ uint32_t seek_count = 0;
+ uint32_t new_count;
+
+ if (seek_time > 0)
+ seek_count = (uint64_t)seek_time * ci->id3->frequency
+ / (2000LL * fmt->chunksize);
+
+ new_count = seek(seek_count, &cur_data, read_buffer, &decode_for_seek);
+ newpos.pos = new_count * fmt->chunksize;
+ newpos.samples = (newpos.pos / fmt->blockalign) * fmt->samplesperblock;
+ return &newpos;
+}
+
+static const struct pcm_codec codec = {
+ set_format,
+ get_seek_pos,
+ decode,
+ };
+
+const struct pcm_codec *get_dialogic_oki_adpcm_codec(void)
+{
+ /*
+ * initialize first pcm data, step index
+ * because the dialogic oki adpcm is always monaural,
+ * pcmdata[1], step[1] do not use.
+ */
+ cur_data.pcmdata[0] = 0;
+ cur_data.step[0] = 0;
+
+ return &codec;
+}
diff --git a/apps/codecs/libpcm/dvi_adpcm.c b/apps/codecs/libpcm/dvi_adpcm.c
index 3df5e901be..97ba017451 100644
--- a/apps/codecs/libpcm/dvi_adpcm.c
+++ b/apps/codecs/libpcm/dvi_adpcm.c
@@ -21,280 +21,282 @@
****************************************************************************/
#include "codeclib.h"
#include "pcm_common.h"
-#include "support_formats.h"
+#include "ima_adpcm_common.h"
/*
- * Intel DVI ADPCM
+ * Intel DVI ADPCM (IMA ADPCM)
+ *
+ * References
+ * [1] The IMA Digital Audio Focus and Technical Working Groups,
+ * Recommended Practices for Enhancing Digital Audio Compatibility
+ * in Multimedia Systems Revision 3.00, 1992
+ * [2] Microsoft Corporation, New Multimedia Data Types and Data Techniques,
+ * Revision:3.0, 1994
+ * [3] ffmpeg source code, libavcodec/adpcm.c
*/
-static const uint16_t dvi_adpcm_steptab[89] ICONST_ATTR = {
- 7, 8, 9, 10, 11, 12, 13, 14,
- 16, 17, 19, 21, 23, 25, 28, 31,
- 34, 37, 41, 45, 50, 55, 60, 66,
- 73, 80, 88, 97, 107, 118, 130, 143,
- 157, 173, 190, 209, 230, 253, 279, 307,
- 337, 371, 408, 449, 494, 544, 598, 658,
- 724, 796, 876, 963, 1060, 1166, 1282, 1411,
- 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
- 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
- 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
- 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
- 32767 };
-
-static const int dvi_adpcm_indextab4[8] ICONST_ATTR = {
- -1, -1, -1, -1, 2, 4, 6, 8 };
-
-static const int dvi_adpcm_indextab3[4] ICONST_ATTR = { -1, -1, 1, 2 };
-
static struct pcm_format *fmt;
-static bool set_format(struct pcm_format *format, const unsigned char *fmtpos)
+static bool set_format(struct pcm_format *format)
{
fmt = format;
- (void)fmtpos;
-
- if (fmt->bitspersample != 4 && fmt->bitspersample != 3)
+ if (fmt->bitspersample < 2 || fmt->bitspersample > 5)
{
- DEBUGF("CODEC_ERROR: dvi_adpcm must have 3 or 4 bitspersample\n");
+ DEBUGF("CODEC_ERROR: dvi adpcm must be 2, 3, 4 or 5 bitspersample: %d\n",
+ fmt->bitspersample);
return false;
}
- if (fmt->size < 2) {
- DEBUGF("CODEC_ERROR: dvi_adpcm is missing SamplesPerBlock value\n");
- return false;
- }
-
- /* chunksize is computed so that one chunk is about 1/50s.
- * this make 4096 for 44.1kHz 16bits stereo.
- * It also has to be a multiple of blockalign */
- fmt->chunksize = (1 + fmt->avgbytespersec / (50*fmt->blockalign))*fmt->blockalign;
-
- /* check that the output buffer is big enough (convert to samplespersec,
- then round to the blockalign multiple below) */
- if ((((uint64_t)fmt->chunksize * ci->id3->frequency * fmt->channels * fmt->bitspersample)>>3)
- /(uint64_t)fmt->avgbytespersec >= PCM_CHUNK_SIZE)
- fmt->chunksize = ((uint64_t)PCM_CHUNK_SIZE * fmt->avgbytespersec
- /((uint64_t)ci->id3->frequency * fmt->channels * 2
- * fmt->blockalign)) * fmt->blockalign;
+ fmt->chunksize = fmt->blockalign;
+ init_ima_adpcm_decoder(fmt->bitspersample, NULL);
return true;
}
-static uint32_t get_seek_pos(long seek_time)
+static struct pcm_pos *get_seek_pos(long seek_time,
+ uint8_t *(*read_buffer)(size_t *realsize))
{
- uint32_t newpos;
+ static struct pcm_pos newpos;
+ uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency)
+ / (1000LL * fmt->samplesperblock);
- /* use avgbytespersec to round to the closest blockalign multiple,
- add firstblockposn. 64-bit casts to avoid overflows. */
- newpos = (((uint64_t)fmt->avgbytespersec*(seek_time - 1))
- / (1000LL*fmt->blockalign))*fmt->blockalign;
- return newpos;
+ (void)read_buffer;
+ newpos.pos = newblock * fmt->blockalign;
+ newpos.samples = newblock * fmt->samplesperblock;
+ return &newpos;
}
-static int decode_dvi_adpcm(const uint8_t *inbuf, size_t inbufsize,
- int32_t *outbuf, size_t *outbufcount)
+static inline void decode_2bit(const uint8_t **inbuf,
+ int32_t **outbuf, int *outbufcount)
{
- size_t nsamples = 0;
- int sample[2];
- int samplecode[32][2];
+ int ch;
int i;
- int stepindex[2];
- int c;
- int diff;
- int step;
- int codem;
- int code;
+ int32_t *pcmbuf;
+ int samples;
- if (fmt->bitspersample != 4 && fmt->bitspersample != 3) {
- DEBUGF("decode_dvi_adpcm: wrong bitspersample\n");
- return CODEC_ERROR;
+ samples = fmt->blockalign / (4 * fmt->channels) - 1;
+ *outbufcount += (samples << 4);
+ while (samples-- > 0)
+ {
+ for (ch = 0; ch < fmt->channels; ch++)
+ {
+ pcmbuf = *outbuf + ch;
+ for (i = 0; i < 4; i++)
+ {
+ *pcmbuf = create_pcmdata(ch, **inbuf ) << 13;
+ pcmbuf += fmt->channels;
+ *pcmbuf = create_pcmdata(ch, **inbuf >> 2) << 13;
+ pcmbuf += fmt->channels;
+ *pcmbuf = create_pcmdata(ch, **inbuf >> 4) << 13;
+ pcmbuf += fmt->channels;
+ *pcmbuf = create_pcmdata(ch, **inbuf >> 6) << 13;
+ pcmbuf += fmt->channels;
+ (*inbuf)++;
+ }
+ }
+ *outbuf += 16 * fmt->channels;
}
+}
- /* decode block header */
- for (c = 0; c < fmt->channels && inbufsize >= 4; c++) {
- /* decode + push first sample */
- sample[c] = (short)(inbuf[0]|(inbuf[1]<<8));/* need cast for sign-extend */
- outbuf[c] = sample[c] << 13;
- nsamples++;
- stepindex[c] = inbuf[2];
- /* check for step table index overflow */
- if (stepindex[c] > 88) {
- DEBUGF("decode_dvi_adpcm: stepindex[%d]=%d>88\n",c,stepindex[c]);
- return CODEC_ERROR;
- }
+static inline void decode_3bit(const uint8_t **inbuf,
+ int32_t **outbuf, int *outbufcount)
+{
+ const uint8_t *adpcmbuf;
+ uint32_t adpcms;
+ int ch;
+ int i;
+ int32_t *pcmbuf;
+ int samples;
- inbuf += 4;
- inbufsize -= 4;
- }
- if (fmt->bitspersample == 4) {
- while (inbufsize >= (size_t)(fmt->channels*4) &&
- (nsamples + (fmt->channels*8) <= *outbufcount))
+ samples = (fmt->blockalign - 4 * fmt->channels) / (12 * fmt->channels);
+ *outbufcount += (samples << 5);
+ while (samples--)
+ {
+ for (ch = 0; ch < fmt->channels; ch++)
{
- for (c = 0; c < fmt->channels; c++)
+ adpcmbuf = *inbuf + ch * 4;
+ pcmbuf = *outbuf + ch;
+ adpcms = *adpcmbuf++;
+ adpcms |= (*adpcmbuf++) << 8;
+ adpcms |= (*adpcmbuf++) << 16;
+ for (i = 0; i < 8; i++)
{
- samplecode[0][c] = inbuf[0]&0xf;
- samplecode[1][c] = inbuf[0]>>4;
- samplecode[2][c] = inbuf[1]&0xf;
- samplecode[3][c] = inbuf[1]>>4;
- samplecode[4][c] = inbuf[2]&0xf;
- samplecode[5][c] = inbuf[2]>>4;
- samplecode[6][c] = inbuf[3]&0xf;
- samplecode[7][c] = inbuf[3]>>4;
- inbuf += 4;
- inbufsize -= 4;
+ *pcmbuf = create_pcmdata(ch, adpcms >> (3 * i)) << 13;
+ pcmbuf += fmt->channels;
}
+ adpcms = *adpcmbuf++;
+ adpcmbuf += (fmt->channels - 1) * 4;
+ adpcms |= (*adpcmbuf++) << 8;
+ adpcms |= (*adpcmbuf++) << 16;
for (i = 0; i < 8; i++)
{
- for (c = 0; c < fmt->channels; c++)
- {
- step = dvi_adpcm_steptab[stepindex[c]];
- codem = samplecode[i][c];
- code = codem & 0x07;
-
- /* adjust the step table index */
- stepindex[c] += dvi_adpcm_indextab4[code];
- /* check for step table index overflow and underflow */
- if (stepindex[c] > 88)
- stepindex[c] = 88;
- else if (stepindex[c] < 0)
- stepindex[c] = 0;
- /* calculate the difference */
-#ifdef STRICT_IMA
- diff = 0;
- if (code & 4)
- diff += step;
- step = step >> 1;
- if (code & 2)
- diff += step;
- step = step >> 1;
- if (code & 1)
- diff += step;
- step = step >> 1;
- diff += step;
-#else
- diff = ((code + code + 1) * step) >> 3; /* faster */
-#endif
- /* check the sign bit */
- /* check for overflow and underflow errors */
- if (code != codem)
- {
- sample[c] -= diff;
- if (sample[c] < -32768)
- sample[c] = -32768;
- }
- else
- {
- sample[c] += diff;
- if (sample[c] > 32767)
- sample[c] = 32767;
- }
- /* output the new sample */
- outbuf[nsamples] = sample[c] << 13;
- nsamples++;
- }
+ *pcmbuf = create_pcmdata(ch, adpcms >> (3 * i)) << 13;
+ pcmbuf += fmt->channels;
}
- }
- } else { /* bitspersample == 3 */
- while (inbufsize >= (uint32_t)(fmt->channels*12) &&
- (nsamples + 32*fmt->channels) <= *outbufcount) {
- for (c = 0; c < fmt->channels; c++) {
- uint16_t bitstream = 0;
- int bitsread = 0;
- for (i = 0; i < 32 && inbufsize > 0; i++) {
- if (bitsread < 3) {
- /* read 8 more bits */
- bitstream |= inbuf[0]<<bitsread;
- bitsread += 8;
- inbufsize--;
- inbuf++;
- }
- samplecode[i][c] = bitstream & 7;
- bitstream = bitstream>>3;
- bitsread -= 3;
- }
- if (bitsread != 0) {
- /* 32*3 = 3 words, so we should end with bitsread==0 */
- DEBUGF("decode_dvi_adpcm: error in implementation\n");
- return CODEC_ERROR;
- }
+ adpcms = *adpcmbuf++;
+ adpcms |= (*adpcmbuf++) << 8;
+ adpcmbuf += (fmt->channels - 1) * 4;
+ adpcms |= (*adpcmbuf++) << 16;
+ for (i = 0; i < 8; i++)
+ {
+ *pcmbuf = create_pcmdata(ch, adpcms >> (3 * i)) << 13;
+ pcmbuf += fmt->channels;
}
-
- for (i = 0; i < 32; i++) {
- for (c = 0; c < fmt->channels; c++) {
- step = dvi_adpcm_steptab[stepindex[c]];
- codem = samplecode[i][c];
- code = codem & 0x03;
-
- /* adjust the step table index */
- stepindex[c] += dvi_adpcm_indextab3[code];
- /* check for step table index overflow and underflow */
- if (stepindex[c] > 88)
- stepindex[c] = 88;
- else if (stepindex[c] < 0)
- stepindex[c] = 0;
- /* calculate the difference */
-#ifdef STRICT_IMA
- diff = 0;
- if (code & 2)
- diff += step;
- step = step >> 1;
- if (code & 1)
- diff += step;
- step = step >> 1;
- diff += step;
-#else
- diff = ((code + code + 1) * step) >> 3; /* faster */
-#endif
- /* check the sign bit */
- /* check for overflow and underflow errors */
- if (code != codem) {
- sample[c] -= diff;
- if (sample[c] < -32768)
- sample[c] = -32768;
- }
- else {
- sample[c] += diff;
- if (sample[c] > 32767)
- sample[c] = 32767;
- }
- /* output the new sample */
- outbuf[nsamples] = sample[c] << 13;
- nsamples++;
- }
+ adpcms = *adpcmbuf++;
+ adpcms |= (*adpcmbuf++) << 8;
+ adpcms |= (*adpcmbuf++) << 16;
+ for (i = 0; i < 8; i++)
+ {
+ *pcmbuf = create_pcmdata(ch, adpcms >> (3 * i)) << 13;
+ pcmbuf += fmt->channels;
}
}
+ *outbuf += 32 * fmt->channels;
+ *inbuf += 12 * fmt->channels;
}
+}
- if (nsamples > *outbufcount) {
- DEBUGF("decode_dvi_adpcm: output buffer overflow!\n");
- return CODEC_ERROR;
+static inline void decode_4bit(const uint8_t **inbuf,
+ int32_t **outbuf, int *outbufcount)
+{
+ int ch;
+ int i;
+ int32_t *pcmbuf;
+ int samples;
+
+ samples = fmt->blockalign / (4 * fmt->channels) - 1;
+ *outbufcount += (samples << 3);
+ while (samples-- > 0)
+ {
+ for (ch = 0; ch < fmt->channels; ch++)
+ {
+ pcmbuf = *outbuf + ch;
+ for (i = 0; i < 4; i++)
+ {
+ *pcmbuf = create_pcmdata_size4(ch, **inbuf ) << 13;
+ pcmbuf += fmt->channels;
+ *pcmbuf = create_pcmdata_size4(ch, **inbuf >> 4) << 13;
+ pcmbuf += fmt->channels;
+ (*inbuf)++;
+ }
+ }
+ *outbuf += 8 * fmt->channels;
}
- *outbufcount = nsamples;
- if (inbufsize != 0) {
- DEBUGF("decode_dvi_adpcm: n=%d unprocessed bytes\n", (int)inbufsize);
+}
+
+static inline void decode_5bit(const uint8_t **inbuf,
+ int32_t **outbuf, int *outbufcount)
+{
+ const uint8_t *adpcmbuf;
+ uint64_t adpcms;
+ int ch;
+ int i;
+ int32_t *pcmbuf;
+ int samples;
+
+ samples = (fmt->blockalign - 4 * fmt->channels) / (20 * fmt->channels);
+ *outbufcount += (samples << 5);
+ while (samples--)
+ {
+ for (ch = 0; ch < fmt->channels; ch++)
+ {
+ adpcmbuf = *inbuf + ch * 4;
+ pcmbuf = *outbuf + ch;
+ adpcms = *adpcmbuf++;
+ adpcms |= (*adpcmbuf++) << 8;
+ adpcms |= (*adpcmbuf++) << 16;
+ adpcms |= (uint64_t)(*adpcmbuf++) << 24;
+ adpcmbuf += (fmt->channels - 1) * 4;
+ adpcms |= (uint64_t)(*adpcmbuf++) << 32;
+ for (i = 0; i < 8; i++)
+ {
+ *pcmbuf = create_pcmdata(ch, adpcms >> (5 * i)) << 13;
+ pcmbuf += fmt->channels;
+ }
+ adpcms = *adpcmbuf++;
+ adpcms |= (*adpcmbuf++) << 8;
+ adpcms |= (*adpcmbuf++) << 16;
+ adpcmbuf += (fmt->channels - 1) * 4;
+ adpcms |= (uint64_t)(*adpcmbuf++) << 24;
+ adpcms |= (uint64_t)(*adpcmbuf++) << 32;
+ for (i = 0; i < 8; i++)
+ {
+ *pcmbuf = create_pcmdata(ch, adpcms >> (5 * i)) << 13;
+ pcmbuf += fmt->channels;
+ }
+ adpcms = *adpcmbuf++;
+ adpcms |= (*adpcmbuf++) << 8;
+ adpcmbuf += (fmt->channels - 1) * 4;
+ adpcms |= (*adpcmbuf++) << 16;
+ adpcms |= (uint64_t)(*adpcmbuf++) << 24;
+ adpcms |= (uint64_t)(*adpcmbuf++) << 32;
+ for (i = 0; i < 8; i++)
+ {
+ *pcmbuf = create_pcmdata(ch, adpcms >> (5 * i)) << 13;
+ pcmbuf += fmt->channels;
+ }
+ adpcms = *adpcmbuf++;
+ adpcmbuf += (fmt->channels - 1) * 4;
+ adpcms |= (*adpcmbuf++) << 8;
+ adpcms |= (*adpcmbuf++) << 16;
+ adpcms |= (uint64_t)(*adpcmbuf++) << 24;
+ adpcms |= (uint64_t)(*adpcmbuf++) << 32;
+ for (i = 0; i < 8; i++)
+ {
+ *pcmbuf = create_pcmdata(ch, adpcms >> (5 * i)) << 13;
+ pcmbuf += fmt->channels;
+ }
+ }
+ *outbuf += 32 * fmt->channels;
+ *inbuf += 20 * fmt->channels;
}
- return CODEC_OK;
}
static int decode(const uint8_t *inbuf, size_t inbufsize,
- int32_t *outbuf, int *outbufsize)
+ int32_t *outbuf, int *outbufcount)
{
+ int ch;
unsigned int i;
+ int32_t init_pcmdata[2];
+ int8_t init_index[2];
unsigned int nblocks = fmt->chunksize / fmt->blockalign;
(void)inbufsize;
+ *outbufcount = 0;
for (i = 0; i < nblocks; i++)
{
- size_t decodedsize = fmt->samplesperblock * fmt->channels;
- if (decode_dvi_adpcm(inbuf + i * fmt->blockalign, fmt->blockalign,
- outbuf + i * fmt->samplesperblock * fmt->channels,
- &decodedsize) != CODEC_OK) {
- return CODEC_ERROR;
+ for (ch = 0; ch < fmt->channels; ch++)
+ {
+ init_pcmdata[ch] = inbuf[0] | (inbuf[1] << 8);
+ if (init_pcmdata[ch] > 32767)
+ init_pcmdata[ch] -= 65536;
+
+ init_index[ch] = inbuf[2];
+ if (init_index[ch] > 88 || init_index[ch] < 0)
+ {
+ DEBUGF("CODEC_ERROR: dvi adpcm illegal step index=%d > 88\n",
+ init_index[ch]);
+ return CODEC_ERROR;
+ }
+ inbuf += 4;
+
+ *outbuf++ = init_pcmdata[ch] << 13;
}
+
+ *outbufcount += 1;
+ set_decode_parameters(fmt->channels, init_pcmdata, init_index);
+
+ if (fmt->bitspersample == 4)
+ decode_4bit(&inbuf, &outbuf, outbufcount);
+ else if (fmt->bitspersample == 3)
+ decode_3bit(&inbuf, &outbuf, outbufcount);
+ else if (fmt->bitspersample == 5)
+ decode_5bit(&inbuf, &outbuf, outbufcount);
+ else /* fmt->bitspersample == 2 */
+ decode_2bit(&inbuf, &outbuf, outbufcount);
}
- *outbufsize = nblocks * fmt->samplesperblock;
return CODEC_OK;
}
diff --git a/apps/codecs/libpcm/ieee_float.c b/apps/codecs/libpcm/ieee_float.c
index c0e91a46cb..0530993f31 100644
--- a/apps/codecs/libpcm/ieee_float.c
+++ b/apps/codecs/libpcm/ieee_float.c
@@ -28,33 +28,38 @@
static struct pcm_format *fmt;
-static bool set_format(struct pcm_format *format, const unsigned char *fmtpos)
+static bool set_format(struct pcm_format *format)
{
fmt = format;
- (void)fmtpos;
-
if (fmt->bitspersample != 32 && fmt->bitspersample != 64)
{
- DEBUGF("CODEC_ERROR: ieee float must be 32 or 64 bitspersample %d\n", fmt->bitspersample);
+ DEBUGF("CODEC_ERROR: ieee float must be 32 or 64 bitspersample: %d\n",
+ fmt->bitspersample);
return false;
}
fmt->bytespersample = fmt->bitspersample >> 3;
- fmt->blockalign = fmt->bytespersample;
+ fmt->samplesperblock = fmt->blockalign / (fmt->bytespersample * fmt->channels);
- /* chunksize is computed so that one chunk is about 1/50s. */
- fmt->chunksize = (ci->id3->frequency * fmt->channels / 50) * fmt->blockalign;
+ /* chunksize = about 1/50[sec] data */
+ fmt->chunksize = (ci->id3->frequency / (50 * fmt->samplesperblock))
+ * fmt->blockalign;
return true;
}
-static uint32_t get_seek_pos(long seek_time)
+static struct pcm_pos *get_seek_pos(long seek_time,
+ uint8_t *(*read_buffer)(size_t *realsize))
{
- uint32_t newpos;
-
- newpos = ((uint64_t)(seek_time * ci->id3->frequency * fmt->channels / 1000LL))*fmt->blockalign;
- return newpos;
+ static struct pcm_pos newpos;
+ uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency)
+ / (1000LL * fmt->samplesperblock);
+
+ (void)read_buffer;
+ newpos.pos = newblock * fmt->blockalign;
+ newpos.samples = newblock * fmt->samplesperblock;
+ return &newpos;
}
static int decode(const uint8_t *inbuf, size_t inbufsize,
diff --git a/apps/codecs/libpcm/ima_adpcm_common.c b/apps/codecs/libpcm/ima_adpcm_common.c
new file mode 100644
index 0000000000..ff5051f166
--- /dev/null
+++ b/apps/codecs/libpcm/ima_adpcm_common.c
@@ -0,0 +1,171 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Yoshihisa Uchida
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "codeclib.h"
+#include "pcm_common.h"
+#include "ima_adpcm_common.h"
+
+/*
+ * Functions for IMA ADPCM and IMA ADPCM series format
+ *
+ * References
+ * [1] The IMA Digital Audio Focus and Technical Working Groups,
+ * Recommended Practices for Enhancing Digital Audio Compatibility
+ * in Multimedia Systems Revision 3.00, 1992
+ * [2] Microsoft Corporation, New Multimedia Data Types and Data Techniques,
+ * Revision:3.0, 1994
+ * [3] ffmpeg source code, libavcodec/adpcm.c
+ */
+
+/* step table */
+static const uint16_t step_table[89] ICONST_ATTR = {
+ 7, 8, 9, 10, 11, 12, 13, 14,
+ 16, 17, 19, 21, 23, 25, 28, 31,
+ 34, 37, 41, 45, 50, 55, 60, 66,
+ 73, 80, 88, 97, 107, 118, 130, 143,
+ 157, 173, 190, 209, 230, 253, 279, 307,
+ 337, 371, 408, 449, 494, 544, 598, 658,
+ 724, 796, 876, 963, 1060, 1166, 1282, 1411,
+ 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024,
+ 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484,
+ 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
+ 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
+ 32767
+};
+
+/* step index tables */
+static const int index_tables[4][16] ICONST_ATTR = {
+ /* adpcm data size is 2 */
+ { -1, 2 },
+ /* adpcm data size is 3 */
+ { -1, -1, 1, 2 },
+ /* adpcm data size is 4 */
+ { -1, -1, -1, -1, 2, 4, 6, 8 },
+ /* adpcm data size is 5 */
+ { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 },
+};
+
+static int32_t pcmdata[2];
+static int8_t index[2];
+
+static int adpcm_data_size;
+static uint8_t step_mask;
+static uint8_t step_sign_mask;
+static int8_t step_shift;
+static const int *use_index_table;
+
+/*
+ * Before first decoding, this function must be executed.
+ *
+ * params
+ * bit: adpcm data size (2 <= bit <= 5).
+ * index_table: step index table
+ * if index_table is null, then step index table
+ * is used index_tables[bit-2].
+ */
+void init_ima_adpcm_decoder(int bit, const int *index_table)
+{
+ adpcm_data_size = bit;
+ step_sign_mask = 1 << (adpcm_data_size - 1);
+ step_mask = step_sign_mask - 1;
+ step_shift = adpcm_data_size - 2;
+ if (index_table)
+ use_index_table = index_table;
+ else
+ use_index_table = index_tables[adpcm_data_size - 2];
+}
+
+/*
+ * When starting decoding for each block, this function must be executed.
+ *
+ * params
+ * channels: channel count
+ * init_pcmdata: array of init pcmdata
+ * init_index: array of init step indexes
+ */
+void set_decode_parameters(int channels, int32_t *init_pcmdata, int8_t *init_index)
+{
+ int ch;
+
+ for (ch = 0; ch < channels; ch++)
+ {
+ pcmdata[ch] = init_pcmdata[ch];
+ index[ch] = init_index[ch];
+ }
+}
+
+/*
+ * convert ADPCM to PCM for any adpcm data size.
+ *
+ * If adpcm_data_size is 4, then you use create_pcmdata_size4()
+ * in place of this functon.
+ */
+int16_t create_pcmdata(int ch, uint8_t nibble)
+{
+ int check_bit = 1 << step_shift;
+ int32_t delta = 0;
+ int16_t step = step_table[index[ch]];
+
+ do {
+ if (nibble & check_bit)
+ delta += step;
+ step >>= 1;
+ check_bit >>= 1;
+ } while (check_bit);
+ delta += step;
+
+ if (nibble & step_sign_mask)
+ pcmdata[ch] -= delta;
+ else
+ pcmdata[ch] += delta;
+
+ index[ch] += use_index_table[nibble & step_mask];
+ CLIP(index[ch], 0, 88);
+
+ CLIP(pcmdata[ch], -32768, 32767);
+
+ return (int16_t)pcmdata[ch];
+}
+
+/*
+ * convert ADPCM to PCM when adpcm data size is 4.
+ */
+int16_t create_pcmdata_size4(int ch, uint8_t nibble)
+{
+ int32_t delta;
+ int16_t step = step_table[index[ch]];
+
+ delta = (step >> 3);
+ if (nibble & 4) delta += step;
+ if (nibble & 2) delta += (step >> 1);
+ if (nibble & 1) delta += (step >> 2);
+
+ if (nibble & 0x08)
+ pcmdata[ch] -= delta;
+ else
+ pcmdata[ch] += delta;
+
+ index[ch] += use_index_table[nibble & 0x07];
+ CLIP(index[ch], 0, 88);
+
+ CLIP(pcmdata[ch], -32768, 32767);
+
+ return (int16_t)pcmdata[ch];
+}
diff --git a/apps/codecs/libpcm/ima_adpcm_common.h b/apps/codecs/libpcm/ima_adpcm_common.h
new file mode 100644
index 0000000000..65cfefcfa3
--- /dev/null
+++ b/apps/codecs/libpcm/ima_adpcm_common.h
@@ -0,0 +1,32 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Yoshihisa Uchida
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef CODEC_LIBPCM_IMA_ADPCM_COMMON_H
+#define CODEC_LIBPCM_IMA_ADPCM_COMMON_H
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+void init_ima_adpcm_decoder(int bit, const int *index_table);
+void set_decode_parameters(int channels, int32_t *init_pcmdata, int8_t *init_index);
+int16_t create_pcmdata(int ch, uint8_t nibble);
+int16_t create_pcmdata_size4(int ch, uint8_t nibble);
+#endif
diff --git a/apps/codecs/libpcm/itut_g711.c b/apps/codecs/libpcm/itut_g711.c
index 520ca46a7a..9a38031882 100644
--- a/apps/codecs/libpcm/itut_g711.c
+++ b/apps/codecs/libpcm/itut_g711.c
@@ -109,49 +109,43 @@ static const int16_t ulaw2linear16[256] ICONST_ATTR = {
static struct pcm_format *fmt;
-static bool set_format(struct pcm_format *format, const unsigned char *fmtpos)
+static bool set_format(struct pcm_format *format)
{
fmt = format;
- (void)fmtpos;
-
if (fmt->bitspersample != 8)
{
- DEBUGF("CODEC_ERROR: alaw and mulaw must have 8 bitspersample\n");
+ DEBUGF("CODEC_ERROR: alaw and mulaw must have 8 bitspersample: %d\n",
+ fmt->bitspersample);
return false;
}
if (fmt->totalsamples == 0)
{
- fmt->bytespersample = fmt->channels;
- fmt->totalsamples = fmt->numbytes/fmt->bytespersample;
+ fmt->bytespersample = 1;
+ fmt->totalsamples = fmt->numbytes / (fmt->bytespersample * fmt->channels);
}
- /* chunksize is computed so that one chunk is about 1/50s.
- * this make 4096 for 44.1kHz 16bits stereo.
- * It also has to be a multiple of blockalign */
- fmt->chunksize = (1 + fmt->avgbytespersec / (50*fmt->blockalign))*fmt->blockalign;
+ fmt->samplesperblock = fmt->blockalign / (fmt->bytespersample * fmt->channels);
- /* check that the output buffer is big enough (convert to samplespersec,
- then round to the blockalign multiple below) */
- if ((((uint64_t)fmt->chunksize * ci->id3->frequency * fmt->channels * fmt->bitspersample)>>3)
- /(uint64_t)fmt->avgbytespersec >= PCM_CHUNK_SIZE)
- fmt->chunksize = ((uint64_t)PCM_CHUNK_SIZE * fmt->avgbytespersec
- /((uint64_t)ci->id3->frequency * fmt->channels * 2
- * fmt->blockalign)) * fmt->blockalign;
+ /* chunksize = about 1/50[sec] data */
+ fmt->chunksize = (ci->id3->frequency / (50 * fmt->samplesperblock))
+ * fmt->blockalign;
return true;
}
-static uint32_t get_seek_pos(long seek_time)
+static struct pcm_pos *get_seek_pos(long seek_time,
+ uint8_t *(*read_buffer)(size_t *realsize))
{
- uint32_t newpos;
-
- /* use avgbytespersec to round to the closest blockalign multiple,
- add firstblockposn. 64-bit casts to avoid overflows. */
- newpos = (((uint64_t)fmt->avgbytespersec*(seek_time - 1))
- / (1000LL*fmt->blockalign))*fmt->blockalign;
- return newpos;
+ static struct pcm_pos newpos;
+ uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency)
+ / (1000LL * fmt->samplesperblock);
+
+ (void)read_buffer;
+ newpos.pos = newblock * fmt->blockalign;
+ newpos.samples = newblock * fmt->samplesperblock;
+ return &newpos;
}
static int decode_alaw(const uint8_t *inbuf, size_t inbufsize,
diff --git a/apps/codecs/libpcm/linear_pcm.c b/apps/codecs/libpcm/linear_pcm.c
index 4db27ca2b3..5360d79901 100644
--- a/apps/codecs/libpcm/linear_pcm.c
+++ b/apps/codecs/libpcm/linear_pcm.c
@@ -29,12 +29,10 @@
static struct pcm_format *fmt;
-static bool set_format(struct pcm_format *format, const unsigned char *fmtpos)
+static bool set_format(struct pcm_format *format)
{
fmt = format;
- (void)fmtpos;
-
if (fmt->bitspersample > 32)
{
DEBUGF("CODEC_ERROR: pcm with more than 32 bitspersample "
@@ -42,33 +40,34 @@ static bool set_format(struct pcm_format *format, const unsigned char *fmtpos)
return false;
}
+ fmt->bytespersample = fmt->bitspersample >> 3;
+
if (fmt->totalsamples == 0)
- {
- fmt->bytespersample = (((fmt->bitspersample - 1)/8 + 1)*fmt->channels);
fmt->totalsamples = fmt->numbytes/fmt->bytespersample;
- }
- /* chunksize is computed so that one chunk is about 1/50s.
- * this make 4096 for 44.1kHz 16bits stereo.
- * It also has to be a multiple of blockalign */
- fmt->chunksize = (1 + fmt->avgbytespersec / (50*fmt->blockalign))*fmt->blockalign;
+ fmt->samplesperblock = fmt->blockalign / (fmt->bytespersample * fmt->channels);
+
+ /* chunksize = about 1/50[sec] data */
+ fmt->chunksize = (ci->id3->frequency / (50 * fmt->samplesperblock))
+ * fmt->blockalign;
return true;
}
-static uint32_t get_seek_pos(long seek_time)
+static struct pcm_pos *get_seek_pos(long seek_time,
+ uint8_t *(*read_buffer)(size_t *realsize))
{
- uint32_t newpos;
-
- /* use avgbytespersec to round to the closest blockalign multiple,
- add firstblockposn. 64-bit casts to avoid overflows. */
- newpos = (((uint64_t)fmt->avgbytespersec*(seek_time - 1))
- / (1000LL*fmt->blockalign))*fmt->blockalign;
- return newpos;
+ static struct pcm_pos newpos;
+ uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency)
+ / (1000LL * fmt->samplesperblock);
+
+ (void)read_buffer;
+ newpos.pos = newblock * fmt->blockalign;
+ newpos.samples = newblock * fmt->samplesperblock;
+ return &newpos;
}
-static int decode(const uint8_t *inbuf, size_t inbufsize,
- int32_t *outbuf, int *outbufsize)
+static int decode(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf, int *outbufsize)
{
uint32_t i;
diff --git a/apps/codecs/libpcm/ms_adpcm.c b/apps/codecs/libpcm/ms_adpcm.c
new file mode 100644
index 0000000000..899ecc2045
--- /dev/null
+++ b/apps/codecs/libpcm/ms_adpcm.c
@@ -0,0 +1,166 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Yoshihisa Uchida
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "codeclib.h"
+#include "pcm_common.h"
+
+/*
+ * Microsoft ADPCM
+ *
+ * References
+ * [1] Microsoft, New Multimedia Data Types and Data Techniques Revision 3.0, 1994
+ * [2] MulitimediaWiki, Microsoft ADPCM, 2006
+ * (http://wiki.multimedia.cx/index.php?title=Microsoft_ADPCM)
+ * [3] ffmpeg source code, libavcodec/adpcm.c
+ */
+
+#define ADPCM_NUM_COEFF 7
+
+static int16_t dec_coeff[2][2];
+static uint16_t delta[2];
+static int16_t sample[2][2];
+
+static struct pcm_format *fmt;
+
+static const int16_t adaptation_table[] ICONST_ATTR = {
+ 230, 230, 230, 230, 307, 409, 512, 614,
+ 768, 614, 512, 409, 307, 230, 230, 230
+};
+
+static bool set_format(struct pcm_format *format)
+{
+ fmt = format;
+
+ if (fmt->bitspersample != 4)
+ {
+ DEBUGF("CODEC_ERROR: microsoft adpcm must be 4 bitspersample: %d\n",
+ fmt->bitspersample);
+ return false;
+ }
+
+ fmt->chunksize = fmt->blockalign;
+
+ return true;
+}
+
+static struct pcm_pos *get_seek_pos(long seek_time,
+ uint8_t *(*read_buffer)(size_t *realsize))
+{
+ static struct pcm_pos newpos;
+ uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency)
+ / (1000LL * fmt->samplesperblock);
+
+ (void)read_buffer;
+ newpos.pos = newblock * fmt->blockalign;
+ newpos.samples = newblock * fmt->samplesperblock;
+ return &newpos;
+}
+
+static int16_t create_pcmdata(int ch, uint8_t nibble)
+{
+ int32_t pcmdata;
+
+ pcmdata = (sample[ch][0] * dec_coeff[ch][0] +
+ sample[ch][1] * dec_coeff[ch][1]) / 256;
+ pcmdata += (delta[ch] * (nibble - ((nibble & 0x8) << 1)));
+
+ CLIP(pcmdata, -32768, 32767);
+
+ sample[ch][1] = sample[ch][0];
+ sample[ch][0] = pcmdata;
+
+ delta[ch] = (adaptation_table[nibble] * delta[ch]) >> 8;
+ if (delta[ch] < 16)
+ delta[ch] = 16;
+
+ return (int16_t)pcmdata;
+}
+
+static int decode(const uint8_t *inbuf, size_t inbufsize,
+ int32_t *outbuf, int *outbufcount)
+{
+ int ch;
+ size_t nsamples = 0;
+ int size = fmt->samplesperblock;
+
+ /* read block header */
+ for (ch = 0; ch < fmt->channels; ch++)
+ {
+ if (*inbuf >= ADPCM_NUM_COEFF)
+ {
+ DEBUGF("CODEC_ERROR: microsoft adpcm illegal initial coeff=%d > 7\n",
+ *inbuf);
+ return CODEC_ERROR;
+ }
+ dec_coeff[ch][0] = fmt->coeffs[*inbuf][0];
+ dec_coeff[ch][1] = fmt->coeffs[*inbuf][1];
+ inbuf++;
+ }
+
+ for (ch = 0; ch < fmt->channels; ch++)
+ {
+ delta[ch] = inbuf[0] | (SE(inbuf[1]) << 8);
+ inbuf += 2;
+ }
+
+ for (ch = 0; ch < fmt->channels; ch++)
+ {
+ sample[ch][0] = inbuf[0] | (SE(inbuf[1]) << 8);
+ inbuf += 2;
+ }
+
+ for (ch = 0; ch < fmt->channels; ch++)
+ {
+ sample[ch][1] = inbuf[0] | (SE(inbuf[1]) << 8);
+ inbuf += 2;
+ }
+
+ inbufsize -= 7 * fmt->channels;
+ ch = fmt->channels - 1;
+
+ while (size-- > 0)
+ {
+ *outbuf++ = create_pcmdata(0, *inbuf >> 4 ) << 13;
+ *outbuf++ = create_pcmdata(ch, *inbuf & 0xf) << 13;
+ nsamples += 2;
+
+ inbuf++;
+ inbufsize--;
+ if (inbufsize <= 0)
+ break;
+ }
+
+ if (fmt->channels == 2)
+ nsamples >>= 1;
+ *outbufcount = nsamples;
+
+ return CODEC_OK;
+}
+
+static const struct pcm_codec codec = {
+ set_format,
+ get_seek_pos,
+ decode,
+ };
+
+const struct pcm_codec *get_ms_adpcm_codec(void)
+{
+ return &codec;
+}
diff --git a/apps/codecs/libpcm/pcm_common.h b/apps/codecs/libpcm/pcm_common.h
index 757d0ad5d9..d490a85e9f 100644
--- a/apps/codecs/libpcm/pcm_common.h
+++ b/apps/codecs/libpcm/pcm_common.h
@@ -18,8 +18,8 @@
* KIND, either express or implied.
*
****************************************************************************/
-#ifndef CODEC_LIBPCMS_PCM_COMMON_H
-#define CODEC_LIBPCMS_PCM_COMMON_H
+#ifndef CODEC_LIBPCM_PCM_COMMON_H
+#define CODEC_LIBPCM_PCM_COMMON_H
#include <sys/types.h>
#include <stdbool.h>
@@ -38,6 +38,19 @@
/* Macro that shift to -0x80. (0 .. 127 to -128 .. -1, 128 .. 255 to 0 .. 127) */
#define SFT(x) ((int32_t)x-0x80)
+/* Macro that clipping data */
+#define CLIP(data, min, max) \
+if ((data) > (max)) data = max; \
+else if ((data) < (min)) data = min;
+
+/* nums of msadpcm coeffs
+ * 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.
+ */
+#define MSADPCM_NUM_COEFF 7
+
struct pcm_format {
/*
* RIFF: wFormatTag (in 'fmt ' chunk)
@@ -103,13 +116,67 @@ struct pcm_format {
* true: signed, false: unsigned
*/
bool is_signed;
+
+ /* the following values are format speciffic parameters */
+
+ /* microsoft adpcm: aCoeff */
+ int16_t coeffs[MSADPCM_NUM_COEFF][2];
+};
+
+struct pcm_pos {
+ uint32_t pos;
+ uint32_t samples;
};
struct pcm_codec {
- bool (*set_format)(struct pcm_format *format, const unsigned char *fmtpos);
- uint32_t (*get_seek_pos)(long seek_time);
+ /*
+ * sets the format speciffic RIFF/AIFF header information and checks the pcm_format.
+ *
+ * [In/Out] format
+ * the structure which supplies RIFF/AIFF header information.
+ *
+ * return
+ * true: RIFF/AIFF header check OK
+ * false: RIFF/AIFF header check NG
+ */
+ bool (*set_format)(struct pcm_format *format);
+
+ /*
+ * get seek position
+ *
+ * [In] seek_time
+ * seek time [ms]
+ *
+ * [In] read_buffer
+ * the function which reads the data from the file (chunksize bytes read).
+ *
+ * return
+ * position after the seeking.
+ */
+ struct pcm_pos *(*get_seek_pos)(long seek_time,
+ uint8_t *(*read_buffer)(size_t *realsize));
+
+ /*
+ * decode wave data.
+ *
+ * [In] inbuf
+ * the start pointer of wave data buffer.
+ *
+ * [In] inbufsize
+ * wave data buffer size (bytes).
+ *
+ * [Out] outbuf
+ * the start pointer of the buffer which supplies decoded pcm data.
+ *
+ * [Out] outbufcount
+ * decoded pcm data count.
+ *
+ * return
+ * CODEC_OK: decode succeed.
+ * CODEC_ERROR: decode failure.
+ */
int (*decode)(const uint8_t *inbuf, size_t inbufsize,
- int32_t *outbuf, int *outbufsize);
+ int32_t *outbuf, int *outbufcount);
};
struct pcm_entry {
diff --git a/apps/codecs/libpcm/qt_ima_adpcm.c b/apps/codecs/libpcm/qt_ima_adpcm.c
new file mode 100644
index 0000000000..a34e0e86cd
--- /dev/null
+++ b/apps/codecs/libpcm/qt_ima_adpcm.c
@@ -0,0 +1,136 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Yoshihisa Uchida
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "codeclib.h"
+#include "pcm_common.h"
+#include "ima_adpcm_common.h"
+
+/*
+ * Apple QuickTime IMA ADPCM
+ *
+ * References
+ * [1] Multimedia Wiki, Apple QuickTime IMA ADPCM
+ * URL:http://wiki.multimedia.cx/index.php?title=Apple_QuickTime_IMA_ADPCM
+ * [2] Apple Inc., Technical Note TN1081 Understanding the Differences Between
+ * Apple and Windows IMA-ADPCM Compressed Sound Files, 1996
+ * [3] ffmpeg source code, libavcodec/adpcm.c
+ */
+
+static struct pcm_format *fmt;
+
+static bool set_format(struct pcm_format *format)
+{
+ fmt = format;
+
+ if (fmt->bitspersample != 4)
+ {
+ DEBUGF("CODEC_ERROR: quicktime ima adpcm must be 4 bitspersample: %d\n",
+ fmt->bitspersample);
+ return false;
+ }
+
+ fmt->blockalign = 34 * fmt->channels;
+ fmt->samplesperblock = 64;
+
+ /* chunksize = about 1/50[s] data */
+ fmt->chunksize = (ci->id3->frequency / (50 * fmt->samplesperblock))
+ * fmt->blockalign;
+
+ init_ima_adpcm_decoder(4, NULL);
+ return true;
+}
+
+static struct pcm_pos *get_seek_pos(long seek_time,
+ uint8_t *(*read_buffer)(size_t *realsize))
+{
+ static struct pcm_pos newpos;
+ uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency)
+ / (1000LL * fmt->samplesperblock);
+
+ (void)read_buffer;
+ newpos.pos = newblock * fmt->blockalign;
+ newpos.samples = newblock * fmt->samplesperblock;
+ return &newpos;
+}
+
+static int decode(const uint8_t *inbuf, size_t inbufsize,
+ int32_t *outbuf, int *outbufcount)
+{
+ int ch;
+ size_t nsamples = 0;
+ int block_size;
+ int32_t *pcmbuf;
+ int32_t init_pcmdata;
+ int8_t init_index;
+
+ while (inbufsize > 0)
+ {
+ for (ch = 0; ch < fmt->channels; ch++)
+ {
+ /* read block header */
+ init_pcmdata = (inbuf[0] << 8)|(inbuf[1] & 0x80);
+ if (init_pcmdata > 32767)
+ init_pcmdata -= 65536;
+
+ init_index = inbuf[1] & 0x7f;
+ if (init_index > 88)
+ {
+ DEBUGF("CODEC_ERROR: quicktime ima adpcm illegal step index=%d > 88\n",
+ init_index);
+ return CODEC_ERROR;
+ }
+
+ inbuf += 2;
+ inbufsize -= 2;
+
+ set_decode_parameters(1, &init_pcmdata, &init_index);
+
+ /* read block data */
+ pcmbuf = outbuf + ch;
+ for (block_size = 32; block_size > 0 && inbufsize > 0; block_size--, inbufsize--)
+ {
+ *pcmbuf = create_pcmdata_size4(ch, *inbuf ) << 13;
+ pcmbuf += fmt->channels;
+ *pcmbuf = create_pcmdata_size4(ch, *inbuf >> 4) << 13;
+ pcmbuf += fmt->channels;
+ nsamples += 2;
+ inbuf++;
+ }
+ }
+ outbuf += 64 * fmt->channels;
+ }
+
+ if (fmt->channels == 2)
+ nsamples >>= 1;
+ *outbufcount = nsamples;
+
+ return CODEC_OK;
+}
+
+static const struct pcm_codec codec = {
+ set_format,
+ get_seek_pos,
+ decode,
+ };
+
+const struct pcm_codec *get_qt_ima_adpcm_codec(void)
+{
+ return &codec;
+}
diff --git a/apps/codecs/libpcm/support_formats.h b/apps/codecs/libpcm/support_formats.h
index 0a6ea339f4..b1e089e464 100644
--- a/apps/codecs/libpcm/support_formats.h
+++ b/apps/codecs/libpcm/support_formats.h
@@ -18,8 +18,8 @@
* KIND, either express or implied.
*
****************************************************************************/
-#ifndef CODEC_LIBPCMS_SUPPORT_FORMATS_H
-#define CODEC_LIBPCMS_SUPPORT_FORMATS_H
+#ifndef CODEC_LIBPCM_SUPPORT_FORMATS_H
+#define CODEC_LIBPCM_SUPPORT_FORMATS_H
#include "pcm_common.h"
@@ -32,9 +32,24 @@ const struct pcm_codec *get_itut_g711_alaw_codec(void);
/* ITU-T G.711 mu-law */
const struct pcm_codec *get_itut_g711_mulaw_codec(void);
-/* Intel DVI ADPCM */
+/* Intel DVI ADPCM (IMA ADPCM) */
const struct pcm_codec *get_dvi_adpcm_codec(void);
/* IEEE float */
const struct pcm_codec *get_ieee_float_codec(void);
+
+/* Microsoft ADPCM */
+const struct pcm_codec *get_ms_adpcm_codec(void);
+
+/* Dialogic OKI ADPCM */
+const struct pcm_codec *get_dialogic_oki_adpcm_codec(void);
+
+/* YAMAHA ADPCM */
+const struct pcm_codec *get_yamaha_adpcm_codec(void);
+
+/* Apple QuickTime IMA ADPCM */
+const struct pcm_codec *get_qt_ima_adpcm_codec(void);
+
+/* Adobe SWF ADPCM */
+const struct pcm_codec *get_swf_adpcm_codec(void);
#endif
diff --git a/apps/codecs/libpcm/swf_adpcm.c b/apps/codecs/libpcm/swf_adpcm.c
new file mode 100644
index 0000000000..456e1cdd4c
--- /dev/null
+++ b/apps/codecs/libpcm/swf_adpcm.c
@@ -0,0 +1,233 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Yoshihisa Uchida
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "codeclib.h"
+#include "pcm_common.h"
+#include "ima_adpcm_common.h"
+
+/*
+ * Adobe SWF ADPCM
+ *
+ * References
+ * [1] Adobe, SWF File Format Specification Version 10, 2008
+ * [2] Jack Jansen, adpcm.c in adpcm.zip
+ * [3] ffmpeg source code, libavcodec/adpcm.c
+ */
+
+/* step index table when bitspersample is 3.
+ * (when bitspersample is 2, 4, 5, step index table uses the table
+ * which is defined ima_adpcm_common.c.)
+ */
+static const int index_table[4] ICONST_ATTR = {
+ -1, -1, 2, 4,
+};
+
+static int validity_bits = 8;
+static bool first_block = true;
+static int blockbits = 0;
+static int lastbytebits = 0;
+static bool after_seek = false;
+
+static struct pcm_format *fmt;
+
+static bool set_format(struct pcm_format *format)
+{
+ fmt = format;
+
+ if (fmt->bitspersample < 2 || fmt->bitspersample > 5)
+ {
+ DEBUGF("CODEC_ERROR: swf adpcm must be 2, 3, 4 or 5 bitspersample: %d\n",
+ fmt->bitspersample);
+ return false;
+ }
+
+ if (fmt->samplesperblock == 0)
+ fmt->samplesperblock = (((fmt->blockalign << 3) - 2) / fmt->channels - 22)
+ / fmt->bitspersample + 1;
+
+ blockbits = ((fmt->samplesperblock - 1) * fmt->bitspersample + 22) * fmt->channels;
+
+ /*
+ * chunksize = about 93 [ms] data (frequency:44.1kHz, 4096 [sample/block])
+ * chunksize changes depending upon the position of block.
+ */
+ fmt->chunksize = (blockbits + 9) >> 3;
+
+ /* initialize for ima adpcm common functions */
+ if (fmt->bitspersample == 3)
+ init_ima_adpcm_decoder(fmt->bitspersample, index_table);
+ else
+ init_ima_adpcm_decoder(fmt->bitspersample, NULL);
+
+ return true;
+}
+
+static struct pcm_pos *get_seek_pos(long seek_time,
+ uint8_t *(*read_buffer)(size_t *realsize))
+{
+ static struct pcm_pos newpos;
+ uint32_t chunkbits = blockbits;
+ uint32_t seekbits = (((uint64_t)seek_time * ci->id3->frequency)
+ / (1000LL * fmt->samplesperblock)) * blockbits + 2;
+
+ (void)read_buffer;
+
+ newpos.pos = seekbits >> 3;
+ newpos.samples = (((uint64_t)seek_time * ci->id3->frequency)
+ / (1000LL * fmt->samplesperblock))
+ * fmt->samplesperblock;
+
+ if (newpos.pos == 0)
+ {
+ first_block = true;
+ lastbytebits = 0;
+ }
+ else
+ {
+ first_block = false;
+ lastbytebits = seekbits & 0x07;
+ if (lastbytebits != 0)
+ chunkbits -= (8 - lastbytebits);
+ }
+
+ /* calculates next read bytes */
+ fmt->chunksize = (chunkbits >> 3) + (((chunkbits & 0x07) > 0)?1:0)
+ + ((lastbytebits > 0)?1:0);
+
+ after_seek = true;
+ return &newpos;
+}
+
+static uint8_t get_data(const uint8_t **buf, int bit)
+{
+ uint8_t res = 0;
+ uint8_t mask = (1 << bit) - 1;
+
+ if (validity_bits >= bit)
+ {
+ validity_bits -= bit;
+ return (**buf >> validity_bits) & mask;
+ }
+
+ if (validity_bits > 0)
+ res = **buf << (bit - validity_bits);
+
+ validity_bits += 8 - bit;
+ res = (res | (*(++(*buf)) >> validity_bits)) & mask;
+ return res;
+}
+
+static int decode(const uint8_t *inbuf, size_t inbufsize,
+ int32_t *outbuf, int *outbufcount)
+{
+ int ch;
+ int adpcm_code_size;
+ int count = fmt->samplesperblock;
+ int32_t init_pcmdata[2];
+ int8_t init_index[2];
+ static uint8_t lastbyte = 0;
+
+ (void)inbufsize;
+
+ validity_bits = 8;
+
+ /* read block header */
+ ch = fmt->channels - 1;
+ if (first_block)
+ {
+ adpcm_code_size = get_data(&inbuf, 2) + 2;
+ if (fmt->bitspersample != adpcm_code_size)
+ {
+ DEBUGF("CODEC_ERROR: swf adpcm different adpcm code size=%d != %d\n",
+ adpcm_code_size, fmt->bitspersample);
+ return CODEC_ERROR;
+ }
+ init_pcmdata[0] = (get_data(&inbuf, 8) << 8) | get_data(&inbuf, 8);
+
+ lastbytebits = 0;
+ first_block = false;
+ }
+ else
+ {
+ if (after_seek && lastbytebits > 0)
+ {
+ lastbyte = *inbuf++;
+ after_seek = false;
+ }
+ if (lastbytebits > 0)
+ init_pcmdata[0] = ((lastbyte << (8 + lastbytebits)) |
+ (get_data(&inbuf, 8) << lastbytebits) |
+ get_data(&inbuf, lastbytebits)) & 65535;
+ else
+ init_pcmdata[0] = (get_data(&inbuf, 8) << 8) | get_data(&inbuf, 8);
+ }
+ after_seek = false;
+
+ init_index[0] = get_data(&inbuf, 6);
+ if (init_pcmdata[0] > 32767)
+ init_pcmdata[0] -= 65536;
+
+ if (ch > 0)
+ {
+ init_pcmdata[1] = (get_data(&inbuf, 8) << 8) | get_data(&inbuf, 8);
+ init_index[1] = get_data(&inbuf, 6);
+ if (init_pcmdata[1] > 32767)
+ init_pcmdata[1] -= 65536;
+ }
+
+ *outbuf++ = init_pcmdata[0] << 13;
+ if (ch > 0)
+ *outbuf++ = init_pcmdata[1] << 13;
+
+ set_decode_parameters(fmt->channels, init_pcmdata, init_index);
+
+ /* read block data */
+ while (--count > 0)
+ {
+ *outbuf++ = create_pcmdata(0, get_data(&inbuf, fmt->bitspersample)) << 13;
+ if (ch > 0)
+ *outbuf++ = create_pcmdata(ch, get_data(&inbuf, fmt->bitspersample)) << 13;
+ }
+
+ *outbufcount = fmt->samplesperblock;
+
+ lastbyte = *inbuf;
+ lastbytebits = (8 - validity_bits) & 0x07;
+
+ /* calculates next read bytes */
+ fmt->chunksize = (blockbits - validity_bits + 7) >> 3;
+
+ return CODEC_OK;
+}
+
+static const struct pcm_codec codec = {
+ set_format,
+ get_seek_pos,
+ decode,
+ };
+
+const struct pcm_codec *get_swf_adpcm_codec(void)
+{
+ first_block = true;
+ lastbytebits = 0;
+ after_seek = false;
+
+ return &codec;
+}
diff --git a/apps/codecs/libpcm/yamaha_adpcm.c b/apps/codecs/libpcm/yamaha_adpcm.c
new file mode 100644
index 0000000000..6b3daa8f83
--- /dev/null
+++ b/apps/codecs/libpcm/yamaha_adpcm.c
@@ -0,0 +1,245 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Yoshihisa Uchida
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "codeclib.h"
+#include "pcm_common.h"
+#include "adpcm_seek.h"
+
+/*
+ * YAMAHA ADPCM
+ *
+ * References
+ * [1] YAMAHA, YAMAHA ADPCM ACM Driver Version 1.0.0.0, 2005
+ * [2] BlendWorks, YM2608 ADPCM,
+ * http://web.archive.org/web/20050208190547/www.memb.jp/~dearna/ma/ym2608/adpcm.html
+ * [3] Naoyuki Sawa, ADPCM no shikumi #1,
+ * http://www.piece-me.org/piece-lab/adpcm/adpcm1.html
+ * [4] ffmpeg source code, libavcodec/adpcm.c
+ */
+
+/* ADPCM data block layout
+ *
+ * when the block header exists. (for example, encoding by YAMAHA ADPCM ACM Driver)
+ * blockAlign = (frequency / 60 + 4) * channels.
+ *
+ * block
+ * <Mono> (channels = 1)
+ * int16_t first value (Little endian)
+ * uint16_t first predictor (Little endian)
+ * uint8_t ADPCM data (1st data: 0-3 bit, 2nd data: 4-7 bit)
+ * ....
+ *
+ * <Stereo> (channels = 2)
+ * int16_t Left channel first value (Little endian)
+ * uint16_t Left channel first predictor (Little endian)
+ * int16_t Right channel first value (Little endian)
+ * uint16_t Right channel first predictor (Little endian)
+ * uint8_t ADPCM data (Left channel: 0-3 bit, Right channel: 4-7 bit)
+ * ....
+ *
+ * when the block header does not exist. (for example, encoding by ffmpeg)
+ * blockAlign = 8000
+ *
+ * block
+ * <Mono> (channels = 1)
+ * uint8_t ADPCM data (1st data: 0-3 bit, 2nd data: 4-7 bit)
+ * ....
+ *
+ * <Stereo> (channels = 2)
+ * uint8_t ADPCM data (Left channel: 0-3 bit, Right channel: 4-7 bit)
+ * ....
+ */
+
+static const int32_t amplification_table[] ICONST_ATTR = {
+ 230, 230, 230, 230, 307, 409, 512, 614, 230, 230, 230, 230, 307, 409, 512, 614
+};
+
+static bool has_block_header = false;
+
+static struct adpcm_data cur_data;
+static int blocksperchunk;
+
+static struct pcm_format *fmt;
+
+static bool set_format(struct pcm_format *format)
+{
+ fmt = format;
+
+ if (fmt->bitspersample != 4)
+ {
+ DEBUGF("CODEC_ERROR: yamaha adpcm must be 4 bitspersample: %d\n",
+ fmt->bitspersample);
+ return false;
+ }
+
+ /* check exists block header */
+ if (fmt->blockalign == ((ci->id3->frequency / 60) + 4) * fmt->channels)
+ {
+ has_block_header = true;
+
+ /* chunksize = about 1/30 [sec] data */
+ fmt->chunksize = fmt->blockalign;
+ blocksperchunk = 1;
+ }
+ else
+ {
+ uint32_t max_chunk_count;
+
+ has_block_header = false;
+
+ /* blockalign = 2 * channels samples */
+ fmt->blockalign = fmt->channels;
+ fmt->samplesperblock = 2;
+
+ /* chunksize = about 1/32[sec] data */
+ blocksperchunk = ci->id3->frequency >> 6;
+ fmt->chunksize = blocksperchunk * fmt->blockalign;
+
+ max_chunk_count = (uint64_t)ci->id3->length * ci->id3->frequency
+ / (2000LL * fmt->chunksize / fmt->channels);
+
+ /* initialize seek table */
+ init_seek_table(max_chunk_count);
+ /* add first data */
+ add_adpcm_data(&cur_data);
+ }
+
+ return true;
+}
+
+static int16_t create_pcmdata(int ch, uint8_t nibble)
+{
+ int32_t tmp_pcmdata = cur_data.pcmdata[ch];
+ int32_t step = cur_data.step[ch];
+ int32_t delta = step >> 3;
+
+ if (nibble & 4) delta += step;
+ if (nibble & 2) delta += (step >> 1);
+ if (nibble & 1) delta += (step >> 2);
+
+ if (nibble & 0x08)
+ tmp_pcmdata -= delta;
+ else
+ tmp_pcmdata += delta;
+
+ CLIP(tmp_pcmdata, -32768, 32767);
+ cur_data.pcmdata[ch] = tmp_pcmdata;
+
+ step = (step * amplification_table[nibble & 0x07]) >> 8;
+ CLIP(step, 127, 24576);
+ cur_data.step[ch] = step;
+
+ return cur_data.pcmdata[ch];
+}
+
+static int decode(const uint8_t *inbuf, size_t inbufsize,
+ int32_t *outbuf, int *outbufcount)
+{
+ int ch;
+ size_t nsamples = 0;
+
+ /* read block header */
+ if (has_block_header)
+ {
+ for (ch = 0; ch < fmt->channels; ch++)
+ {
+ cur_data.pcmdata[ch] = inbuf[0] | (SE(inbuf[1]) << 8);
+ cur_data.step[ch] = inbuf[2] | (inbuf[3] << 8);
+
+ inbuf += 4;
+ inbufsize -= 4;
+ }
+ }
+
+ /* read block data */
+ ch = fmt->channels - 1;
+ while (inbufsize)
+ {
+ *outbuf++ = create_pcmdata(0, *inbuf ) << 13;
+ *outbuf++ = create_pcmdata(ch, *inbuf >> 4) << 13;
+ nsamples += 2;
+
+ inbuf++;
+ inbufsize--;
+ }
+
+ if (fmt->channels == 2)
+ nsamples >>= 1;
+ *outbufcount = nsamples;
+
+ if (!has_block_header)
+ add_adpcm_data(&cur_data);
+
+ return CODEC_OK;
+}
+
+static int decode_for_seek(const uint8_t *inbuf, size_t inbufsize)
+{
+ int ch = fmt->channels - 1;
+
+ while (inbufsize)
+ {
+ create_pcmdata(0, *inbuf );
+ create_pcmdata(ch, *inbuf >> 4);
+
+ inbuf++;
+ inbufsize--;
+ }
+
+ add_adpcm_data(&cur_data);
+
+ return CODEC_OK;
+}
+
+static struct pcm_pos *get_seek_pos(long seek_time,
+ uint8_t *(*read_buffer)(size_t *realsize))
+{
+ static struct pcm_pos newpos;
+ uint32_t new_count= 0;
+
+ if (seek_time > 0)
+ new_count = ((uint64_t)seek_time * ci->id3->frequency
+ / (1000LL * fmt->samplesperblock)) / blocksperchunk;
+
+ if (!has_block_header)
+ {
+ new_count = seek(new_count, &cur_data, read_buffer, &decode_for_seek);
+ }
+ newpos.pos = new_count * fmt->chunksize;
+ newpos.samples = new_count * blocksperchunk * fmt->samplesperblock;
+ return &newpos;
+}
+
+static struct pcm_codec codec = {
+ set_format,
+ get_seek_pos,
+ decode,
+ };
+
+const struct pcm_codec *get_yamaha_adpcm_codec(void)
+{
+ /* initialize first step, pcm data */
+ cur_data.pcmdata[0] = 0;
+ cur_data.pcmdata[1] = 0;
+ cur_data.step[0] = 127;
+ cur_data.step[1] = 127;
+
+ return &codec;
+}
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;
diff --git a/apps/metadata/aiff.c b/apps/metadata/aiff.c
index 67fb43b8c6..aba327f8c8 100644
--- a/apps/metadata/aiff.c
+++ b/apps/metadata/aiff.c
@@ -29,6 +29,9 @@
#include "metadata_common.h"
#include "metadata_parsers.h"
+/* compressionType: AIFC QuickTime IMA ADPCM */
+#define AIFC_FORMAT_QT_IMA_ADPCM "ima4"
+
bool get_aiff_metadata(int fd, struct mp3entry* id3)
{
/* Use the trackname part of the id3 structure as a temporary buffer */
@@ -40,6 +43,7 @@ bool get_aiff_metadata(int fd, struct mp3entry* id3)
unsigned long numbytes = 0;
int read_bytes;
int i;
+ bool is_aifc = false;
if ((lseek(fd, 0, SEEK_SET) < 0)
|| ((read_bytes = read(fd, buf, sizeof(id3->path))) < 54))
@@ -47,10 +51,15 @@ bool get_aiff_metadata(int fd, struct mp3entry* id3)
return false;
}
- if ((memcmp(buf, "FORM",4) != 0)
- || ((memcmp(&buf[8], "AIFF", 4) !=0) && (memcmp(&buf[8], "AIFC", 4) !=0)))
- {
+ if (memcmp(buf, "FORM",4) != 0)
return false;
+
+ if (memcmp(&buf[8], "AIFF", 4) != 0)
+ {
+ if (memcmp(&buf[8], "AIFC", 4) != 0)
+ return false;
+
+ is_aifc = true;
}
buf += 12;
@@ -75,7 +84,13 @@ bool get_aiff_metadata(int fd, struct mp3entry* id3)
/* save format infos */
id3->bitrate = (sampleSize * numChannels * sampleRate) / 1000;
id3->frequency = sampleRate;
- id3->length = ((int64_t) numSampleFrames * 1000) / id3->frequency;
+ if (!is_aifc || memcmp(&buf[26], AIFC_FORMAT_QT_IMA_ADPCM, 4) != 0)
+ id3->length = ((int64_t) numSampleFrames * 1000) / id3->frequency;
+ else
+ {
+ /* QuickTime IMA ADPCM is 1block = 64 data for each channel */
+ id3->length = (int64_t)(numSampleFrames * 64000LL) / id3->frequency;
+ }
id3->vbr = false; /* AIFF files are CBR */
id3->filesize = filesize(fd);
diff --git a/apps/metadata/wave.c b/apps/metadata/wave.c
index acef32dd38..79bb8178bd 100644
--- a/apps/metadata/wave.c
+++ b/apps/metadata/wave.c
@@ -28,6 +28,7 @@
#include "metadata.h"
#include "metadata_common.h"
#include "metadata_parsers.h"
+#include "logf.h"
# define AV_WL32(p, d) do { \
((uint8_t*)(p))[0] = (d); \
@@ -40,29 +41,101 @@
((uint8_t*)(p))[1] = (d)>>8; \
} while(0)
+enum
+{
+ 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_ATRAC3 = 0x0270, /* Atrac3 stream */
+ WAVE_FORMAT_SWF_ADPCM = 0x5346, /* Adobe SWF ADPCM */
+};
+
+struct wave_fmt {
+ unsigned int formattag;
+ unsigned long channels;
+ unsigned int blockalign;
+ unsigned long bitspersample;
+ unsigned int samplesperblock;
+ unsigned long numbytes;
+};
+
+static unsigned long get_totalsamples(struct wave_fmt *fmt, struct mp3entry* id3)
+{
+ unsigned long totalsamples = 0;
+
+ switch (fmt->formattag)
+ {
+ case WAVE_FORMAT_PCM:
+ case WAVE_FORMAT_IEEE_FLOAT:
+ case WAVE_FORMAT_ALAW:
+ case WAVE_FORMAT_MULAW:
+ case IBM_FORMAT_ALAW:
+ case IBM_FORMAT_MULAW:
+ totalsamples =
+ fmt->numbytes / ((((fmt->bitspersample - 1) / 8) + 1) * fmt->channels);
+ break;
+ case WAVE_FORMAT_ADPCM:
+ case WAVE_FORMAT_DVI_ADPCM:
+ case WAVE_FORMAT_XBOX_ADPCM:
+ totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock;
+ break;
+ case WAVE_FORMAT_YAMAHA_ADPCM:
+ if (fmt->samplesperblock == 0)
+ {
+ if (fmt->blockalign == ((id3->frequency / 60) + 4) * fmt->channels)
+ fmt->samplesperblock = id3->frequency / 30;
+ else
+ fmt->samplesperblock = fmt->blockalign * 2 / fmt->channels;
+ }
+ totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock;
+ break;
+ case WAVE_FORMAT_DIALOGIC_OKI_ADPCM:
+ totalsamples = 2 * fmt->numbytes;
+ break;
+ case WAVE_FORMAT_SWF_ADPCM:
+ if (fmt->samplesperblock == 0)
+ fmt->samplesperblock = (((fmt->blockalign << 3) - 2) / fmt->channels - 22)
+ / fmt->bitspersample;
+
+ totalsamples = (fmt->numbytes / fmt->blockalign) * fmt->samplesperblock;
+ break;
+ default:
+ totalsamples = 0;
+ break;
+ }
+ return totalsamples;
+}
+
bool get_wave_metadata(int fd, struct mp3entry* id3)
{
/* Use the trackname part of the id3 structure as a temporary buffer */
unsigned char* buf = (unsigned char *)id3->path;
+ struct wave_fmt fmt;
unsigned long totalsamples = 0;
- unsigned long channels = 0;
- unsigned long bitspersample = 0;
- unsigned long numbytes = 0;
unsigned long offset = 0;
int read_bytes;
int i;
+ memset(&fmt, 0, sizeof(struct wave_fmt));
+
/* get RIFF chunk header */
- if ((lseek(fd, 0, SEEK_SET) < 0)
- || ((read_bytes = read(fd, buf, 12)) < 12))
+ if ((lseek(fd, 0, SEEK_SET) < 0) || (read(fd, buf, 12) < 12))
{
return false;
}
offset += 12;
- if ((memcmp(buf, "RIFF",4) != 0)
- || (memcmp(&buf[8], "WAVE", 4) !=0 ))
+ if ((memcmp(buf, "RIFF", 4) != 0) || (memcmp(&buf[8], "WAVE", 4) != 0))
{
+ DEBUGF("metadata error: missing riff header.\n");
return false;
}
@@ -70,7 +143,7 @@ bool get_wave_metadata(int fd, struct mp3entry* id3)
while (true)
{
/* get chunk header */
- if ((read_bytes = read(fd, buf, 8)) < 8)
+ if (read(fd, buf, 8) < 8)
return false;
offset += 8;
@@ -80,26 +153,41 @@ bool get_wave_metadata(int fd, struct mp3entry* id3)
if (memcmp(buf, "fmt ", 4) == 0)
{
/* get rest of chunk */
- if ((read_bytes = read(fd, buf, 16)) < 16)
+ if (i < 16)
return false;
- offset += 16;
- i -= 16;
+ read_bytes = 16;
+ if (i > 19)
+ read_bytes = 20;
- /* skipping wFormatTag */
+ if (read(fd, buf, read_bytes) != read_bytes)
+ return false;
+
+ offset += read_bytes;
+ i -= read_bytes;
+
+ /* wFormatTag */
+ fmt.formattag = buf[0] | (buf[1] << 8);
/* wChannels */
- channels = buf[2] | (buf[3] << 8);
+ fmt.channels = buf[2] | (buf[3] << 8);
/* dwSamplesPerSec */
id3->frequency = get_long_le(&buf[4]);
/* dwAvgBytesPerSec */
id3->bitrate = (get_long_le(&buf[8]) * 8) / 1000;
/* wBlockAlign */
- id3->bytesperframe = buf[12] | (buf[13] << 8);
+ fmt.blockalign = buf[12] | (buf[13] << 8);
+ id3->bytesperframe = fmt.blockalign;
/* wBitsPerSample */
- bitspersample = buf[14] | (buf[15] << 8);
+ fmt.bitspersample = buf[14] | (buf[15] << 8);
+ if (read_bytes > 19)
+ {
+ /* wSamplesPerBlock */
+ fmt.samplesperblock = buf[18] | (buf[19] << 8);
+ }
+
/* Check for ATRAC3 stream */
- if((buf[0] | (buf[1] << 8)) == 0x0270)
- {
+ if (fmt.formattag == WAVE_FORMAT_ATRAC3)
+ {
int jsflag = 0;
if(id3->bitrate == 66 || id3->bitrate == 94)
jsflag = 1;
@@ -107,7 +195,7 @@ bool get_wave_metadata(int fd, struct mp3entry* id3)
id3->extradata_size = 14;
id3->channels = 2;
id3->codectype = AFMT_OMA_ATRAC3;
- /* Store the extradata for the codec */
+ /* Store the extradata for the codec */
AV_WL16(&id3->id3v2buf[0], 1); // always 1
AV_WL32(&id3->id3v2buf[2], id3->frequency); // samples rate
AV_WL16(&id3->id3v2buf[6], jsflag); // coding mode
@@ -118,8 +206,9 @@ bool get_wave_metadata(int fd, struct mp3entry* id3)
}
else if (memcmp(buf, "data", 4) == 0)
{
- numbytes = i;
- id3->first_frame_offset = offset;
+ fmt.numbytes = i;
+ if (fmt.formattag == WAVE_FORMAT_ATRAC3)
+ id3->first_frame_offset = offset;
break;
}
else if (memcmp(buf, "fact", 4) == 0)
@@ -128,7 +217,7 @@ bool get_wave_metadata(int fd, struct mp3entry* id3)
if (i >= 4)
{
/* get rest of chunk */
- if ((read_bytes = read(fd, buf, 4)) < 4)
+ if (read(fd, buf, 4) < 4)
return false;
offset += 4;
i -= 4;
@@ -145,16 +234,15 @@ bool get_wave_metadata(int fd, struct mp3entry* id3)
offset += i;
}
- if ((numbytes == 0) || (channels == 0))
+ if ((fmt.numbytes == 0) || (fmt.channels == 0) || (fmt.blockalign == 0))
{
+ DEBUGF("metadata error: numbytes, channels, or blockalign is 0.\n");
return false;
}
if (totalsamples == 0)
{
- /* for PCM only */
- totalsamples = numbytes
- / ((((bitspersample - 1) / 8) + 1) * channels);
+ totalsamples = get_totalsamples(&fmt, id3);
}
id3->vbr = false; /* All WAV files are CBR */