1 /* File format: AMR   (c) 2007 robs@users.sourceforge.net
2  *
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.
7  *
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.
12  *
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
16  */
17 
18 #include <string.h>
19 #include <math.h>
20 
21 #ifdef AMR_OPENCORE
22 
23 LSX_DLENTRIES_TO_FUNCTIONS(AMR_OPENCORE_FUNC_ENTRIES)
24 
25 typedef struct amr_opencore_funcs {
26   LSX_DLENTRIES_TO_PTRS(AMR_OPENCORE_FUNC_ENTRIES, amr_dl);
27 } amr_opencore_funcs;
28 
29 #endif /* AMR_OPENCORE */
30 
31 #ifdef AMR_VO
32 
33 LSX_DLENTRIES_TO_FUNCTIONS(AMR_VO_FUNC_ENTRIES)
34 
35 typedef struct amr_vo_funcs {
36   LSX_DLENTRIES_TO_PTRS(AMR_VO_FUNC_ENTRIES, amr_dl);
37 } amr_vo_funcs;
38 
39 #endif /* AMR_VO */
40 
41 #define AMR_CALL(p, func, args) ((p)->opencore.func args)
42 
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
48 
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;
61 
62 #ifdef AMR_OPENCORE
decode_1_frame(sox_format_t * ft)63 static size_t decode_1_frame(sox_format_t * ft)
64 {
65   priv_t * p = (priv_t *)ft->priv;
66   size_t n;
67   uint8_t coded[AMR_CODED_MAX];
68 
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;
75   }
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;
81 }
82 #endif
83 
openlibrary(priv_t * p,int encoding)84 static int openlibrary(priv_t* p, int encoding)
85 {
86   int open_library_result;
87 
88   (void)encoding;
89 #ifdef AMR_OPENCORE
90   if (AMR_OPENCORE_ENABLE_ENCODE || !encoding)
91   {
92     LSX_DLLIBRARY_TRYOPEN(
93       0,
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;
104   }
105 #endif /* AMR_OPENCORE */
106 
107 #ifdef AMR_VO
108   if (encoding) {
109     LSX_DLLIBRARY_TRYOPEN(
110         0,
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);
120   }
121 #endif /* AMR_VO */
122 
123   return SOX_EOF;
124 }
125 
closelibrary(priv_t * p)126 static void closelibrary(priv_t* p)
127 {
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
134 }
135 
136 #ifdef AMR_OPENCORE
amr_duration_frames(sox_format_t * ft)137 static size_t amr_duration_frames(sox_format_t * ft)
138 {
139   off_t      frame_size, data_start_offset = lsx_tell(ft);
140   size_t     frames;
141   uint8_t    coded;
142 
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;
148     }
149     if (lsx_seeki(ft, frame_size - 1, SEEK_CUR)) {
150       lsx_fail("seek");
151       break;
152     }
153   }
154   lsx_debug("frames=%lu", (unsigned long)frames);
155   lsx_seeki(ft, data_start_offset, SEEK_SET);
156   return frames;
157 }
158 #endif
159 
startread(sox_format_t * ft)160 static int startread(sox_format_t * ft)
161 {
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;
169 
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;
175   }
176 
177   open_library_result = openlibrary(p, 0);
178   if (open_library_result != SOX_SUCCESS)
179     return open_library_result;
180 
181   p->pcm_index = AMR_FRAME;
182   p->state = AMR_CALL(p, AmrDecoderInit, ());
183   if (!p->state)
184   {
185       closelibrary(p);
186       lsx_fail("AMR decoder failed to initialize.");
187       return SOX_EOF;
188   }
189 
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
197 }
198 
199 #ifdef AMR_OPENCORE
200 
read_samples(sox_format_t * ft,sox_sample_t * buf,size_t len)201 static size_t read_samples(sox_format_t * ft, sox_sample_t * buf, size_t len)
202 {
203   priv_t * p = (priv_t *)ft->priv;
204   size_t done;
205 
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);
212   }
213   return done;
214 }
215 
stopread(sox_format_t * ft)216 static int stopread(sox_format_t * ft)
217 {
218   priv_t * p = (priv_t *)ft->priv;
219   AMR_CALL(p, AmrDecoderExit, (p->state));
220   closelibrary(p);
221   return SOX_SUCCESS;
222 }
223 
224 #else
225 
226 #define read_samples NULL
227 #define stopread NULL
228 
229 #endif
230 
startwrite(sox_format_t * ft)231 static int startwrite(sox_format_t * ft)
232 {
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;
239 
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;
245     }
246   }
247   else p->mode = 0;
248 
249   open_library_result = openlibrary(p, 1);
250   if (open_library_result != SOX_SUCCESS)
251     return open_library_result;
252 
253   p->state = AMR_CALL_ENCODER(p, AmrEncoderInit, ());
254   if (!p->state)
255   {
256       closelibrary(p);
257       lsx_fail("AMR encoder failed to initialize.");
258       return SOX_EOF;
259   }
260 
261   lsx_writes(ft, amr_magic);
262   p->pcm_index = 0;
263   return SOX_SUCCESS;
264 #endif
265 }
266 
267 #if defined(AMR_VO) || AMR_OPENCORE_ENABLE_ENCODE
268 
encode_1_frame(sox_format_t * ft)269 static sox_bool encode_1_frame(sox_format_t * ft)
270 {
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;
278 }
279 
write_samples(sox_format_t * ft,const sox_sample_t * buf,size_t len)280 static size_t write_samples(sox_format_t * ft, const sox_sample_t * buf, size_t len)
281 {
282   priv_t * p = (priv_t *)ft->priv;
283   size_t done;
284 
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;
292     }
293   }
294   return done;
295 }
296 
stopwrite(sox_format_t * ft)297 static int stopwrite(sox_format_t * ft)
298 {
299   priv_t * p = (priv_t *)ft->priv;
300   int result = SOX_SUCCESS;
301 
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;
308   }
309   AMR_CALL_ENCODER(p, AmrEncoderExit, (p->state));
310   return result;
311 }
312 
313 #else
314 
315 #define write_samples NULL
316 #define stopwrite NULL
317 
318 #endif /* defined(AMR_VO) || AMR_OPENCORE_ENABLE_ENCODE */
319 
320 sox_format_handler_t const * AMR_FORMAT_FN(void);
AMR_FORMAT_FN(void)321 sox_format_handler_t const * AMR_FORMAT_FN(void)
322 {
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)
333   };
334   return &handler;
335 }
336