/*************************************************************************** * __________ __ ___. * 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; }