diff options
author | Sean Bartell <wingedtachikoma@gmail.com> | 2011-06-25 21:32:25 -0400 |
---|---|---|
committer | Nils Wallménius <nils@rockbox.org> | 2012-04-25 22:13:20 +0200 |
commit | f40bfc9267b13b54e6379dfe7539447662879d24 (patch) | |
tree | 9b20069d5e62809ff434061ad730096836f916f2 /lib/rbcodec/codecs/libpcm/swf_adpcm.c | |
parent | a0009907de7a0107d49040d8a180f140e2eff299 (diff) | |
download | rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.tar.gz rockbox-f40bfc9267b13b54e6379dfe7539447662879d24.zip |
Add codecs to librbcodec.
Change-Id: Id7f4717d51ed02d67cb9f9cb3c0ada4a81843f97
Reviewed-on: http://gerrit.rockbox.org/137
Reviewed-by: Nils Wallménius <nils@rockbox.org>
Tested-by: Nils Wallménius <nils@rockbox.org>
Diffstat (limited to 'lib/rbcodec/codecs/libpcm/swf_adpcm.c')
-rw-r--r-- | lib/rbcodec/codecs/libpcm/swf_adpcm.c | 236 |
1 files changed, 236 insertions, 0 deletions
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 @@ | |||
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 "ima_adpcm_common.h" | ||
23 | #include "support_formats.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 | */ | ||
38 | static const int index_table[4] ICONST_ATTR = { | ||
39 | -1, -1, 2, 4, | ||
40 | }; | ||
41 | |||
42 | static int validity_bits = 8; | ||
43 | static bool first_block = true; | ||
44 | static int blockbits = 0; | ||
45 | static int lastbytebits = 0; | ||
46 | static bool after_seek = false; | ||
47 | |||
48 | static struct pcm_format *fmt; | ||
49 | |||
50 | #define GET_SAMPLE_COUNT(s) ((((s) << 3) / fmt->channels - 22) / fmt->bitspersample + 1) | ||
51 | |||
52 | static bool set_format(struct pcm_format *format) | ||
53 | { | ||
54 | fmt = format; | ||
55 | |||
56 | if (fmt->bitspersample < 2 || fmt->bitspersample > 5) | ||
57 | { | ||
58 | DEBUGF("CODEC_ERROR: swf adpcm must be 2, 3, 4 or 5 bitspersample: %d\n", | ||
59 | fmt->bitspersample); | ||
60 | return false; | ||
61 | } | ||
62 | |||
63 | if (fmt->samplesperblock == 0) | ||
64 | fmt->samplesperblock = (((fmt->blockalign << 3) - 2) / fmt->channels - 22) | ||
65 | / fmt->bitspersample + 1; | ||
66 | |||
67 | blockbits = ((fmt->samplesperblock - 1) * fmt->bitspersample + 22) * fmt->channels; | ||
68 | |||
69 | /* | ||
70 | * chunksize = about 93 [ms] data (frequency:44.1kHz, 4096 [sample/block]) | ||
71 | * chunksize changes depending upon the position of block. | ||
72 | */ | ||
73 | fmt->chunksize = (blockbits + 9) >> 3; | ||
74 | |||
75 | /* initialize for ima adpcm common functions */ | ||
76 | if (fmt->bitspersample == 3) | ||
77 | init_ima_adpcm_decoder(fmt->bitspersample, index_table); | ||
78 | else | ||
79 | init_ima_adpcm_decoder(fmt->bitspersample, NULL); | ||
80 | |||
81 | return true; | ||
82 | } | ||
83 | |||
84 | static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, | ||
85 | uint8_t *(*read_buffer)(size_t *realsize)) | ||
86 | { | ||
87 | static struct pcm_pos newpos; | ||
88 | uint32_t chunkbits = blockbits; | ||
89 | uint32_t seekblocks = (seek_mode == PCM_SEEK_TIME)? | ||
90 | ((uint64_t)seek_val * ci->id3->frequency) | ||
91 | / (1000LL * fmt->samplesperblock) : | ||
92 | ((seek_val << 3) - 2) / blockbits; | ||
93 | uint32_t seekbits = seekblocks * blockbits + 2; | ||
94 | |||
95 | (void)read_buffer; | ||
96 | |||
97 | newpos.pos = seekbits >> 3; | ||
98 | newpos.samples = seekblocks * fmt->samplesperblock; | ||
99 | |||
100 | if (newpos.pos == 0) | ||
101 | { | ||
102 | first_block = true; | ||
103 | lastbytebits = 0; | ||
104 | } | ||
105 | else | ||
106 | { | ||
107 | first_block = false; | ||
108 | lastbytebits = seekbits & 0x07; | ||
109 | if (lastbytebits != 0) | ||
110 | chunkbits -= (8 - lastbytebits); | ||
111 | } | ||
112 | |||
113 | /* calculates next read bytes */ | ||
114 | fmt->chunksize = (chunkbits >> 3) + (((chunkbits & 0x07) > 0)?1:0) | ||
115 | + ((lastbytebits > 0)?1:0); | ||
116 | |||
117 | after_seek = true; | ||
118 | return &newpos; | ||
119 | } | ||
120 | |||
121 | static uint8_t get_data(const uint8_t **buf, int bit) | ||
122 | { | ||
123 | uint8_t res = 0; | ||
124 | uint8_t mask = (1 << bit) - 1; | ||
125 | |||
126 | if (validity_bits >= bit) | ||
127 | { | ||
128 | validity_bits -= bit; | ||
129 | return (**buf >> validity_bits) & mask; | ||
130 | } | ||
131 | |||
132 | if (validity_bits > 0) | ||
133 | res = **buf << (bit - validity_bits); | ||
134 | |||
135 | validity_bits += 8 - bit; | ||
136 | res = (res | (*(++(*buf)) >> validity_bits)) & mask; | ||
137 | return res; | ||
138 | } | ||
139 | |||
140 | static int decode(const uint8_t *inbuf, size_t inbufsize, | ||
141 | int32_t *outbuf, int *outbufcount) | ||
142 | { | ||
143 | int ch; | ||
144 | int adpcm_code_size; | ||
145 | int count = ((size_t)fmt->chunksize == inbufsize) ? fmt->samplesperblock : | ||
146 | GET_SAMPLE_COUNT(inbufsize); | ||
147 | int32_t init_pcmdata[2]; | ||
148 | int8_t init_index[2]; | ||
149 | static uint8_t lastbyte = 0; | ||
150 | |||
151 | validity_bits = 8; | ||
152 | *outbufcount = count; | ||
153 | |||
154 | /* read block header */ | ||
155 | ch = fmt->channels - 1; | ||
156 | if (first_block) | ||
157 | { | ||
158 | adpcm_code_size = get_data(&inbuf, 2) + 2; | ||
159 | if (fmt->bitspersample != adpcm_code_size) | ||
160 | { | ||
161 | DEBUGF("CODEC_ERROR: swf adpcm different adpcm code size=%d != %d\n", | ||
162 | adpcm_code_size, fmt->bitspersample); | ||
163 | return CODEC_ERROR; | ||
164 | } | ||
165 | init_pcmdata[0] = (get_data(&inbuf, 8) << 8) | get_data(&inbuf, 8); | ||
166 | |||
167 | lastbytebits = 0; | ||
168 | first_block = false; | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | if (after_seek && lastbytebits > 0) | ||
173 | { | ||
174 | lastbyte = *inbuf++; | ||
175 | after_seek = false; | ||
176 | } | ||
177 | if (lastbytebits > 0) | ||
178 | init_pcmdata[0] = ((lastbyte << (8 + lastbytebits)) | | ||
179 | (get_data(&inbuf, 8) << lastbytebits) | | ||
180 | get_data(&inbuf, lastbytebits)) & 65535; | ||
181 | else | ||
182 | init_pcmdata[0] = (get_data(&inbuf, 8) << 8) | get_data(&inbuf, 8); | ||
183 | } | ||
184 | after_seek = false; | ||
185 | |||
186 | init_index[0] = get_data(&inbuf, 6); | ||
187 | if (init_pcmdata[0] > 32767) | ||
188 | init_pcmdata[0] -= 65536; | ||
189 | |||
190 | if (ch > 0) | ||
191 | { | ||
192 | init_pcmdata[1] = (get_data(&inbuf, 8) << 8) | get_data(&inbuf, 8); | ||
193 | init_index[1] = get_data(&inbuf, 6); | ||
194 | if (init_pcmdata[1] > 32767) | ||
195 | init_pcmdata[1] -= 65536; | ||
196 | } | ||
197 | |||
198 | *outbuf++ = init_pcmdata[0] << IMA_ADPCM_INC_DEPTH; | ||
199 | if (ch > 0) | ||
200 | *outbuf++ = init_pcmdata[1] << IMA_ADPCM_INC_DEPTH; | ||
201 | |||
202 | set_decode_parameters(fmt->channels, init_pcmdata, init_index); | ||
203 | |||
204 | /* read block data */ | ||
205 | while (--count > 0) | ||
206 | { | ||
207 | *outbuf++ = create_pcmdata(0, get_data(&inbuf, fmt->bitspersample)) | ||
208 | << IMA_ADPCM_INC_DEPTH; | ||
209 | if (ch > 0) | ||
210 | *outbuf++ = create_pcmdata(ch, get_data(&inbuf, fmt->bitspersample)) | ||
211 | << IMA_ADPCM_INC_DEPTH; | ||
212 | } | ||
213 | |||
214 | lastbyte = *inbuf; | ||
215 | lastbytebits = (8 - validity_bits) & 0x07; | ||
216 | |||
217 | /* calculates next read bytes */ | ||
218 | fmt->chunksize = (blockbits - validity_bits + 7) >> 3; | ||
219 | |||
220 | return CODEC_OK; | ||
221 | } | ||
222 | |||
223 | static const struct pcm_codec codec = { | ||
224 | set_format, | ||
225 | get_seek_pos, | ||
226 | decode, | ||
227 | }; | ||
228 | |||
229 | const struct pcm_codec *get_swf_adpcm_codec(void) | ||
230 | { | ||
231 | first_block = true; | ||
232 | lastbytebits = 0; | ||
233 | after_seek = false; | ||
234 | |||
235 | return &codec; | ||
236 | } | ||