stats: improve bit depth reporting [bug #267]
[sox.git] / src / amr.h
blobfe4ef368dfde23b6e032fb7a2c5d865f647e30b1
1 /* File format: AMR (c) 2007 robs@users.sourceforge.net
3 * This library is free software; you can redistribute it and/or modify it
4 * under the terms of the GNU Lesser General Public License as published by
5 * the Free Software Foundation; either version 2.1 of the License, or (at
6 * your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
11 * General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 #include <string.h>
19 #include <math.h>
21 #ifdef AMR_OPENCORE
23 LSX_DLENTRIES_TO_FUNCTIONS(AMR_OPENCORE_FUNC_ENTRIES)
25 typedef struct amr_opencore_funcs {
26 LSX_DLENTRIES_TO_PTRS(AMR_OPENCORE_FUNC_ENTRIES, amr_dl);
27 } amr_opencore_funcs;
29 #endif /* AMR_OPENCORE */
31 #ifdef AMR_VO
33 LSX_DLENTRIES_TO_FUNCTIONS(AMR_VO_FUNC_ENTRIES)
35 typedef struct amr_vo_funcs {
36 LSX_DLENTRIES_TO_PTRS(AMR_VO_FUNC_ENTRIES, amr_dl);
37 } amr_vo_funcs;
39 #endif /* AMR_VO */
41 #define AMR_CALL(p, func, args) ((p)->opencore.func args)
43 #ifdef AMR_VO
44 #define AMR_CALL_ENCODER(p, func, args) ((p)->vo.func args)
45 #else
46 #define AMR_CALL_ENCODER(p, func, args) ((p)->opencore.func args)
47 #endif
49 typedef struct amr_priv_t {
50 void* state;
51 unsigned mode;
52 size_t pcm_index;
53 #ifdef AMR_OPENCORE
54 amr_opencore_funcs opencore;
55 #endif /* AMR_OPENCORE */
56 #ifdef AMR_VO
57 amr_vo_funcs vo;
58 #endif /* AMR_VO */
59 short pcm[AMR_FRAME];
60 } priv_t;
62 #ifdef AMR_OPENCORE
63 static size_t decode_1_frame(sox_format_t * ft)
65 priv_t * p = (priv_t *)ft->priv;
66 size_t n;
67 uint8_t coded[AMR_CODED_MAX];
69 if (lsx_readbuf(ft, &coded[0], (size_t)1) != 1)
70 return AMR_FRAME;
71 n = amr_block_size[(coded[0] >> 3) & 0x0F];
72 if (!n) {
73 lsx_fail("invalid block type");
74 return AMR_FRAME;
76 n--;
77 if (lsx_readbuf(ft, &coded[1], n) != n)
78 return AMR_FRAME;
79 AMR_CALL(p, AmrDecoderDecode, (p->state, coded, p->pcm, 0));
80 return 0;
82 #endif
84 static int openlibrary(priv_t* p, int encoding)
86 int open_library_result;
88 (void)encoding;
89 #ifdef AMR_OPENCORE
90 if (AMR_OPENCORE_ENABLE_ENCODE || !encoding)
92 LSX_DLLIBRARY_TRYOPEN(
94 &p->opencore,
95 amr_dl,
96 AMR_OPENCORE_FUNC_ENTRIES,
97 AMR_OPENCORE_DESC,
98 amr_opencore_library_names,
99 open_library_result);
100 if (!open_library_result)
101 return SOX_SUCCESS;
102 lsx_fail("Unable to open " AMR_OPENCORE_DESC);
103 return SOX_EOF;
105 #endif /* AMR_OPENCORE */
107 #ifdef AMR_VO
108 if (encoding) {
109 LSX_DLLIBRARY_TRYOPEN(
111 &p->vo,
112 amr_dl,
113 AMR_VO_FUNC_ENTRIES,
114 AMR_VO_DESC,
115 amr_vo_library_names,
116 open_library_result);
117 if (!open_library_result)
118 return SOX_SUCCESS;
119 lsx_fail("Unable to open " AMR_VO_DESC);
121 #endif /* AMR_VO */
123 return SOX_EOF;
126 static void closelibrary(priv_t* p)
128 #ifdef AMR_OPENCORE
129 LSX_DLLIBRARY_CLOSE(&p->opencore, amr_dl);
130 #endif
131 #ifdef AMR_VO
132 LSX_DLLIBRARY_CLOSE(&p->vo, amr_dl);
133 #endif
136 #ifdef AMR_OPENCORE
137 static size_t amr_duration_frames(sox_format_t * ft)
139 off_t frame_size, data_start_offset = lsx_tell(ft);
140 size_t frames;
141 uint8_t coded;
143 for (frames = 0; lsx_readbuf(ft, &coded, (size_t)1) == 1; ++frames) {
144 frame_size = amr_block_size[coded >> 3 & 15];
145 if (!frame_size) {
146 lsx_fail("invalid block type");
147 break;
149 if (lsx_seeki(ft, frame_size - 1, SEEK_CUR)) {
150 lsx_fail("seek");
151 break;
154 lsx_debug("frames=%lu", (unsigned long)frames);
155 lsx_seeki(ft, data_start_offset, SEEK_SET);
156 return frames;
158 #endif
160 static int startread(sox_format_t * ft)
162 #if !defined(AMR_OPENCORE)
163 lsx_fail_errno(ft, SOX_EOF, "SoX was compiled without AMR-WB decoding support.");
164 return SOX_EOF;
165 #else
166 priv_t * p = (priv_t *)ft->priv;
167 char buffer[sizeof(amr_magic) - 1];
168 int open_library_result;
170 if (lsx_readchars(ft, buffer, sizeof(buffer)))
171 return SOX_EOF;
172 if (memcmp(buffer, amr_magic, sizeof(buffer))) {
173 lsx_fail_errno(ft, SOX_EHDR, "invalid magic number");
174 return SOX_EOF;
177 open_library_result = openlibrary(p, 0);
178 if (open_library_result != SOX_SUCCESS)
179 return open_library_result;
181 p->pcm_index = AMR_FRAME;
182 p->state = AMR_CALL(p, AmrDecoderInit, ());
183 if (!p->state)
185 closelibrary(p);
186 lsx_fail("AMR decoder failed to initialize.");
187 return SOX_EOF;
190 ft->signal.rate = AMR_RATE;
191 ft->encoding.encoding = AMR_ENCODING;
192 ft->signal.channels = 1;
193 ft->signal.length = ft->signal.length != SOX_IGNORE_LENGTH && ft->seekable?
194 (size_t)(amr_duration_frames(ft) * .02 * ft->signal.rate +.5) : SOX_UNSPEC;
195 return SOX_SUCCESS;
196 #endif
199 #ifdef AMR_OPENCORE
201 static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len)
203 priv_t * p = (priv_t *)ft->priv;
204 size_t done;
206 for (done = 0; done < len; done++) {
207 if (p->pcm_index >= AMR_FRAME)
208 p->pcm_index = decode_1_frame(ft);
209 if (p->pcm_index >= AMR_FRAME)
210 break;
211 *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(p->pcm[p->pcm_index++], ft->clips);
213 return done;
216 static int stopread(sox_format_t * ft)
218 priv_t * p = (priv_t *)ft->priv;
219 AMR_CALL(p, AmrDecoderExit, (p->state));
220 closelibrary(p);
221 return SOX_SUCCESS;
224 #else
226 #define read_samples NULL
227 #define stopread NULL
229 #endif
231 static int startwrite(sox_format_t * ft)
233 #if !defined(AMR_VO) && !AMR_OPENCORE_ENABLE_ENCODE
234 lsx_fail_errno(ft, SOX_EOF, "SoX was compiled without AMR-WB encoding support.");
235 return SOX_EOF;
236 #else
237 priv_t * p = (priv_t *)ft->priv;
238 int open_library_result;
240 if (ft->encoding.compression != HUGE_VAL) {
241 p->mode = (unsigned)ft->encoding.compression;
242 if (p->mode != ft->encoding.compression || p->mode > AMR_MODE_MAX) {
243 lsx_fail_errno(ft, SOX_EINVAL, "compression level must be a whole number from 0 to %i", AMR_MODE_MAX);
244 return SOX_EOF;
247 else p->mode = 0;
249 open_library_result = openlibrary(p, 1);
250 if (open_library_result != SOX_SUCCESS)
251 return open_library_result;
253 p->state = AMR_CALL_ENCODER(p, AmrEncoderInit, ());
254 if (!p->state)
256 closelibrary(p);
257 lsx_fail("AMR encoder failed to initialize.");
258 return SOX_EOF;
261 lsx_writes(ft, amr_magic);
262 p->pcm_index = 0;
263 return SOX_SUCCESS;
264 #endif
267 #if defined(AMR_VO) || AMR_OPENCORE_ENABLE_ENCODE
269 static sox_bool encode_1_frame(sox_format_t * ft)
271 priv_t * p = (priv_t *)ft->priv;
272 uint8_t coded[AMR_CODED_MAX];
273 int n = AMR_CALL_ENCODER(p, AmrEncoderEncode, (p->state, p->mode, p->pcm, coded, 1));
274 sox_bool result = lsx_writebuf(ft, coded, (size_t) (size_t) (unsigned)n) == (unsigned)n;
275 if (!result)
276 lsx_fail_errno(ft, errno, "write error");
277 return result;
280 static size_t write_samples(sox_format_t * ft, const sox_sample_t * buf, size_t len)
282 priv_t * p = (priv_t *)ft->priv;
283 size_t done;
285 for (done = 0; done < len; ++done) {
286 SOX_SAMPLE_LOCALS;
287 p->pcm[p->pcm_index++] = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips);
288 if (p->pcm_index == AMR_FRAME) {
289 p->pcm_index = 0;
290 if (!encode_1_frame(ft))
291 return 0;
294 return done;
297 static int stopwrite(sox_format_t * ft)
299 priv_t * p = (priv_t *)ft->priv;
300 int result = SOX_SUCCESS;
302 if (p->pcm_index) {
303 do {
304 p->pcm[p->pcm_index++] = 0;
305 } while (p->pcm_index < AMR_FRAME);
306 if (!encode_1_frame(ft))
307 result = SOX_EOF;
309 AMR_CALL_ENCODER(p, AmrEncoderExit, (p->state));
310 return result;
313 #else
315 #define write_samples NULL
316 #define stopwrite NULL
318 #endif /* defined(AMR_VO) || AMR_OPENCORE_ENABLE_ENCODE */
320 sox_format_handler_t const * AMR_FORMAT_FN(void);
321 sox_format_handler_t const * AMR_FORMAT_FN(void)
323 static char const * const names[] = {AMR_NAMES, NULL};
324 static sox_rate_t const write_rates[] = {AMR_RATE, 0};
325 static unsigned const write_encodings[] = {AMR_ENCODING, 0, 0};
326 static sox_format_handler_t handler = {
327 SOX_LIB_VERSION_CODE,
328 AMR_DESC,
329 names, SOX_FILE_MONO,
330 startread, read_samples, stopread,
331 startwrite, write_samples, stopwrite,
332 NULL, write_encodings, write_rates, sizeof(priv_t)
334 return &handler;