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/dialogic_oki_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/dialogic_oki_adpcm.c')
-rw-r--r-- | lib/rbcodec/codecs/libpcm/dialogic_oki_adpcm.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libpcm/dialogic_oki_adpcm.c b/lib/rbcodec/codecs/libpcm/dialogic_oki_adpcm.c new file mode 100644 index 0000000000..60090aaa89 --- /dev/null +++ b/lib/rbcodec/codecs/libpcm/dialogic_oki_adpcm.c | |||
@@ -0,0 +1,183 @@ | |||
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 | * Dialogic OKI ADPCM | ||
27 | * | ||
28 | * References | ||
29 | * [1] Dialogic Corporation, Dialogic ADPCM Algorithm, 1988 | ||
30 | * [2] MultimediaWiki, Dialogic IMA ADPCM, URL:http://wiki.multimedia.cx/index.php?title=Dialogic_IMA_ADPCM | ||
31 | * [3] sox source code, src/adpcms.c | ||
32 | * [4] Tetsuya Isaki, NetBSD:/sys/dev/audio.c, http://www.tri-tree.gr.jp/~isaki/NetBSD/src/sys/dev/ic/msm6258.c.html | ||
33 | */ | ||
34 | |||
35 | static const uint16_t step_table[] ICONST_ATTR = { | ||
36 | 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, | ||
37 | 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, | ||
38 | 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, | ||
39 | 876, 963, 1060, 1166, 1282, 1411, 1552, | ||
40 | }; | ||
41 | |||
42 | static const int index_table[] ICONST_ATTR = { | ||
43 | -1, -1, -1, -1, 2, 4, 6, 8 | ||
44 | }; | ||
45 | |||
46 | static struct adpcm_data cur_data; | ||
47 | static int blocksperchunk; | ||
48 | |||
49 | static struct pcm_format *fmt; | ||
50 | |||
51 | static bool set_format(struct pcm_format *format) | ||
52 | { | ||
53 | uint32_t max_chunk_count; | ||
54 | |||
55 | fmt = format; | ||
56 | |||
57 | if (fmt->bitspersample != 4) | ||
58 | { | ||
59 | DEBUGF("CODEC_ERROR: dialogic oki adpcm must be 4 bitspersample: %d\n", | ||
60 | fmt->bitspersample); | ||
61 | return false; | ||
62 | } | ||
63 | |||
64 | if (fmt->channels != 1) | ||
65 | { | ||
66 | DEBUGF("CODEC_ERROR: dialogic oki adpcm must be monaural\n"); | ||
67 | return false; | ||
68 | } | ||
69 | |||
70 | /* blockalign = 2 samples */ | ||
71 | fmt->blockalign = 1; | ||
72 | fmt->samplesperblock = 2; | ||
73 | |||
74 | /* chunksize = about 1/32[sec] data */ | ||
75 | blocksperchunk = ci->id3->frequency >> 6; | ||
76 | fmt->chunksize = blocksperchunk * fmt->blockalign; | ||
77 | |||
78 | max_chunk_count = (uint64_t)ci->id3->length * ci->id3->frequency | ||
79 | / (2000LL * fmt->chunksize); | ||
80 | |||
81 | /* initialize seek table */ | ||
82 | init_seek_table(max_chunk_count); | ||
83 | /* add first data */ | ||
84 | add_adpcm_data(&cur_data); | ||
85 | |||
86 | return true; | ||
87 | } | ||
88 | |||
89 | static int16_t create_pcmdata(uint8_t nibble) | ||
90 | { | ||
91 | int16_t delta; | ||
92 | int16_t index = cur_data.step[0]; | ||
93 | int16_t step = step_table[index]; | ||
94 | |||
95 | delta = (step >> 3); | ||
96 | if (nibble & 4) delta += step; | ||
97 | if (nibble & 2) delta += (step >> 1); | ||
98 | if (nibble & 1) delta += (step >> 2); | ||
99 | |||
100 | if (nibble & 0x08) | ||
101 | cur_data.pcmdata[0] -= delta; | ||
102 | else | ||
103 | cur_data.pcmdata[0] += delta; | ||
104 | |||
105 | CLIP(cur_data.pcmdata[0], -2048, 2047); | ||
106 | |||
107 | index += index_table[nibble & 0x07]; | ||
108 | CLIP(index, 0, 48); | ||
109 | cur_data.step[0] = index; | ||
110 | |||
111 | return cur_data.pcmdata[0]; | ||
112 | } | ||
113 | |||
114 | static int decode(const uint8_t *inbuf, size_t inbufsize, | ||
115 | int32_t *outbuf, int *outbufcount) | ||
116 | { | ||
117 | size_t nsamples = 0; | ||
118 | |||
119 | while (inbufsize) | ||
120 | { | ||
121 | *outbuf++ = create_pcmdata(*inbuf >> 4) << (PCM_OUTPUT_DEPTH - 12); | ||
122 | *outbuf++ = create_pcmdata(*inbuf ) << (PCM_OUTPUT_DEPTH - 12); | ||
123 | nsamples += 2; | ||
124 | |||
125 | inbuf++; | ||
126 | inbufsize--; | ||
127 | } | ||
128 | |||
129 | *outbufcount = nsamples; | ||
130 | add_adpcm_data(&cur_data); | ||
131 | |||
132 | return CODEC_OK; | ||
133 | } | ||
134 | |||
135 | static int decode_for_seek(const uint8_t *inbuf, size_t inbufsize) | ||
136 | { | ||
137 | while (inbufsize) | ||
138 | { | ||
139 | create_pcmdata(*inbuf >> 4); | ||
140 | create_pcmdata(*inbuf ); | ||
141 | |||
142 | inbuf++; | ||
143 | inbufsize--; | ||
144 | } | ||
145 | |||
146 | add_adpcm_data(&cur_data); | ||
147 | |||
148 | return CODEC_OK; | ||
149 | } | ||
150 | |||
151 | static struct pcm_pos *get_seek_pos(uint32_t seek_val, int seek_mode, | ||
152 | uint8_t *(*read_buffer)(size_t *realsize)) | ||
153 | { | ||
154 | static struct pcm_pos newpos; | ||
155 | uint32_t seek_count = (seek_mode == PCM_SEEK_TIME)? | ||
156 | ((uint64_t)seek_val * ci->id3->frequency / 1000LL) | ||
157 | / (blocksperchunk * fmt->samplesperblock) : | ||
158 | seek_val / (unsigned long)fmt->chunksize; | ||
159 | uint32_t new_count = seek(seek_count, &cur_data, read_buffer, &decode_for_seek); | ||
160 | |||
161 | newpos.pos = new_count * fmt->chunksize; | ||
162 | newpos.samples = new_count * blocksperchunk * fmt->samplesperblock; | ||
163 | return &newpos; | ||
164 | } | ||
165 | |||
166 | static const struct pcm_codec codec = { | ||
167 | set_format, | ||
168 | get_seek_pos, | ||
169 | decode, | ||
170 | }; | ||
171 | |||
172 | const struct pcm_codec *get_dialogic_oki_adpcm_codec(void) | ||
173 | { | ||
174 | /* | ||
175 | * initialize first pcm data, step index | ||
176 | * because the dialogic oki adpcm is always monaural, | ||
177 | * pcmdata[1], step[1] do not use. | ||
178 | */ | ||
179 | cur_data.pcmdata[0] = 0; | ||
180 | cur_data.step[0] = 0; | ||
181 | |||
182 | return &codec; | ||
183 | } | ||