summaryrefslogtreecommitdiff
path: root/apps/codecs/libpcm/swf_adpcm.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/codecs/libpcm/swf_adpcm.c')
-rw-r--r--apps/codecs/libpcm/swf_adpcm.c233
1 files changed, 233 insertions, 0 deletions
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 @@
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 "pcm_common.h"
23#include "ima_adpcm_common.h"
24
25/*
26 * Adobe SWF ADPCM
27 *
28 * References
29 * [1] Adobe, SWF File Format Specification Version 10, 2008
30 * [2] Jack Jansen, adpcm.c in adpcm.zip
31 * [3] ffmpeg source code, libavcodec/adpcm.c
32 */
33
34/* step index table when bitspersample is 3.
35 * (when bitspersample is 2, 4, 5, step index table uses the table
36 * which is defined ima_adpcm_common.c.)
37 */
38static const int index_table[4] ICONST_ATTR = {
39 -1, -1, 2, 4,
40};
41
42static int validity_bits = 8;
43static bool first_block = true;
44static int blockbits = 0;
45static int lastbytebits = 0;
46static bool after_seek = false;
47
48static struct pcm_format *fmt;
49
50static bool set_format(struct pcm_format *format)
51{
52 fmt = format;
53
54 if (fmt->bitspersample < 2 || fmt->bitspersample > 5)
55 {
56 DEBUGF("CODEC_ERROR: swf adpcm must be 2, 3, 4 or 5 bitspersample: %d\n",
57 fmt->bitspersample);
58 return false;
59 }
60
61 if (fmt->samplesperblock == 0)
62 fmt->samplesperblock = (((fmt->blockalign << 3) - 2) / fmt->channels - 22)
63 / fmt->bitspersample + 1;
64
65 blockbits = ((fmt->samplesperblock - 1) * fmt->bitspersample + 22) * fmt->channels;
66
67 /*
68 * chunksize = about 93 [ms] data (frequency:44.1kHz, 4096 [sample/block])
69 * chunksize changes depending upon the position of block.
70 */
71 fmt->chunksize = (blockbits + 9) >> 3;
72
73 /* initialize for ima adpcm common functions */
74 if (fmt->bitspersample == 3)
75 init_ima_adpcm_decoder(fmt->bitspersample, index_table);
76 else
77 init_ima_adpcm_decoder(fmt->bitspersample, NULL);
78
79 return true;
80}
81
82static struct pcm_pos *get_seek_pos(long seek_time,
83 uint8_t *(*read_buffer)(size_t *realsize))
84{
85 static struct pcm_pos newpos;
86 uint32_t chunkbits = blockbits;
87 uint32_t seekbits = (((uint64_t)seek_time * ci->id3->frequency)
88 / (1000LL * fmt->samplesperblock)) * blockbits + 2;
89
90 (void)read_buffer;
91
92 newpos.pos = seekbits >> 3;
93 newpos.samples = (((uint64_t)seek_time * ci->id3->frequency)
94 / (1000LL * fmt->samplesperblock))
95 * fmt->samplesperblock;
96
97 if (newpos.pos == 0)
98 {
99 first_block = true;
100 lastbytebits = 0;
101 }
102 else
103 {
104 first_block = false;
105 lastbytebits = seekbits & 0x07;
106 if (lastbytebits != 0)
107 chunkbits -= (8 - lastbytebits);
108 }
109
110 /* calculates next read bytes */
111 fmt->chunksize = (chunkbits >> 3) + (((chunkbits & 0x07) > 0)?1:0)
112 + ((lastbytebits > 0)?1:0);
113
114 after_seek = true;
115 return &newpos;
116}
117
118static uint8_t get_data(const uint8_t **buf, int bit)
119{
120 uint8_t res = 0;
121 uint8_t mask = (1 << bit) - 1;
122
123 if (validity_bits >= bit)
124 {
125 validity_bits -= bit;
126 return (**buf >> validity_bits) & mask;
127 }
128
129 if (validity_bits > 0)
130 res = **buf << (bit - validity_bits);
131
132 validity_bits += 8 - bit;
133 res = (res | (*(++(*buf)) >> validity_bits)) & mask;
134 return res;
135}
136
137static int decode(const uint8_t *inbuf, size_t inbufsize,
138 int32_t *outbuf, int *outbufcount)
139{
140 int ch;
141 int adpcm_code_size;
142 int count = fmt->samplesperblock;
143 int32_t init_pcmdata[2];
144 int8_t init_index[2];
145 static uint8_t lastbyte = 0;
146
147 (void)inbufsize;
148
149 validity_bits = 8;
150
151 /* read block header */
152 ch = fmt->channels - 1;
153 if (first_block)
154 {
155 adpcm_code_size = get_data(&inbuf, 2) + 2;
156 if (fmt->bitspersample != adpcm_code_size)
157 {
158 DEBUGF("CODEC_ERROR: swf adpcm different adpcm code size=%d != %d\n",
159 adpcm_code_size, fmt->bitspersample);
160 return CODEC_ERROR;
161 }
162 init_pcmdata[0] = (get_data(&inbuf, 8) << 8) | get_data(&inbuf, 8);
163
164 lastbytebits = 0;
165 first_block = false;
166 }
167 else
168 {
169 if (after_seek && lastbytebits > 0)
170 {
171 lastbyte = *inbuf++;
172 after_seek = false;
173 }
174 if (lastbytebits > 0)
175 init_pcmdata[0] = ((lastbyte << (8 + lastbytebits)) |
176 (get_data(&inbuf, 8) << lastbytebits) |
177 get_data(&inbuf, lastbytebits)) & 65535;
178 else
179 init_pcmdata[0] = (get_data(&inbuf, 8) << 8) | get_data(&inbuf, 8);
180 }
181 after_seek = false;
182
183 init_index[0] = get_data(&inbuf, 6);
184 if (init_pcmdata[0] > 32767)
185 init_pcmdata[0] -= 65536;
186
187 if (ch > 0)
188 {
189 init_pcmdata[1] = (get_data(&inbuf, 8) << 8) | get_data(&inbuf, 8);
190 init_index[1] = get_data(&inbuf, 6);
191 if (init_pcmdata[1] > 32767)
192 init_pcmdata[1] -= 65536;
193 }
194
195 *outbuf++ = init_pcmdata[0] << 13;
196 if (ch > 0)
197 *outbuf++ = init_pcmdata[1] << 13;
198
199 set_decode_parameters(fmt->channels, init_pcmdata, init_index);
200
201 /* read block data */
202 while (--count > 0)
203 {
204 *outbuf++ = create_pcmdata(0, get_data(&inbuf, fmt->bitspersample)) << 13;
205 if (ch > 0)
206 *outbuf++ = create_pcmdata(ch, get_data(&inbuf, fmt->bitspersample)) << 13;
207 }
208
209 *outbufcount = fmt->samplesperblock;
210
211 lastbyte = *inbuf;
212 lastbytebits = (8 - validity_bits) & 0x07;
213
214 /* calculates next read bytes */
215 fmt->chunksize = (blockbits - validity_bits + 7) >> 3;
216
217 return CODEC_OK;
218}
219
220static const struct pcm_codec codec = {
221 set_format,
222 get_seek_pos,
223 decode,
224 };
225
226const struct pcm_codec *get_swf_adpcm_codec(void)
227{
228 first_block = true;
229 lastbytebits = 0;
230 after_seek = false;
231
232 return &codec;
233}