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
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
);
29 #endif /* AMR_OPENCORE */
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
);
41 #define AMR_CALL(p, func, args) ((p)->opencore.func args)
44 #define AMR_CALL_ENCODER(p, func, args) ((p)->vo.func args)
46 #define AMR_CALL_ENCODER(p, func, args) ((p)->opencore.func args)
49 typedef struct amr_priv_t
{
54 amr_opencore_funcs opencore
;
55 #endif /* AMR_OPENCORE */
63 static size_t decode_1_frame(sox_format_t
* ft
)
65 priv_t
* p
= (priv_t
*)ft
->priv
;
67 uint8_t coded
[AMR_CODED_MAX
];
69 if (lsx_readbuf(ft
, &coded
[0], (size_t)1) != 1)
71 n
= amr_block_size
[(coded
[0] >> 3) & 0x0F];
73 lsx_fail("invalid block type");
77 if (lsx_readbuf(ft
, &coded
[1], n
) != n
)
79 AMR_CALL(p
, AmrDecoderDecode
, (p
->state
, coded
, p
->pcm
, 0));
84 static int openlibrary(priv_t
* p
, int encoding
)
86 int open_library_result
;
90 if (AMR_OPENCORE_ENABLE_ENCODE
|| !encoding
)
92 LSX_DLLIBRARY_TRYOPEN(
96 AMR_OPENCORE_FUNC_ENTRIES
,
98 amr_opencore_library_names
,
100 if (!open_library_result
)
102 lsx_fail("Unable to open " AMR_OPENCORE_DESC
);
105 #endif /* AMR_OPENCORE */
109 LSX_DLLIBRARY_TRYOPEN(
115 amr_vo_library_names
,
116 open_library_result
);
117 if (!open_library_result
)
119 lsx_fail("Unable to open " AMR_VO_DESC
);
126 static void closelibrary(priv_t
* p
)
129 LSX_DLLIBRARY_CLOSE(&p
->opencore
, amr_dl
);
132 LSX_DLLIBRARY_CLOSE(&p
->vo
, amr_dl
);
137 static size_t amr_duration_frames(sox_format_t
* ft
)
139 off_t frame_size
, data_start_offset
= lsx_tell(ft
);
143 for (frames
= 0; lsx_readbuf(ft
, &coded
, (size_t)1) == 1; ++frames
) {
144 frame_size
= amr_block_size
[coded
>> 3 & 15];
146 lsx_fail("invalid block type");
149 if (lsx_seeki(ft
, frame_size
- 1, SEEK_CUR
)) {
154 lsx_debug("frames=%lu", (unsigned long)frames
);
155 lsx_seeki(ft
, data_start_offset
, SEEK_SET
);
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.");
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
)))
172 if (memcmp(buffer
, amr_magic
, sizeof(buffer
))) {
173 lsx_fail_errno(ft
, SOX_EHDR
, "invalid magic number");
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
, ());
186 lsx_fail("AMR decoder failed to initialize.");
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
;
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
;
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
)
211 *buf
++ = SOX_SIGNED_16BIT_TO_SAMPLE(p
->pcm
[p
->pcm_index
++], ft
->clips
);
216 static int stopread(sox_format_t
* ft
)
218 priv_t
* p
= (priv_t
*)ft
->priv
;
219 AMR_CALL(p
, AmrDecoderExit
, (p
->state
));
226 #define read_samples NULL
227 #define stopread NULL
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.");
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
);
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
, ());
257 lsx_fail("AMR encoder failed to initialize.");
261 lsx_writes(ft
, amr_magic
);
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
;
276 lsx_fail_errno(ft
, errno
, "write error");
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
;
285 for (done
= 0; done
< len
; ++done
) {
287 p
->pcm
[p
->pcm_index
++] = SOX_SAMPLE_TO_SIGNED_16BIT(*buf
++, ft
->clips
);
288 if (p
->pcm_index
== AMR_FRAME
) {
290 if (!encode_1_frame(ft
))
297 static int stopwrite(sox_format_t
* ft
)
299 priv_t
* p
= (priv_t
*)ft
->priv
;
300 int result
= SOX_SUCCESS
;
304 p
->pcm
[p
->pcm_index
++] = 0;
305 } while (p
->pcm_index
< AMR_FRAME
);
306 if (!encode_1_frame(ft
))
309 AMR_CALL_ENCODER(p
, AmrEncoderExit
, (p
->state
));
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
,
329 names
, SOX_FILE_MONO
,
330 startread
, read_samples
, stopread
,
331 startwrite
, write_samples
, stopwrite
,
332 NULL
, write_encodings
, write_rates
, sizeof(priv_t
)