From f40bfc9267b13b54e6379dfe7539447662879d24 Mon Sep 17 00:00:00 2001 From: Sean Bartell Date: Sat, 25 Jun 2011 21:32:25 -0400 Subject: Add codecs to librbcodec. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97 Reviewed-on: http://gerrit.rockbox.org/137 Reviewed-by: Nils Wallménius Tested-by: Nils Wallménius --- lib/rbcodec/codecs/libpcm/SOURCES | 11 + lib/rbcodec/codecs/libpcm/adpcm_seek.c | 101 ++++++++ lib/rbcodec/codecs/libpcm/adpcm_seek.h | 39 ++++ lib/rbcodec/codecs/libpcm/dialogic_oki_adpcm.c | 183 +++++++++++++++ lib/rbcodec/codecs/libpcm/dvi_adpcm.c | 308 +++++++++++++++++++++++++ lib/rbcodec/codecs/libpcm/ieee_float.c | 165 +++++++++++++ lib/rbcodec/codecs/libpcm/ima_adpcm_common.c | 171 ++++++++++++++ lib/rbcodec/codecs/libpcm/ima_adpcm_common.h | 33 +++ lib/rbcodec/codecs/libpcm/itut_g711.c | 204 ++++++++++++++++ lib/rbcodec/codecs/libpcm/libpcm.make | 18 ++ lib/rbcodec/codecs/libpcm/linear_pcm.c | 294 +++++++++++++++++++++++ lib/rbcodec/codecs/libpcm/ms_adpcm.c | 168 ++++++++++++++ lib/rbcodec/codecs/libpcm/pcm_common.h | 190 +++++++++++++++ lib/rbcodec/codecs/libpcm/qt_ima_adpcm.c | 138 +++++++++++ lib/rbcodec/codecs/libpcm/support_formats.h | 55 +++++ lib/rbcodec/codecs/libpcm/swf_adpcm.c | 236 +++++++++++++++++++ lib/rbcodec/codecs/libpcm/yamaha_adpcm.c | 250 ++++++++++++++++++++ 17 files changed, 2564 insertions(+) create mode 100644 lib/rbcodec/codecs/libpcm/SOURCES create mode 100644 lib/rbcodec/codecs/libpcm/adpcm_seek.c create mode 100644 lib/rbcodec/codecs/libpcm/adpcm_seek.h create mode 100644 lib/rbcodec/codecs/libpcm/dialogic_oki_adpcm.c create mode 100644 lib/rbcodec/codecs/libpcm/dvi_adpcm.c create mode 100644 lib/rbcodec/codecs/libpcm/ieee_float.c create mode 100644 lib/rbcodec/codecs/libpcm/ima_adpcm_common.c create mode 100644 lib/rbcodec/codecs/libpcm/ima_adpcm_common.h create mode 100644 lib/rbcodec/codecs/libpcm/itut_g711.c create mode 100644 lib/rbcodec/codecs/libpcm/libpcm.make create mode 100644 lib/rbcodec/codecs/libpcm/linear_pcm.c create mode 100644 lib/rbcodec/codecs/libpcm/ms_adpcm.c create mode 100644 lib/rbcodec/codecs/libpcm/pcm_common.h create mode 100644 lib/rbcodec/codecs/libpcm/qt_ima_adpcm.c create mode 100644 lib/rbcodec/codecs/libpcm/support_formats.h create mode 100644 lib/rbcodec/codecs/libpcm/swf_adpcm.c create mode 100644 lib/rbcodec/codecs/libpcm/yamaha_adpcm.c (limited to 'lib/rbcodec/codecs/libpcm') diff --git a/lib/rbcodec/codecs/libpcm/SOURCES b/lib/rbcodec/codecs/libpcm/SOURCES new file mode 100644 index 0000000000..356c9cdbb7 --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/SOURCES @@ -0,0 +1,11 @@ +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/lib/rbcodec/codecs/libpcm/adpcm_seek.c b/lib/rbcodec/codecs/libpcm/adpcm_seek.c new file mode 100644 index 0000000000..ce49d5fcd3 --- /dev/null +++ b/lib/rbcodec/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/lib/rbcodec/codecs/libpcm/adpcm_seek.h b/lib/rbcodec/codecs/libpcm/adpcm_seek.h new file mode 100644 index 0000000000..2dd3f000b1 --- /dev/null +++ b/lib/rbcodec/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/lib/rbcodec/codecs/libpcm/dialogic_oki_adpcm.c b/lib/rbcodec/codecs/libpcm/dialogic_oki_adpcm.c new file mode 100644 index 0000000000..60090aaa89 --- /dev/null +++ b/lib/rbcodec/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 "adpcm_seek.h" +#include "support_formats.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 int blocksperchunk; + +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 */ + blocksperchunk = ci->id3->frequency >> 6; + fmt->chunksize = blocksperchunk * fmt->blockalign; + + 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) << (PCM_OUTPUT_DEPTH - 12); + *outbuf++ = create_pcmdata(*inbuf ) << (PCM_OUTPUT_DEPTH - 12); + 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(uint32_t seek_val, int seek_mode, + uint8_t *(*read_buffer)(size_t *realsize)) +{ + static struct pcm_pos newpos; + uint32_t seek_count = (seek_mode == PCM_SEEK_TIME)? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / (blocksperchunk * fmt->samplesperblock) : + seek_val / (unsigned long)fmt->chunksize; + uint32_t new_count = seek(seek_count, &cur_data, read_buffer, &decode_for_seek); + + newpos.pos = new_count * fmt->chunksize; + newpos.samples = new_count * blocksperchunk * 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/lib/rbcodec/codecs/libpcm/dvi_adpcm.c b/lib/rbcodec/codecs/libpcm/dvi_adpcm.c new file mode 100644 index 0000000000..2e702ca394 --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/dvi_adpcm.c @@ -0,0 +1,308 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Dave Chapman + * Copyright (C) 2009 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 "ima_adpcm_common.h" +#include "support_formats.h" + +/* + * 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 struct pcm_format *fmt; + +static bool set_format(struct pcm_format *format) +{ + fmt = format; + + if (fmt->bitspersample < 2 || fmt->bitspersample > 5) + { + DEBUGF("CODEC_ERROR: dvi adpcm must be 2, 3, 4 or 5 bitspersample: %d\n", + fmt->bitspersample); + return false; + } + + fmt->chunksize = fmt->blockalign; + + init_ima_adpcm_decoder(fmt->bitspersample, NULL); + return true; +} + +static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, + uint8_t *(*read_buffer)(size_t *realsize)) +{ + static struct pcm_pos newpos; + uint32_t newblock = (seek_mode == PCM_SEEK_TIME) ? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / fmt->samplesperblock : + seek_val / fmt->blockalign; + + (void)read_buffer; + newpos.pos = newblock * fmt->blockalign; + newpos.samples = newblock * fmt->samplesperblock; + return &newpos; +} + +static inline void decode_2bit(const uint8_t **inbuf, size_t inbufsize, + int32_t **outbuf, int *outbufcount) +{ + int ch; + int i; + int32_t *pcmbuf; + int samples; + + samples = inbufsize / (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 ) << IMA_ADPCM_INC_DEPTH; + pcmbuf += fmt->channels; + *pcmbuf = create_pcmdata(ch, **inbuf >> 2) << IMA_ADPCM_INC_DEPTH; + pcmbuf += fmt->channels; + *pcmbuf = create_pcmdata(ch, **inbuf >> 4) << IMA_ADPCM_INC_DEPTH; + pcmbuf += fmt->channels; + *pcmbuf = create_pcmdata(ch, **inbuf >> 6) << IMA_ADPCM_INC_DEPTH; + pcmbuf += fmt->channels; + (*inbuf)++; + } + } + *outbuf += 16 * fmt->channels; + } +} + +static inline void decode_3bit(const uint8_t **inbuf, size_t inbufsize, + int32_t **outbuf, int *outbufcount) +{ + const uint8_t *adpcmbuf; + uint32_t adpcms; + int ch; + int i; + int32_t *pcmbuf; + int samples; + + samples = (inbufsize - 4 * fmt->channels) / (12 * 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; + for (i = 0; i < 8; i++) + { + *pcmbuf = create_pcmdata(ch, adpcms >> (3 * i)) << IMA_ADPCM_INC_DEPTH; + pcmbuf += fmt->channels; + } + adpcms = *adpcmbuf++; + adpcmbuf += (fmt->channels - 1) * 4; + adpcms |= (*adpcmbuf++) << 8; + adpcms |= (*adpcmbuf++) << 16; + for (i = 0; i < 8; i++) + { + *pcmbuf = create_pcmdata(ch, adpcms >> (3 * i)) << IMA_ADPCM_INC_DEPTH; + pcmbuf += fmt->channels; + } + 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)) << IMA_ADPCM_INC_DEPTH; + pcmbuf += fmt->channels; + } + adpcms = *adpcmbuf++; + adpcms |= (*adpcmbuf++) << 8; + adpcms |= (*adpcmbuf++) << 16; + for (i = 0; i < 8; i++) + { + *pcmbuf = create_pcmdata(ch, adpcms >> (3 * i)) << IMA_ADPCM_INC_DEPTH; + pcmbuf += fmt->channels; + } + } + *outbuf += 32 * fmt->channels; + *inbuf += 12 * fmt->channels; + } +} + +static inline void decode_4bit(const uint8_t **inbuf, size_t inbufsize, + int32_t **outbuf, int *outbufcount) +{ + int ch; + int i; + int32_t *pcmbuf; + int samples; + + samples = inbufsize / (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 ) << IMA_ADPCM_INC_DEPTH; + pcmbuf += fmt->channels; + *pcmbuf = create_pcmdata_size4(ch, **inbuf >> 4) << IMA_ADPCM_INC_DEPTH; + pcmbuf += fmt->channels; + (*inbuf)++; + } + } + *outbuf += 8 * fmt->channels; + } +} + +static inline void decode_5bit(const uint8_t **inbuf, size_t inbufsize, + int32_t **outbuf, int *outbufcount) +{ + const uint8_t *adpcmbuf; + uint64_t adpcms; + int ch; + int i; + int32_t *pcmbuf; + int samples; + + samples = (inbufsize - 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)) << IMA_ADPCM_INC_DEPTH; + 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)) << IMA_ADPCM_INC_DEPTH; + 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)) << IMA_ADPCM_INC_DEPTH; + 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)) << IMA_ADPCM_INC_DEPTH; + pcmbuf += fmt->channels; + } + } + *outbuf += 32 * fmt->channels; + *inbuf += 20 * fmt->channels; + } +} + +static int decode(const uint8_t *inbuf, size_t inbufsize, + int32_t *outbuf, int *outbufcount) +{ + int ch; + int32_t init_pcmdata[2]; + int8_t init_index[2]; + + *outbufcount = 0; + 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] << IMA_ADPCM_INC_DEPTH; + } + + *outbufcount += 1; + set_decode_parameters(fmt->channels, init_pcmdata, init_index); + + if (fmt->bitspersample == 4) + decode_4bit(&inbuf, inbufsize, &outbuf, outbufcount); + else if (fmt->bitspersample == 3) + decode_3bit(&inbuf, inbufsize, &outbuf, outbufcount); + else if (fmt->bitspersample == 5) + decode_5bit(&inbuf, inbufsize, &outbuf, outbufcount); + else /* fmt->bitspersample == 2 */ + decode_2bit(&inbuf, inbufsize, &outbuf, outbufcount); + + return CODEC_OK; +} + +static const struct pcm_codec codec = { + set_format, + get_seek_pos, + decode, + }; + +const struct pcm_codec *get_dvi_adpcm_codec(void) +{ + return &codec; +} diff --git a/lib/rbcodec/codecs/libpcm/ieee_float.c b/lib/rbcodec/codecs/libpcm/ieee_float.c new file mode 100644 index 0000000000..639390bcd5 --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/ieee_float.c @@ -0,0 +1,165 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2009 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 "support_formats.h" + +/* + * IEEE float + */ + +static struct pcm_format *fmt; + +static bool set_format(struct pcm_format *format) +{ + fmt = format; + + if (fmt->channels == 0) + { + DEBUGF("CODEC_ERROR: channels is 0\n"); + return false; + } + + if (fmt->bitspersample != 32 && fmt->bitspersample != 64) + { + DEBUGF("CODEC_ERROR: ieee float must be 32 or 64 bitspersample: %d\n", + fmt->bitspersample); + return false; + } + + fmt->bytespersample = fmt->bitspersample >> 3; + + if (fmt->blockalign == 0) + fmt->blockalign = fmt->bytespersample * fmt->channels; + + 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 struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, + uint8_t *(*read_buffer)(size_t *realsize)) +{ + static struct pcm_pos newpos; + uint32_t newblock = (seek_mode == PCM_SEEK_TIME) ? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / fmt->samplesperblock : + seek_val / fmt->blockalign; + + (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) +{ + uint32_t i; + int32_t pcm; + int16_t exp; + int sgn; + + if (fmt->bitspersample == 32) + { + for (i = 0; i < inbufsize; i += 4) + { + if (fmt->is_little_endian) + { + pcm = (inbuf[0]<<5)|(inbuf[1]<<13)|((inbuf[2]|0x80)<<21); + exp = ((inbuf[2]>>7)|((inbuf[3]&0x7f)<<1)) - 127; + sgn = inbuf[3] & 0x80; + } + else + { + pcm = (inbuf[3]<<5)|(inbuf[2]<<13)|((inbuf[1]|0x80)<<21); + exp = ((inbuf[1]>>7)|((inbuf[0]&0x7f)<<1)) - 127; + sgn = inbuf[0] & 0x80; + } + if (exp > -29 && exp < 0) + { + pcm >>= -exp; + if (sgn) + pcm = -pcm; + } + else if (exp < -28) + pcm = 0; + else + pcm = (sgn)?-(1<<28):(1<<28)-1; + + outbuf[i/4] = pcm; + inbuf += 4; + } + *outbufsize = inbufsize >> 2; + } + else + { + for (i = 0; i < inbufsize; i += 8) + { + if (fmt->is_little_endian) + { + pcm = inbuf[3]|(inbuf[4]<<8)|(inbuf[5]<<16)|(((inbuf[6]&0x0f)|0x10)<<24); + exp = (((inbuf[6]&0xf0)>>4)|((inbuf[7]&0x7f)<<4)) - 1023; + sgn = inbuf[7] & 0x80; + } + else + { + pcm = inbuf[4]|(inbuf[3]<<8)|(inbuf[2]<<16)|(((inbuf[1]&0x0f)|0x10)<<24); + exp = (((inbuf[1]&0xf0)>>4)|((inbuf[0]&0x7f)<<4)) - 1023; + sgn = inbuf[0] & 0x80; + } + if (exp > -29 && exp < 0) + { + pcm >>= -exp; + if (sgn) + pcm = -pcm; + } + else if (exp < -28) + pcm = 0; + else + pcm = (sgn)?-(1<<28):(1<<28)-1; + + outbuf[i/8] = pcm; + inbuf += 8; + } + *outbufsize = inbufsize >> 3; + } + + if (fmt->channels == 2) + *outbufsize >>= 1; + + return CODEC_OK; +} + +static const struct pcm_codec codec = { + set_format, + get_seek_pos, + decode, + }; + +const struct pcm_codec *get_ieee_float_codec(void) +{ + return &codec; +} diff --git a/lib/rbcodec/codecs/libpcm/ima_adpcm_common.c b/lib/rbcodec/codecs/libpcm/ima_adpcm_common.c new file mode 100644 index 0000000000..724cce31b0 --- /dev/null +++ b/lib/rbcodec/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 indices[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]; + indices[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[indices[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; + + indices[ch] += use_index_table[nibble & step_mask]; + CLIP(indices[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[indices[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; + + indices[ch] += use_index_table[nibble & 0x07]; + CLIP(indices[ch], 0, 88); + + CLIP(pcmdata[ch], -32768, 32767); + + return (int16_t)pcmdata[ch]; +} diff --git a/lib/rbcodec/codecs/libpcm/ima_adpcm_common.h b/lib/rbcodec/codecs/libpcm/ima_adpcm_common.h new file mode 100644 index 0000000000..46fd6083ec --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/ima_adpcm_common.h @@ -0,0 +1,33 @@ +/*************************************************************************** + * __________ __ ___. + * 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 + +#define IMA_ADPCM_INC_DEPTH (PCM_OUTPUT_DEPTH - 16) + +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/lib/rbcodec/codecs/libpcm/itut_g711.c b/lib/rbcodec/codecs/libpcm/itut_g711.c new file mode 100644 index 0000000000..88ff5f59e6 --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/itut_g711.c @@ -0,0 +1,204 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Dave Chapman + * Copyright (C) 2009 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 "support_formats.h" + +/* + * ITU-T G.711 A-law mu-law + */ + +static const int16_t alaw2linear16[256] ICONST_ATTR = { + -5504, -5248, -6016, -5760, -4480, -4224, -4992, + -4736, -7552, -7296, -8064, -7808, -6528, -6272, + -7040, -6784, -2752, -2624, -3008, -2880, -2240, + -2112, -2496, -2368, -3776, -3648, -4032, -3904, + -3264, -3136, -3520, -3392, -22016, -20992, -24064, + -23040, -17920, -16896, -19968, -18944, -30208, -29184, + -32256, -31232, -26112, -25088, -28160, -27136, -11008, + -10496, -12032, -11520, -8960, -8448, -9984, -9472, + -15104, -14592, -16128, -15616, -13056, -12544, -14080, + -13568, -344, -328, -376, -360, -280, -264, + -312, -296, -472, -456, -504, -488, -408, + -392, -440, -424, -88, -72, -120, -104, + -24, -8, -56, -40, -216, -200, -248, + -232, -152, -136, -184, -168, -1376, -1312, + -1504, -1440, -1120, -1056, -1248, -1184, -1888, + -1824, -2016, -1952, -1632, -1568, -1760, -1696, + -688, -656, -752, -720, -560, -528, -624, + -592, -944, -912, -1008, -976, -816, -784, + -880, -848, 5504, 5248, 6016, 5760, 4480, + 4224, 4992, 4736, 7552, 7296, 8064, 7808, + 6528, 6272, 7040, 6784, 2752, 2624, 3008, + 2880, 2240, 2112, 2496, 2368, 3776, 3648, + 4032, 3904, 3264, 3136, 3520, 3392, 22016, + 20992, 24064, 23040, 17920, 16896, 19968, 18944, + 30208, 29184, 32256, 31232, 26112, 25088, 28160, + 27136, 11008, 10496, 12032, 11520, 8960, 8448, + 9984, 9472, 15104, 14592, 16128, 15616, 13056, + 12544, 14080, 13568, 344, 328, 376, 360, + 280, 264, 312, 296, 472, 456, 504, + 488, 408, 392, 440, 424, 88, 72, + 120, 104, 24, 8, 56, 40, 216, + 200, 248, 232, 152, 136, 184, 168, + 1376, 1312, 1504, 1440, 1120, 1056, 1248, + 1184, 1888, 1824, 2016, 1952, 1632, 1568, + 1760, 1696, 688, 656, 752, 720, 560, + 528, 624, 592, 944, 912, 1008, 976, + 816, 784, 880, 848 +}; + +static const int16_t ulaw2linear16[256] ICONST_ATTR = { + -32124, -31100, -30076, -29052, -28028, -27004, -25980, + -24956, -23932, -22908, -21884, -20860, -19836, -18812, + -17788, -16764, -15996, -15484, -14972, -14460, -13948, + -13436, -12924, -12412, -11900, -11388, -10876, -10364, + -9852, -9340, -8828, -8316, -7932, -7676, -7420, + -7164, -6908, -6652, -6396, -6140, -5884, -5628, + -5372, -5116, -4860, -4604, -4348, -4092, -3900, + -3772, -3644, -3516, -3388, -3260, -3132, -3004, + -2876, -2748, -2620, -2492, -2364, -2236, -2108, + -1980, -1884, -1820, -1756, -1692, -1628, -1564, + -1500, -1436, -1372, -1308, -1244, -1180, -1116, + -1052, -988, -924, -876, -844, -812, -780, + -748, -716, -684, -652, -620, -588, -556, + -524, -492, -460, -428, -396, -372, -356, + -340, -324, -308, -292, -276, -260, -244, + -228, -212, -196, -180, -164, -148, -132, + -120, -112, -104, -96, -88, -80, -72, + -64, -56, -48, -40, -32, -24, -16, + -8, 0, 32124, 31100, 30076, 29052, 28028, + 27004, 25980, 24956, 23932, 22908, 21884, 20860, + 19836, 18812, 17788, 16764, 15996, 15484, 14972, + 14460, 13948, 13436, 12924, 12412, 11900, 11388, + 10876, 10364, 9852, 9340, 8828, 8316, 7932, + 7676, 7420, 7164, 6908, 6652, 6396, 6140, + 5884, 5628, 5372, 5116, 4860, 4604, 4348, + 4092, 3900, 3772, 3644, 3516, 3388, 3260, + 3132, 3004, 2876, 2748, 2620, 2492, 2364, + 2236, 2108, 1980, 1884, 1820, 1756, 1692, + 1628, 1564, 1500, 1436, 1372, 1308, 1244, + 1180, 1116, 1052, 988, 924, 876, 844, + 812, 780, 748, 716, 684, 652, 620, + 588, 556, 524, 492, 460, 428, 396, + 372, 356, 340, 324, 308, 292, 276, + 260, 244, 228, 212, 196, 180, 164, + 148, 132, 120, 112, 104, 96, 88, + 80, 72, 64, 56, 48, 40, 32, + 24, 16, 8, 0 +}; + +static struct pcm_format *fmt; + +static bool set_format(struct pcm_format *format) +{ + fmt = format; + + if (fmt->channels == 0) + { + DEBUGF("CODEC_ERROR: channels is 0\n"); + return false; + } + + if (fmt->bitspersample != 8) + { + DEBUGF("CODEC_ERROR: alaw and mulaw must have 8 bitspersample: %d\n", + fmt->bitspersample); + return false; + } + + fmt->bytespersample = 1; + + if (fmt->blockalign == 0) + fmt->blockalign = fmt->channels; + + fmt->samplesperblock = fmt->blockalign / fmt->channels; + + /* chunksize = about 1/50[sec] data */ + fmt->chunksize = (ci->id3->frequency / (50 * fmt->samplesperblock)) + * fmt->blockalign; + + return true; +} + +static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, + uint8_t *(*read_buffer)(size_t *realsize)) +{ + static struct pcm_pos newpos; + uint32_t newblock = (seek_mode == PCM_SEEK_TIME) ? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / fmt->samplesperblock : + seek_val / fmt->blockalign; + + (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, + int32_t *outbuf, int *outbufsize) +{ + uint32_t i; + + for (i = 0; i < inbufsize; i++) + outbuf[i] = alaw2linear16[inbuf[i]] << (PCM_OUTPUT_DEPTH - 16); + + *outbufsize = (fmt->channels == 2) ? (inbufsize >> 1) : inbufsize; + + return CODEC_OK; +} + +static int decode_mulaw(const uint8_t *inbuf, size_t inbufsize, + int32_t *outbuf, int *outbufsize) +{ + uint32_t i; + + for (i = 0; i < inbufsize; i++) + outbuf[i] = ulaw2linear16[inbuf[i]] << (PCM_OUTPUT_DEPTH - 16); + + *outbufsize = (fmt->channels == 2) ? (inbufsize >> 1) : inbufsize; + + return CODEC_OK; +} + +static const struct pcm_codec alaw_codec = { + set_format, + get_seek_pos, + decode_alaw, + }; + +static const struct pcm_codec mulaw_codec = { + set_format, + get_seek_pos, + decode_mulaw, + }; + +const struct pcm_codec *get_itut_g711_alaw_codec(void) +{ + return &alaw_codec; +} + +const struct pcm_codec *get_itut_g711_mulaw_codec(void) +{ + return &mulaw_codec; +} + diff --git a/lib/rbcodec/codecs/libpcm/libpcm.make b/lib/rbcodec/codecs/libpcm/libpcm.make new file mode 100644 index 0000000000..15c23bedf2 --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/libpcm.make @@ -0,0 +1,18 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +# libpcm +PCMSLIB := $(CODECDIR)/libpcm.a +PCMSLIB_SRC := $(call preprocess, $(RBCODECLIB_DIR)/codecs/libpcm/SOURCES) +PCMSLIB_OBJ := $(call c2obj, $(PCMSLIB_SRC)) +OTHER_SRC += $(PCMSLIB_SRC) + +$(PCMSLIB): $(PCMSLIB_OBJ) + $(SILENT)$(shell rm -f $@) + $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null diff --git a/lib/rbcodec/codecs/libpcm/linear_pcm.c b/lib/rbcodec/codecs/libpcm/linear_pcm.c new file mode 100644 index 0000000000..5c3c140b8c --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/linear_pcm.c @@ -0,0 +1,294 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 Dave Chapman + * Copyright (C) 2009 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 "support_formats.h" + +/* + * Linear PCM + */ + +#define INC_DEPTH_8 (PCM_OUTPUT_DEPTH - 8) +#define INC_DEPTH_16 (PCM_OUTPUT_DEPTH - 16) +#define INC_DEPTH_24 (PCM_OUTPUT_DEPTH - 24) +#define DEC_DEPTH_32 (32 - PCM_OUTPUT_DEPTH) + + +static struct pcm_format *fmt; + +static bool set_format(struct pcm_format *format) +{ + fmt = format; + + if (fmt->channels == 0) + { + DEBUGF("CODEC_ERROR: channels is 0\n"); + return false; + } + + if (fmt->bitspersample == 0) + { + DEBUGF("CODEC_ERROR: bitspersample is 0\n"); + return false; + } + + if (fmt->bitspersample > 32) + { + DEBUGF("CODEC_ERROR: pcm with more than 32 bitspersample " + "is unsupported\n"); + return false; + } + + fmt->bytespersample = fmt->bitspersample >> 3; + + if (fmt->blockalign == 0) + fmt->blockalign = fmt->bytespersample * fmt->channels; + + 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 struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, + uint8_t *(*read_buffer)(size_t *realsize)) +{ + static struct pcm_pos newpos; + uint32_t newblock = (seek_mode == PCM_SEEK_TIME) ? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / fmt->samplesperblock : + seek_val / fmt->blockalign; + + (void)read_buffer; + newpos.pos = newblock * fmt->blockalign; + newpos.samples = newblock * fmt->samplesperblock; + return &newpos; +} + +/* 8bit decode functions */ +static inline void decode_s8(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i++) + outbuf[i] = SE(inbuf[i]) << INC_DEPTH_8; +} + +static inline void decode_u8(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i++) + outbuf[i] = SFT(inbuf[i]) << INC_DEPTH_8; +} + +/* 16bit decode functions */ +static inline void decode_s16le(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i += 2) + outbuf[i/2] = (inbuf[i] << INC_DEPTH_16)|(SE(inbuf[i+1]) << INC_DEPTH_8); +} + +static inline void decode_u16le(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i += 2) + outbuf[i/2] = (inbuf[i] << INC_DEPTH_16)|(SFT(inbuf[i+1]) << INC_DEPTH_8); +} + +static inline void decode_s16be(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i += 2) + outbuf[i/2] = (inbuf[i+1] << INC_DEPTH_16)|(SE(inbuf[i]) << INC_DEPTH_8); +} + +static inline void decode_u16be(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i += 2) + outbuf[i/2] = (inbuf[i+1] << INC_DEPTH_16)|(SFT(inbuf[i]) << INC_DEPTH_8); +} + +/* 24bit decode functions */ +static inline void decode_s24le(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i += 3) + outbuf[i/3] = (inbuf[i] << INC_DEPTH_24)|(inbuf[i+1] << INC_DEPTH_16)| + (SE(inbuf[i+2]) << INC_DEPTH_8); +} + +static inline void decode_u24le(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i += 3) + outbuf[i/3] = (inbuf[i] << INC_DEPTH_24)|(inbuf[i+1] << INC_DEPTH_16)| + (SFT(inbuf[i+2]) << INC_DEPTH_8); +} + +static inline void decode_s24be(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i += 3) + outbuf[i/3] = (inbuf[i+2] << INC_DEPTH_24)|(inbuf[i+1] << INC_DEPTH_16)| + (SE(inbuf[i]) << INC_DEPTH_8); +} + +static inline void decode_u24be(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i += 3) + outbuf[i/3] = (inbuf[i+2] << INC_DEPTH_24)|(inbuf[i+1] << INC_DEPTH_16)| + (SFT(inbuf[i]) << INC_DEPTH_8); +} + +/* 32bit decode functions */ +static inline void decode_s32le(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i += 4) + outbuf[i/4] = (inbuf[i] >> DEC_DEPTH_32)|(inbuf[i+1] << INC_DEPTH_24)| + (inbuf[i+2] << INC_DEPTH_16)|(SE(inbuf[i+3]) << INC_DEPTH_8); +} + +static inline void decode_u32le(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i += 4) + outbuf[i/4] = (inbuf[i] >> DEC_DEPTH_32)|(inbuf[i+1] << INC_DEPTH_24)| + (inbuf[i+2] << INC_DEPTH_16)|(SFT(inbuf[i+3]) << INC_DEPTH_8); +} + +static inline void decode_s32be(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i += 4) + outbuf[i/4] = (inbuf[i+3] >> DEC_DEPTH_32)|(inbuf[i+2] << INC_DEPTH_24)| + (inbuf[i+1] << INC_DEPTH_16)|(SE(inbuf[i]) << INC_DEPTH_8); +} + +static inline void decode_u32be(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf) +{ + size_t i = 0; + + for ( ; i < inbufsize; i += 4) + outbuf[i/4] = (inbuf[i+3] >> DEC_DEPTH_32)|(inbuf[i+2] << INC_DEPTH_24)| + (inbuf[i+1] << INC_DEPTH_16)|(SFT(inbuf[i]) << INC_DEPTH_8); +} + +static int decode(const uint8_t *inbuf, size_t inbufsize, int32_t *outbuf, int *outbufcount) +{ + if (fmt->bitspersample > 24) + { + if (fmt->is_little_endian) + { + if (fmt->is_signed) + decode_s32le(inbuf, inbufsize, outbuf); + else + decode_u32le(inbuf, inbufsize, outbuf); + } + else + { + if (fmt->is_signed) + decode_s32be(inbuf, inbufsize, outbuf); + else + decode_u32be(inbuf, inbufsize, outbuf); + } + *outbufcount = inbufsize >> 2; + } + else if (fmt->bitspersample > 16) + { + if (fmt->is_little_endian) + { + if (fmt->is_signed) + decode_s24le(inbuf, inbufsize, outbuf); + else + decode_u24le(inbuf, inbufsize, outbuf); + } + else + { + if (fmt->is_signed) + decode_s24be(inbuf, inbufsize, outbuf); + else + decode_u24be(inbuf, inbufsize, outbuf); + } + *outbufcount = inbufsize / 3; + } + else if (fmt->bitspersample > 8) + { + if (fmt->is_little_endian) + { + if (fmt->is_signed) + decode_s16le(inbuf, inbufsize, outbuf); + else + decode_u16le(inbuf, inbufsize, outbuf); + } + else + { + if (fmt->is_signed) + decode_s16be(inbuf, inbufsize, outbuf); + else + decode_u16be(inbuf, inbufsize, outbuf); + } + *outbufcount = inbufsize >> 1; + } + else + { + if (fmt->is_signed) + decode_s8(inbuf, inbufsize, outbuf); + else + decode_u8(inbuf, inbufsize, outbuf); + + *outbufcount = inbufsize; + } + + if (fmt->channels == 2) + *outbufcount >>= 1; + + return CODEC_OK; +} + +static const struct pcm_codec codec = { + set_format, + get_seek_pos, + decode, + }; + +const struct pcm_codec *get_linear_pcm_codec(void) +{ + return &codec; +} diff --git a/lib/rbcodec/codecs/libpcm/ms_adpcm.c b/lib/rbcodec/codecs/libpcm/ms_adpcm.c new file mode 100644 index 0000000000..a385d6c99f --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/ms_adpcm.c @@ -0,0 +1,168 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "support_formats.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(uint32_t seek_val, int seek_mode, + uint8_t *(*read_buffer)(size_t *realsize)) +{ + static struct pcm_pos newpos; + uint32_t newblock = (seek_mode == PCM_SEEK_TIME) ? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / fmt->samplesperblock : + seek_val / fmt->blockalign; + + (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 ) << (PCM_OUTPUT_DEPTH - 16); + *outbuf++ = create_pcmdata(ch, *inbuf & 0xf) << (PCM_OUTPUT_DEPTH - 16); + 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/lib/rbcodec/codecs/libpcm/pcm_common.h b/lib/rbcodec/codecs/libpcm/pcm_common.h new file mode 100644 index 0000000000..90e29c98ee --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/pcm_common.h @@ -0,0 +1,190 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2009 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_PCM_COMMON_H +#define CODEC_LIBPCM_PCM_COMMON_H + +#include +#include +#include + +/* decoded pcm sample depth (sample 28bit + sign 1bit) */ +#define PCM_OUTPUT_DEPTH 29 + +/* Macro that sign extends an unsigned byte */ +#define SE(x) ((int32_t)((int8_t)(x))) + +/* 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) + * AIFF: compressionType (in 'COMM' chunk) + */ + uint32_t formattag; + + /* + * RIFF: wChannels (in 'fmt ' chunk) + * AIFF: numChannels (in 'COMM' chunk) + */ + uint16_t channels; + + /* + * RIFF: dwSamplesPerSec (in 'fmt ' chunk) + * AIFF: sampleRate (in 'COMM' chunk) + */ + uint32_t samplespersec; + + /* RIFF: dwAvgBytesPerSec (in 'fmt ' chunk) */ + uint32_t avgbytespersec; + + /* + * RIFF: wBlockAlign (in 'fmt ' chunk) + * AIFF: blockSize (in 'SSND' chunk) + */ + uint16_t blockalign; + + /* + * RIFF: wBitsPerSample (in 'fmt ' chunk) + * AIFF: sampleSize (in 'COMM' chunk) + */ + uint16_t bitspersample; + + /* RIFF: wSize (in 'fmt ' chunk) */ + uint16_t size; + + /* RIFF: dSamplesPerBlock (in 'fmt ' chunk) */ + uint16_t samplesperblock; + + /* RIFF: wTotalSamples (in 'fact' chunk) */ + uint16_t totalsamples; + + /* the following values are not RIFF/AIFF chunk values */ + + /* bytes per sample */ + int bytespersample; + + /* chunk size */ + long chunksize; + + /* data size */ + uint32_t numbytes; + + /* + * data endian + * true: little endian, false: big endian + */ + bool is_little_endian; + + /* + * data signess + * 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; +}; + +#define PCM_SEEK_TIME 0 +#define PCM_SEEK_POS 1 + +struct pcm_codec { + /* + * 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_val + * seek time [ms] or seek position + * + * [In] seek_mode + * if seek_mode sets PCM_SEEK_TIME, then seek_val means the seek time. + * if seek_mode sets PCM_SEEK_POS, then seek_val means the seek position. + * + * [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)(uint32_t seek_val, int seek_mode, + 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 *outbufcount); +}; + +struct pcm_entry { + uint32_t format_tag; + const struct pcm_codec *(*get_codec)(void); +}; + +#endif diff --git a/lib/rbcodec/codecs/libpcm/qt_ima_adpcm.c b/lib/rbcodec/codecs/libpcm/qt_ima_adpcm.c new file mode 100644 index 0000000000..d7b3360eb3 --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/qt_ima_adpcm.c @@ -0,0 +1,138 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "ima_adpcm_common.h" +#include "support_formats.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(uint32_t seek_val, int seek_mode, + uint8_t *(*read_buffer)(size_t *realsize)) +{ + static struct pcm_pos newpos; + uint32_t newblock = (seek_mode == PCM_SEEK_TIME) ? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / fmt->samplesperblock : + seek_val / fmt->blockalign; + + (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 ) << IMA_ADPCM_INC_DEPTH; + pcmbuf += fmt->channels; + *pcmbuf = create_pcmdata_size4(ch, *inbuf >> 4) << IMA_ADPCM_INC_DEPTH; + 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/lib/rbcodec/codecs/libpcm/support_formats.h b/lib/rbcodec/codecs/libpcm/support_formats.h new file mode 100644 index 0000000000..b1e089e464 --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/support_formats.h @@ -0,0 +1,55 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2009 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_SUPPORT_FORMATS_H +#define CODEC_LIBPCM_SUPPORT_FORMATS_H + +#include "pcm_common.h" + +/* Linear PCM */ +const struct pcm_codec *get_linear_pcm_codec(void); + +/* ITU-T G.711 A-law */ +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 (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/lib/rbcodec/codecs/libpcm/swf_adpcm.c b/lib/rbcodec/codecs/libpcm/swf_adpcm.c new file mode 100644 index 0000000000..c440fd1303 --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/swf_adpcm.c @@ -0,0 +1,236 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "ima_adpcm_common.h" +#include "support_formats.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; + +#define GET_SAMPLE_COUNT(s) ((((s) << 3) / fmt->channels - 22) / fmt->bitspersample + 1) + +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(uint32_t seek_val, int seek_mode, + uint8_t *(*read_buffer)(size_t *realsize)) +{ + static struct pcm_pos newpos; + uint32_t chunkbits = blockbits; + uint32_t seekblocks = (seek_mode == PCM_SEEK_TIME)? + ((uint64_t)seek_val * ci->id3->frequency) + / (1000LL * fmt->samplesperblock) : + ((seek_val << 3) - 2) / blockbits; + uint32_t seekbits = seekblocks * blockbits + 2; + + (void)read_buffer; + + newpos.pos = seekbits >> 3; + newpos.samples = seekblocks * 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 = ((size_t)fmt->chunksize == inbufsize) ? fmt->samplesperblock : + GET_SAMPLE_COUNT(inbufsize); + int32_t init_pcmdata[2]; + int8_t init_index[2]; + static uint8_t lastbyte = 0; + + validity_bits = 8; + *outbufcount = count; + + /* 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] << IMA_ADPCM_INC_DEPTH; + if (ch > 0) + *outbuf++ = init_pcmdata[1] << IMA_ADPCM_INC_DEPTH; + + set_decode_parameters(fmt->channels, init_pcmdata, init_index); + + /* read block data */ + while (--count > 0) + { + *outbuf++ = create_pcmdata(0, get_data(&inbuf, fmt->bitspersample)) + << IMA_ADPCM_INC_DEPTH; + if (ch > 0) + *outbuf++ = create_pcmdata(ch, get_data(&inbuf, fmt->bitspersample)) + << IMA_ADPCM_INC_DEPTH; + } + + 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/lib/rbcodec/codecs/libpcm/yamaha_adpcm.c b/lib/rbcodec/codecs/libpcm/yamaha_adpcm.c new file mode 100644 index 0000000000..c67fe7524a --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/yamaha_adpcm.c @@ -0,0 +1,250 @@ +/*************************************************************************** + * __________ __ ___. + * 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 "adpcm_seek.h" +#include "support_formats.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->channels == 0) + { + DEBUGF("CODEC_ERROR: channels is 0\n"); + return false; + } + + 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 ) << (PCM_OUTPUT_DEPTH - 16); + *outbuf++ = create_pcmdata(ch, *inbuf >> 4) << (PCM_OUTPUT_DEPTH - 16); + 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(uint32_t seek_val, int seek_mode, + uint8_t *(*read_buffer)(size_t *realsize)) +{ + static struct pcm_pos newpos; + uint32_t new_count = (seek_mode == PCM_SEEK_TIME)? + ((uint64_t)seek_val * ci->id3->frequency / 1000LL) + / (blocksperchunk * fmt->samplesperblock) : + seek_val / (unsigned long)fmt->chunksize; + + 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; +} -- cgit v1.2.3