From 3716abba9274f544dd31cdf4e6c83a845bf2a801 Mon Sep 17 00:00:00 2001 From: Yoshihisa Uchida Date: Sat, 20 Feb 2010 02:04:56 +0000 Subject: 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 --- apps/codecs/aiff.c | 58 ++++- apps/codecs/libpcm/SOURCES | 7 + apps/codecs/libpcm/adpcm_seek.c | 101 ++++++++ apps/codecs/libpcm/adpcm_seek.h | 39 +++ apps/codecs/libpcm/dialogic_oki_adpcm.c | 183 +++++++++++++ apps/codecs/libpcm/dvi_adpcm.c | 444 ++++++++++++++++---------------- apps/codecs/libpcm/ieee_float.c | 29 ++- apps/codecs/libpcm/ima_adpcm_common.c | 171 ++++++++++++ apps/codecs/libpcm/ima_adpcm_common.h | 32 +++ apps/codecs/libpcm/itut_g711.c | 44 ++-- apps/codecs/libpcm/linear_pcm.c | 39 ++- apps/codecs/libpcm/ms_adpcm.c | 166 ++++++++++++ apps/codecs/libpcm/pcm_common.h | 77 +++++- apps/codecs/libpcm/qt_ima_adpcm.c | 136 ++++++++++ apps/codecs/libpcm/support_formats.h | 21 +- apps/codecs/libpcm/swf_adpcm.c | 233 +++++++++++++++++ apps/codecs/libpcm/yamaha_adpcm.c | 245 ++++++++++++++++++ apps/codecs/wav.c | 122 ++++++++- apps/metadata/aiff.c | 23 +- apps/metadata/wave.c | 138 ++++++++-- 20 files changed, 1968 insertions(+), 340 deletions(-) create mode 100644 apps/codecs/libpcm/adpcm_seek.c create mode 100644 apps/codecs/libpcm/adpcm_seek.h create mode 100644 apps/codecs/libpcm/dialogic_oki_adpcm.c create mode 100644 apps/codecs/libpcm/ima_adpcm_common.c create mode 100644 apps/codecs/libpcm/ima_adpcm_common.h create mode 100644 apps/codecs/libpcm/ms_adpcm.c create mode 100644 apps/codecs/libpcm/qt_ima_adpcm.c create mode 100644 apps/codecs/libpcm/swf_adpcm.c create mode 100644 apps/codecs/libpcm/yamaha_adpcm.c 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 +#include +#include + +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]<>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 +#include +#include + +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 #include @@ -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 + * (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) + * .... + * + * (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 + * (channels = 1) + * uint8_t ADPCM data (1st data: 0-3 bit, 2nd data: 4-7 bit) + * .... + * + * (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 */ -- cgit v1.2.3