ref: 7eab17120ab538b8ae0f02b719fd279e1bfc7861
parent: 60b5e4f356dfc3b16880c0aeebf684c3cc41a5ca
author: robs <robs>
date: Sat May 5 05:44:30 EDT 2007
Add AMR-NB file format
--- a/AUTHORS
+++ b/AUTHORS
@@ -89,7 +89,7 @@
format support, libao playback, Secret Rabbit Code
resampling; many fixes and much cleanup.
Rob Sykes robs@users.sourceforge.net
- Formats: M3U, PLS, FLAC, AMR-WB, 24bit support for popular
+ Formats: M3U, PLS, FLAC, AMR, 24bit support for popular
formats.
Effects: pad, bass, treble, new flanger, soft-knee companding,
speed via resampling, filters makeover inc. gnuplot & octave
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,7 +11,7 @@
o Added support for ADPCM-encoded PRC files, based on Danny Smith's
rec2wav and sndcmp.
- o Added AMR-WB format. (robs)
+ o Added AMR-NB [FR# 728875] & AMR-WB formats (with external libs). (robs)
o Added M3U & PLS playlist formats [FR# 1667341] (Note: SHOUTcast PLS
is only partially supported). (robs)
o Added libao support. (Reuben Thomas)
@@ -47,6 +47,7 @@
(Bug# 1666599) (cbagwell)
o Fix I/O performance regression in 13.0.0. (Reuben Thomas)
o Fix displayed times when playing a file and using trim. (robs)
+ o Fix CDDA sector duration display for non-CDDA sample rates. (robs)
Internal improvements:
--- a/configure.ac
+++ b/configure.ac
@@ -256,7 +256,7 @@
if test "$with_amr_wb" != "no"; then
using_amr_wb=yes
AC_CHECK_HEADER(amrwb/dec.h,
- [AC_CHECK_LIB(amrwb, D_MAIN_decode,,using_amr_wb=no)],
+ [AC_CHECK_LIB(amrwb, D_IF_init,,using_amr_wb=no)],
using_amr_wb=no)
if test "$with_amr_wb" = "yes" -a "$using_amr_wb" = "no"; then
AC_MSG_FAILURE([cannot find amr-wb])
@@ -264,6 +264,22 @@
fi
AM_CONDITIONAL(HAVE_AMR_WB, test x$using_amr_wb = xyes)
+dnl Check for amr-nb libraries
+AC_ARG_WITH(amr-nb,
+ AC_HELP_STRING([--without-amr-nb],
+ [Don't try to use amr-nb]),
+ [with_amr_nb=$withval])
+if test "$with_amr_nb" != "no"; then
+ using_amr_nb=yes
+ AC_CHECK_HEADER(amrnb/sp_dec.h,
+ [AC_CHECK_LIB(amrnb, Decoder_Interface_init,,using_amr_nb=no)],
+ using_amr_nb=no)
+ if test "$with_amr_nb" = "yes" -a "$using_amr_nb" = "no"; then
+ AC_MSG_FAILURE([cannot find amr-nb])
+ fi
+fi
+AM_CONDITIONAL(HAVE_AMR_NB, test x$using_amr_nb = xyes)
+
dnl Generate output files.
AX_CREATE_STDINT_H(src/soxstdint.h)
AC_CONFIG_FILES(Makefile src/Makefile src/libgsm/Makefile lpc10/Makefile)
@@ -292,6 +308,7 @@
echo "LAME MP3 writer................... $using_lame"
echo "Secret Rabbit Code resampling..... $using_samplerate"
echo "AMR-WB format..................... $using_amr_wb"
+echo "AMR-NB format..................... $using_amr_nb"
echo
echo "Configure finished. Do 'make && make install' to compile and install SoX."
echo
--- a/soxformat.7
+++ b/soxformat.7
@@ -33,10 +33,10 @@
.SH NAME
SoX \- Sound eXchange, the Swiss Army knife of audio manipulation
.SH DESCRIPTION
-File types can be set by the filename extension or the
-.B \-t
-option (see above). File types that can be determined by a filename
-extension are listed with their names preceded by a dot. File types
+File types that can be determined by a filename
+extension are listed with their names preceded by a dot.
+.SP
+File types
that require an external library, such as ffmpeg or libsndfile, are
marked e.g. `\fB(ffmpeg)\fR'. File types that can be handled by an
external library via its pseudo file type (currently libsndfile or
@@ -102,9 +102,28 @@
sox infile -t alsa default
.EE
.TP
+\&\fB.amr\-nb\fR
+Adaptive Multi Rate\*mNarrow Band speech codec; a lossy format used in 3rd
+generation mobile telephony and defined in 3GPP TS 26.071 et al.
+.SP
+AMR-WB audio has a fixed sampling rate of 8 kHz and supports encoding
+to the following bit-rates (as selected by the
+.B \-C
+option): 0 = 4\*d75 kbit/s, 1 = 5\*d15 kbit/s, 2 = 5\*d9 kbit/s, 3 =
+6\*d7 kbit/s, 4 = 7\*d4 kbit/s 5 = 7\*d95 kbit/s, 6 = 10\*d2
+kbit/s, 7 = 12\*d2 kbit/s.
+.SP
+This format in SoX is optional and requires access to external libraries.
+To see if there is support for this format, enter
+.EX
+ sox -h
+.EE
+and look for it under the list:
+.IR "SUPPORTED FILE FORMATS" .
+.TP
\&\fB.amr\-wb\fR
-Adaptive Multi Rate\*mWideband speech codec; a lossy format used in 3rd
-generation mobile telephony and defined in 3GPP TS 26.173.
+Adaptive Multi Rate\*mWide Band speech codec; a lossy format used in 3rd
+generation mobile telephony and defined in 3GPP TS 26.171 et al.
.SP
AMR-WB audio has a fixed sampling rate of 16 kHz and supports encoding
to the following bit-rates (as selected by the
@@ -111,7 +130,15 @@
.B \-C
option): 0 = 6\*d6 kbit/s, 1 = 8\*d85 kbit/s, 2 = 12\*d65 kbit/s, 3 =
14\*d25 kbit/s, 4 = 15\*d85 kbit/s 5 = 18\*d25 kbit/s, 6 = 19\*d85
-kbit/s, 7 = 23\*d05 kbit/s, 8 = 23\*d85 kbit/s
+kbit/s, 7 = 23\*d05 kbit/s, 8 = 23\*d85 kbit/s.
+.SP
+This format in SoX is optional and requires access to external libraries.
+To see if there is support for this format on your system, enter
+.EX
+ sox -h
+.EE
+and look for it under the list:
+.IR "SUPPORTED FILE FORMATS" .
.TP
.B ao
libao device driver.
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -128,6 +128,11 @@
libsox_fmt_amr_wb_la_LIBADD = libsox.la
pkglib_LTLIBRARIES += libsox_fmt_amr_wb.la
endif
+if HAVE_AMR_NB
+libsox_fmt_amr_nb_la_SOURCES = amr-nb.c
+libsox_fmt_amr_nb_la_LIBADD = libsox.la
+pkglib_LTLIBRARIES += libsox_fmt_amr_nb.la
+endif
if HAVE_MP3
libsox_fmt_mp3_la_SOURCES = mp3.c
libsox_fmt_mp3_la_LIBADD = libsox.la
--- /dev/null
+++ b/src/amr-nb.c
@@ -1,0 +1,55 @@
+/*
+ * File format: AMR-NB (c) 2007 robs@users.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
+ */
+
+/* In order to use this format with SoX, first build & install:
+ * http://ftp.penguin.cz/pub/users/utx/amr/amrnb-w.x.y.z.tar.bz2
+ * or install equivalent package(s) e.g. marillat.
+ */
+
+#include "amrnb/typedef.h"
+#include "amrnb/interf_dec.h"
+#include "amrnb/sp_dec.h"
+#define Mode _Mode
+#define MR102 _MR102
+#define MR122 _MR122
+#define MR475 _MR475
+#define MR515 _MR515
+#define MR59 _MR59
+#define MR67 _MR67
+#define MR74 _MR74
+#define MR795 _MR795
+#define MRDTX _MRDTX
+#include "amrnb/interf_enc.h"
+
+static char const magic[] = "#!AMR\n";
+#define AMR_CODED_MAX 32 /* max coded size */
+#define AMR_ENCODING SOX_ENCODING_AMR_NB
+#define AMR_FORMAT_FN sox_amr_nb_format_fn
+#define AMR_FRAME 160 /* 20ms @ 8kHz */
+#define AMR_MODE_MAX 7
+#define AMR_NAMES "amr-nb", "anb"
+#define AMR_PRIV_TOO_BIG amr_nb_PRIVSIZE_too_big
+#define AMR_RATE 8000
+#define D_IF_decode Decoder_Interface_Decode
+#define D_IF_exit Decoder_Interface_exit
+#define D_IF_init Decoder_Interface_init
+#define E_IF_encode Encoder_Interface_Encode
+#define E_IF_exit Encoder_Interface_exit
+#define E_IF_init() Encoder_Interface_init(1)
+static unsigned block_size[] = {13,14,16,18,20,21,27,32,6,1,1,1,1,1,1,1};
+#include "amr.h"
--- a/src/amr-wb.c
+++ b/src/amr-wb.c
@@ -16,163 +16,23 @@
* Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
*/
-/* In order to use this format with SoX, first obtain, build & install:
- * http://ftp.penguin.cz/pub/users/utx/amr/amrwb-7.0.0.0.tar.bz2
+/* In order to use this format with SoX, first build & install:
+ * http://ftp.penguin.cz/pub/users/utx/amr/amrwb-w.x.y.z.tar.bz2
+ * or install equivalent package(s) e.g. marillat.
*/
-#include "sox_i.h"
#include "amrwb/typedef.h"
#include "amrwb/enc_if.h"
#include "amrwb/dec_if.h"
#include "amrwb/if_rom.h"
-#include <string.h>
-#include <math.h>
static char const magic[] = "#!AMR-WB\n";
-
-typedef struct amr_wb
-{
- void * state;
- Word16 coding_mode;
- Word16 pcm[L_FRAME16k];
- sox_size_t pcm_index;
-} * amr_wb_t;
-
-assert_static(sizeof(struct amr_wb) <= SOX_MAX_FILE_PRIVSIZE,
- /* else */ amr_wb_PRIVSIZE_too_big);
-
-static sox_size_t decode_1_frame(ft_t ft)
-{
- amr_wb_t this = (amr_wb_t) ft->priv;
- Word16 mode;
- UWord8 serial[NB_SERIAL_MAX];
-
- if (fread(serial, sizeof(UWord8), 1, ft->fp) != 1)
- return L_FRAME16k;
- mode = (Word16)((serial[0] >> 3) & 0x0F);
- if (fread(&serial[1], sizeof(UWord8), block_size[mode] - 1, ft->fp) != block_size[mode] - 1)
- return L_FRAME16k;
- D_IF_decode(this->state, serial, this->pcm, _good_frame);
- return 0;
-}
-
-static void encode_1_frame(ft_t ft)
-{
- amr_wb_t this = (amr_wb_t) ft->priv;
- UWord8 serial[NB_SERIAL_MAX];
- Word16 mode = this->coding_mode;
- Word32 serial_size = E_IF_encode(this->state, mode, this->pcm, serial, 1);
- fwrite(serial, 1, serial_size, ft->fp);
-}
-
-static void set_format(ft_t ft)
-{
- ft->signal.rate = 16000;
- ft->signal.size = SOX_SIZE_16BIT;
- ft->signal.encoding = SOX_ENCODING_AMR_WB;
- ft->signal.channels = 1;
-}
-
-static int startread(ft_t ft)
-{
- amr_wb_t this = (amr_wb_t) ft->priv;
- char buffer[sizeof(magic)];
-
- this->pcm_index = L_FRAME16k;
-
- this->state = D_IF_init();
-
- fread(buffer, sizeof(char), sizeof(buffer) - 1, ft->fp);
- buffer[sizeof(buffer) - 1] = 0;
- if (strcmp(buffer, magic)) {
- sox_fail("Invalid magic number");
- return SOX_EOF;
- }
- set_format(ft);
- return SOX_SUCCESS;
-}
-
-static sox_size_t read(ft_t ft, sox_ssample_t * buf, sox_size_t len)
-{
- amr_wb_t this = (amr_wb_t) ft->priv;
- sox_size_t done;
-
- for (done = 0; done < len; done++) {
- if (this->pcm_index >= L_FRAME16k)
- this->pcm_index = decode_1_frame(ft);
- if (this->pcm_index >= L_FRAME16k)
- break;
- *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(this->pcm[this->pcm_index++], ft->clips);
- }
- return done;
-}
-
-static int stopread(ft_t ft)
-{
- amr_wb_t this = (amr_wb_t) ft->priv;
- D_IF_exit(this->state);
- return SOX_SUCCESS;
-}
-
-static int startwrite(ft_t ft)
-{
- amr_wb_t this = (amr_wb_t) ft->priv;
-
- if (ft->signal.compression != HUGE_VAL) {
- this->coding_mode = ft->signal.compression;
- if (this->coding_mode != ft->signal.compression || this->coding_mode > 8) {
- sox_fail_errno(ft, SOX_EINVAL, "compression level must be a whole number from 0 to 8");
- return SOX_EOF;
- }
- }
- else this->coding_mode = 0;
-
- set_format(ft);
- this->state = E_IF_init();
- sox_writes(ft, magic);
- this->pcm_index = 0;
- return SOX_SUCCESS;
-}
-
-static sox_size_t write(ft_t ft, const sox_ssample_t * buf, sox_size_t len)
-{
- amr_wb_t this = (amr_wb_t) ft->priv;
- sox_size_t done;
-
- for (done = 0; done < len; ++done) {
- this->pcm[this->pcm_index++] = (Word16) (SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips));
- if (this->pcm_index == L_FRAME16k) {
- this->pcm_index = 0;
- encode_1_frame(ft);
- }
- }
- return done;
-}
-
-static int stopwrite(ft_t ft)
-{
- amr_wb_t this = (amr_wb_t) ft->priv;
-
- if (this->pcm_index) {
- do {
- this->pcm[this->pcm_index++] = 0;
- } while (this->pcm_index < L_FRAME16k);
- encode_1_frame(ft);
- }
- E_IF_exit(this->state);
- return SOX_SUCCESS;
-}
-
-const sox_format_t *sox_amr_wb_format_fn(void);
-
-const sox_format_t *sox_amr_wb_format_fn(void)
-{
- static char const * names[] = {"amr-wb", "awb", NULL};
- static sox_format_t driver = {
- names, 0,
- startread, read, stopread,
- startwrite, write, stopwrite,
- sox_format_nothing_seek
- };
- return &driver;
-}
+#define AMR_CODED_MAX NB_SERIAL_MAX
+#define AMR_ENCODING SOX_ENCODING_AMR_WB
+#define AMR_FORMAT_FN sox_amr_wb_format_fn
+#define AMR_FRAME L_FRAME16k
+#define AMR_MODE_MAX 8
+#define AMR_NAMES "amr-wb", "awb"
+#define AMR_PRIV_TOO_BIG amr_wb_PRIVSIZE_too_big
+#define AMR_RATE 16000
+#include "amr.h"
--- /dev/null
+++ b/src/amr.h
@@ -1,0 +1,165 @@
+/*
+ * File format: AMR (c) 2007 robs@users.sourceforge.net
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, write to the Free Software Foundation,
+ * Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
+ */
+
+#include "sox_i.h"
+#include <string.h>
+#include <math.h>
+
+typedef struct amr
+{
+ void * state;
+ unsigned mode;
+ short pcm[AMR_FRAME];
+ sox_size_t pcm_index;
+} * amr_t;
+
+assert_static(sizeof(struct amr) <= SOX_MAX_FILE_PRIVSIZE, AMR_PRIV_TOO_BIG);
+
+static sox_size_t decode_1_frame(ft_t ft)
+{
+ amr_t amr = (amr_t) ft->priv;
+ int block_size_1;
+ unsigned char coded[AMR_CODED_MAX];
+
+ if (fread(coded, sizeof(coded[0]), 1, ft->fp) != 1)
+ return AMR_FRAME;
+ block_size_1 = block_size[(coded[0] >> 3) & 0x0F] - 1;
+ if (fread(&coded[1], sizeof(coded[1]), block_size_1, ft->fp) != block_size_1)
+ return AMR_FRAME;
+ D_IF_decode(amr->state, coded, amr->pcm, 0);
+ return 0;
+}
+
+static void encode_1_frame(ft_t ft)
+{
+ amr_t amr = (amr_t) ft->priv;
+ unsigned char coded[AMR_CODED_MAX];
+ fwrite(coded, 1, (unsigned)E_IF_encode(amr->state, amr->mode, amr->pcm, coded, 1), ft->fp);
+}
+
+static void set_format(ft_t ft)
+{
+ ft->signal.rate = AMR_RATE;
+ ft->signal.size = SOX_SIZE_16BIT;
+ ft->signal.encoding = AMR_ENCODING;
+ ft->signal.channels = 1;
+}
+
+static int startread(ft_t ft)
+{
+ amr_t amr = (amr_t) ft->priv;
+ char buffer[sizeof(magic)];
+
+ amr->pcm_index = AMR_FRAME;
+
+ amr->state = D_IF_init();
+
+ fread(buffer, sizeof(char), sizeof(buffer) - 1, ft->fp);
+ buffer[sizeof(buffer) - 1] = 0;
+ if (strcmp(buffer, magic)) {
+ sox_fail("Invalid magic number");
+ return SOX_EOF;
+ }
+ set_format(ft);
+ return SOX_SUCCESS;
+}
+
+static sox_size_t read(ft_t ft, sox_ssample_t * buf, sox_size_t len)
+{
+ amr_t amr = (amr_t) ft->priv;
+ sox_size_t done;
+
+ for (done = 0; done < len; done++) {
+ if (amr->pcm_index >= AMR_FRAME)
+ amr->pcm_index = decode_1_frame(ft);
+ if (amr->pcm_index >= AMR_FRAME)
+ break;
+ *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(amr->pcm[amr->pcm_index++], ft->clips);
+ }
+ return done;
+}
+
+static int stopread(ft_t ft)
+{
+ amr_t amr = (amr_t) ft->priv;
+ D_IF_exit(amr->state);
+ return SOX_SUCCESS;
+}
+
+static int startwrite(ft_t ft)
+{
+ amr_t amr = (amr_t) ft->priv;
+
+ if (ft->signal.compression != HUGE_VAL) {
+ amr->mode = ft->signal.compression;
+ if (amr->mode != ft->signal.compression || amr->mode > AMR_MODE_MAX) {
+ sox_fail_errno(ft, SOX_EINVAL, "compression level must be a whole number from 0 to %i", AMR_MODE_MAX);
+ return SOX_EOF;
+ }
+ }
+ else amr->mode = 0;
+
+ set_format(ft);
+ amr->state = E_IF_init();
+ sox_writes(ft, magic);
+ amr->pcm_index = 0;
+ return SOX_SUCCESS;
+}
+
+static sox_size_t write(ft_t ft, const sox_ssample_t * buf, sox_size_t len)
+{
+ amr_t amr = (amr_t) ft->priv;
+ sox_size_t done;
+
+ for (done = 0; done < len; ++done) {
+ amr->pcm[amr->pcm_index++] = SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips);
+ if (amr->pcm_index == AMR_FRAME) {
+ amr->pcm_index = 0;
+ encode_1_frame(ft);
+ }
+ }
+ return done;
+}
+
+static int stopwrite(ft_t ft)
+{
+ amr_t amr = (amr_t) ft->priv;
+
+ if (amr->pcm_index) {
+ do {
+ amr->pcm[amr->pcm_index++] = 0;
+ } while (amr->pcm_index < AMR_FRAME);
+ encode_1_frame(ft);
+ }
+ E_IF_exit(amr->state);
+ return SOX_SUCCESS;
+}
+
+const sox_format_t *AMR_FORMAT_FN(void);
+
+const sox_format_t *AMR_FORMAT_FN(void)
+{
+ static char const * names[] = {AMR_NAMES, NULL};
+ static sox_format_t driver = {
+ names, 0,
+ startread, read, stopread,
+ startwrite, write, stopwrite,
+ sox_format_nothing_seek
+ };
+ return &driver;
+}
--- a/src/auto.c
+++ b/src/auto.c
@@ -114,6 +114,13 @@
(memcmp(header, "XAJ\0", 4) == 0) ||
(memcmp(header, "XA\0\0", 4) == 0))
type = "xa";
+ else if (strncmp(header, "#!AM", 4) == 0) {
+ rc = sox_readbuf(ft, header, 5);
+ if (rc >= 2 && strncmp(header, "R\n", 2) == 0)
+ type = "amr-nb";
+ else if (rc >= 5 && strncmp(header, "R-WB\n", 5) == 0)
+ type = "amr-wb";
+ }
} /* read 4-byte header */
/* If we didn't find type yet then start looking for file
--- a/src/misc.c
+++ b/src/misc.c
@@ -73,6 +73,7 @@
"Vorbis",
"FLAC",
"AMR-WB",
+ "AMR-NB",
};
assert_static(array_length(sox_encodings_str) == SOX_ENCODINGS,
--- a/src/sox.h
+++ b/src/sox.h
@@ -181,6 +181,7 @@
SOX_ENCODING_VORBIS , /* Vorbis compression */
SOX_ENCODING_FLAC , /* FLAC compression */
SOX_ENCODING_AMR_WB , /* AMR-WB compression */
+ SOX_ENCODING_AMR_NB , /* AMR-NB compression */
SOX_ENCODINGS /* End of list marker */
} sox_encoding_t;