summaryrefslogtreecommitdiff
path: root/lib/rbcodec/codecs/libpcm/yamaha_adpcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rbcodec/codecs/libpcm/yamaha_adpcm.c')
-rw-r--r--lib/rbcodec/codecs/libpcm/yamaha_adpcm.c250
1 files changed, 250 insertions, 0 deletions
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Yoshihisa Uchida
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include "codeclib.h"
22#include "adpcm_seek.h"
23#include "support_formats.h"
24
25/*
26 * YAMAHA ADPCM
27 *
28 * References
29 * [1] YAMAHA, YAMAHA ADPCM ACM Driver Version 1.0.0.0, 2005
30 * [2] BlendWorks, YM2608 ADPCM,
31 * http://web.archive.org/web/20050208190547/www.memb.jp/~dearna/ma/ym2608/adpcm.html
32 * [3] Naoyuki Sawa, ADPCM no shikumi #1,
33 * http://www.piece-me.org/piece-lab/adpcm/adpcm1.html
34 * [4] ffmpeg source code, libavcodec/adpcm.c
35 */
36
37/* ADPCM data block layout
38 *
39 * when the block header exists. (for example, encoding by YAMAHA ADPCM ACM Driver)
40 * blockAlign = (frequency / 60 + 4) * channels.
41 *
42 * block
43 * <Mono> (channels = 1)
44 * int16_t first value (Little endian)
45 * uint16_t first predictor (Little endian)
46 * uint8_t ADPCM data (1st data: 0-3 bit, 2nd data: 4-7 bit)
47 * ....
48 *
49 * <Stereo> (channels = 2)
50 * int16_t Left channel first value (Little endian)
51 * uint16_t Left channel first predictor (Little endian)
52 * int16_t Right channel first value (Little endian)
53 * uint16_t Right channel first predictor (Little endian)
54 * uint8_t ADPCM data (Left channel: 0-3 bit, Right channel: 4-7 bit)
55 * ....
56 *
57 * when the block header does not exist. (for example, encoding by ffmpeg)
58 * blockAlign = 8000
59 *
60 * block
61 * <Mono> (channels = 1)
62 * uint8_t ADPCM data (1st data: 0-3 bit, 2nd data: 4-7 bit)
63 * ....
64 *
65 * <Stereo> (channels = 2)
66 * uint8_t ADPCM data (Left channel: 0-3 bit, Right channel: 4-7 bit)
67 * ....
68 */
69
70static const int32_t amplification_table[] ICONST_ATTR = {
71 230, 230, 230, 230, 307, 409, 512, 614, 230, 230, 230, 230, 307, 409, 512, 614
72};
73
74static bool has_block_header = false;
75
76static struct adpcm_data cur_data;
77static int blocksperchunk;
78
79static struct pcm_format *fmt;
80
81static bool set_format(struct pcm_format *format)
82{
83 fmt = format;
84
85 if (fmt->channels == 0)
86 {
87 DEBUGF("CODEC_ERROR: channels is 0\n");
88 return false;
89 }
90
91 if (fmt->bitspersample != 4)
92 {
93 DEBUGF("CODEC_ERROR: yamaha adpcm must be 4 bitspersample: %d\n",
94 fmt->bitspersample);
95 return false;
96 }
97
98 /* check exists block header */
99 if (fmt->blockalign == ((ci->id3->frequency / 60) + 4) * fmt->channels)
100 {
101 has_block_header = true;
102
103 /* chunksize = about 1/30 [sec] data */
104 fmt->chunksize = fmt->blockalign;
105 blocksperchunk = 1;
106 }
107 else
108 {
109 uint32_t max_chunk_count;
110
111 has_block_header = false;
112
113 /* blockalign = 2 * channels samples */
114 fmt->blockalign = fmt->channels;
115 fmt->samplesperblock = 2;
116
117 /* chunksize = about 1/32[sec] data */
118 blocksperchunk = ci->id3->frequency >> 6;
119 fmt->chunksize = blocksperchunk * fmt->blockalign;
120
121 max_chunk_count = (uint64_t)ci->id3->length * ci->id3->frequency
122 / (2000LL * fmt->chunksize / fmt->channels);
123
124 /* initialize seek table */
125 init_seek_table(max_chunk_count);
126 /* add first data */
127 add_adpcm_data(&cur_data);
128 }
129
130 return true;
131}
132
133static int16_t create_pcmdata(int ch, uint8_t nibble)
134{
135 int32_t tmp_pcmdata = cur_data.pcmdata[ch];
136 int32_t step = cur_data.step[ch];
137 int32_t delta = step >> 3;
138
139 if (nibble & 4) delta += step;
140 if (nibble & 2) delta += (step >> 1);
141 if (nibble & 1) delta += (step >> 2);
142
143 if (nibble & 0x08)
144 tmp_pcmdata -= delta;
145 else
146 tmp_pcmdata += delta;
147
148 CLIP(tmp_pcmdata, -32768, 32767);
149 cur_data.pcmdata[ch] = tmp_pcmdata;
150
151 step = (step * amplification_table[nibble & 0x07]) >> 8;
152 CLIP(step, 127, 24576);
153 cur_data.step[ch] = step;
154
155 return cur_data.pcmdata[ch];
156}
157
158static int decode(const uint8_t *inbuf, size_t inbufsize,
159 int32_t *outbuf, int *outbufcount)
160{
161 int ch;
162 size_t nsamples = 0;
163
164 /* read block header */
165 if (has_block_header)
166 {
167 for (ch = 0; ch < fmt->channels; ch++)
168 {
169 cur_data.pcmdata[ch] = inbuf[0] | (SE(inbuf[1]) << 8);
170 cur_data.step[ch] = inbuf[2] | (inbuf[3] << 8);
171
172 inbuf += 4;
173 inbufsize -= 4;
174 }
175 }
176
177 /* read block data */
178 ch = fmt->channels - 1;
179 while (inbufsize)
180 {
181 *outbuf++ = create_pcmdata(0, *inbuf ) << (PCM_OUTPUT_DEPTH - 16);
182 *outbuf++ = create_pcmdata(ch, *inbuf >> 4) << (PCM_OUTPUT_DEPTH - 16);
183 nsamples += 2;
184
185 inbuf++;
186 inbufsize--;
187 }
188
189 if (fmt->channels == 2)
190 nsamples >>= 1;
191 *outbufcount = nsamples;
192
193 if (!has_block_header)
194 add_adpcm_data(&cur_data);
195
196 return CODEC_OK;
197}
198
199static int decode_for_seek(const uint8_t *inbuf, size_t inbufsize)
200{
201 int ch = fmt->channels - 1;
202
203 while (inbufsize)
204 {
205 create_pcmdata(0, *inbuf );
206 create_pcmdata(ch, *inbuf >> 4);
207
208 inbuf++;
209 inbufsize--;
210 }
211
212 add_adpcm_data(&cur_data);
213
214 return CODEC_OK;
215}
216
217static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode,
218 uint8_t *(*read_buffer)(size_t *realsize))
219{
220 static struct pcm_pos newpos;
221 uint32_t new_count = (seek_mode == PCM_SEEK_TIME)?
222 ((uint64_t)seek_val * ci->id3->frequency / 1000LL)
223 / (blocksperchunk * fmt->samplesperblock) :
224 seek_val / (unsigned long)fmt->chunksize;
225
226 if (!has_block_header)
227 {
228 new_count = seek(new_count, &cur_data, read_buffer, &decode_for_seek);
229 }
230 newpos.pos = new_count * fmt->chunksize;
231 newpos.samples = new_count * blocksperchunk * fmt->samplesperblock;
232 return &newpos;
233}
234
235static struct pcm_codec codec = {
236 set_format,
237 get_seek_pos,
238 decode,
239 };
240
241const struct pcm_codec *get_yamaha_adpcm_codec(void)
242{
243 /* initialize first step, pcm data */
244 cur_data.pcmdata[0] = 0;
245 cur_data.pcmdata[1] = 0;
246 cur_data.step[0] = 127;
247 cur_data.step[1] = 127;
248
249 return &codec;
250}