diff options
author | Yoshihisa Uchida <uchida@rockbox.org> | 2010-02-20 02:04:56 +0000 |
---|---|---|
committer | Yoshihisa Uchida <uchida@rockbox.org> | 2010-02-20 02:04:56 +0000 |
commit | 3716abba9274f544dd31cdf4e6c83a845bf2a801 (patch) | |
tree | 07bca7cdd3e40bb176e938fcb5ea8eb2f7c3e9cb /apps/codecs/libpcm/ms_adpcm.c | |
parent | 93caf52db5e0afe826278c148936bdfa563724f1 (diff) | |
download | rockbox-3716abba9274f544dd31cdf4e6c83a845bf2a801.tar.gz rockbox-3716abba9274f544dd31cdf4e6c83a845bf2a801.zip |
commit FS#10424 and FS#10425
- wav(RIFF) supports Microsoft ADPCM, Dialogic OKI ADPCM, YAMAHA ADPCM, Adobe SWF ADPCM.
- AIFF supports QuickTime IMA ADPCM.
- DVI ADPCM(IMA ADPCM) reworks.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24782 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/codecs/libpcm/ms_adpcm.c')
-rw-r--r-- | apps/codecs/libpcm/ms_adpcm.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/apps/codecs/libpcm/ms_adpcm.c b/apps/codecs/libpcm/ms_adpcm.c new file mode 100644 index 0000000000..899ecc2045 --- /dev/null +++ b/apps/codecs/libpcm/ms_adpcm.c | |||
@@ -0,0 +1,166 @@ | |||
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 | |||
24 | /* | ||
25 | * Microsoft ADPCM | ||
26 | * | ||
27 | * References | ||
28 | * [1] Microsoft, New Multimedia Data Types and Data Techniques Revision 3.0, 1994 | ||
29 | * [2] MulitimediaWiki, Microsoft ADPCM, 2006 | ||
30 | * (http://wiki.multimedia.cx/index.php?title=Microsoft_ADPCM) | ||
31 | * [3] ffmpeg source code, libavcodec/adpcm.c | ||
32 | */ | ||
33 | |||
34 | #define ADPCM_NUM_COEFF 7 | ||
35 | |||
36 | static int16_t dec_coeff[2][2]; | ||
37 | static uint16_t delta[2]; | ||
38 | static int16_t sample[2][2]; | ||
39 | |||
40 | static struct pcm_format *fmt; | ||
41 | |||
42 | static const int16_t adaptation_table[] ICONST_ATTR = { | ||
43 | 230, 230, 230, 230, 307, 409, 512, 614, | ||
44 | 768, 614, 512, 409, 307, 230, 230, 230 | ||
45 | }; | ||
46 | |||
47 | static bool set_format(struct pcm_format *format) | ||
48 | { | ||
49 | fmt = format; | ||
50 | |||
51 | if (fmt->bitspersample != 4) | ||
52 | { | ||
53 | DEBUGF("CODEC_ERROR: microsoft adpcm must be 4 bitspersample: %d\n", | ||
54 | fmt->bitspersample); | ||
55 | return false; | ||
56 | } | ||
57 | |||
58 | fmt->chunksize = fmt->blockalign; | ||
59 | |||
60 | return true; | ||
61 | } | ||
62 | |||
63 | static struct pcm_pos *get_seek_pos(long seek_time, | ||
64 | uint8_t *(*read_buffer)(size_t *realsize)) | ||
65 | { | ||
66 | static struct pcm_pos newpos; | ||
67 | uint32_t newblock = ((uint64_t)seek_time * ci->id3->frequency) | ||
68 | / (1000LL * fmt->samplesperblock); | ||
69 | |||
70 | (void)read_buffer; | ||
71 | newpos.pos = newblock * fmt->blockalign; | ||
72 | newpos.samples = newblock * fmt->samplesperblock; | ||
73 | return &newpos; | ||
74 | } | ||
75 | |||
76 | static int16_t create_pcmdata(int ch, uint8_t nibble) | ||
77 | { | ||
78 | int32_t pcmdata; | ||
79 | |||
80 | pcmdata = (sample[ch][0] * dec_coeff[ch][0] + | ||
81 | sample[ch][1] * dec_coeff[ch][1]) / 256; | ||
82 | pcmdata += (delta[ch] * (nibble - ((nibble & 0x8) << 1))); | ||
83 | |||
84 | CLIP(pcmdata, -32768, 32767); | ||
85 | |||
86 | sample[ch][1] = sample[ch][0]; | ||
87 | sample[ch][0] = pcmdata; | ||
88 | |||
89 | delta[ch] = (adaptation_table[nibble] * delta[ch]) >> 8; | ||
90 | if (delta[ch] < 16) | ||
91 | delta[ch] = 16; | ||
92 | |||
93 | return (int16_t)pcmdata; | ||
94 | } | ||
95 | |||
96 | static int decode(const uint8_t *inbuf, size_t inbufsize, | ||
97 | int32_t *outbuf, int *outbufcount) | ||
98 | { | ||
99 | int ch; | ||
100 | size_t nsamples = 0; | ||
101 | int size = fmt->samplesperblock; | ||
102 | |||
103 | /* read block header */ | ||
104 | for (ch = 0; ch < fmt->channels; ch++) | ||
105 | { | ||
106 | if (*inbuf >= ADPCM_NUM_COEFF) | ||
107 | { | ||
108 | DEBUGF("CODEC_ERROR: microsoft adpcm illegal initial coeff=%d > 7\n", | ||
109 | *inbuf); | ||
110 | return CODEC_ERROR; | ||
111 | } | ||
112 | dec_coeff[ch][0] = fmt->coeffs[*inbuf][0]; | ||
113 | dec_coeff[ch][1] = fmt->coeffs[*inbuf][1]; | ||
114 | inbuf++; | ||
115 | } | ||
116 | |||
117 | for (ch = 0; ch < fmt->channels; ch++) | ||
118 | { | ||
119 | delta[ch] = inbuf[0] | (SE(inbuf[1]) << 8); | ||
120 | inbuf += 2; | ||
121 | } | ||
122 | |||
123 | for (ch = 0; ch < fmt->channels; ch++) | ||
124 | { | ||
125 | sample[ch][0] = inbuf[0] | (SE(inbuf[1]) << 8); | ||
126 | inbuf += 2; | ||
127 | } | ||
128 | |||
129 | for (ch = 0; ch < fmt->channels; ch++) | ||
130 | { | ||
131 | sample[ch][1] = inbuf[0] | (SE(inbuf[1]) << 8); | ||
132 | inbuf += 2; | ||
133 | } | ||
134 | |||
135 | inbufsize -= 7 * fmt->channels; | ||
136 | ch = fmt->channels - 1; | ||
137 | |||
138 | while (size-- > 0) | ||
139 | { | ||
140 | *outbuf++ = create_pcmdata(0, *inbuf >> 4 ) << 13; | ||
141 | *outbuf++ = create_pcmdata(ch, *inbuf & 0xf) << 13; | ||
142 | nsamples += 2; | ||
143 | |||
144 | inbuf++; | ||
145 | inbufsize--; | ||
146 | if (inbufsize <= 0) | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | if (fmt->channels == 2) | ||
151 | nsamples >>= 1; | ||
152 | *outbufcount = nsamples; | ||
153 | |||
154 | return CODEC_OK; | ||
155 | } | ||
156 | |||
157 | static const struct pcm_codec codec = { | ||
158 | set_format, | ||
159 | get_seek_pos, | ||
160 | decode, | ||
161 | }; | ||
162 | |||
163 | const struct pcm_codec *get_ms_adpcm_codec(void) | ||
164 | { | ||
165 | return &codec; | ||
166 | } | ||