ref: 4571d2307f86f2ce7ae1b0e6d223698552f52f33
parent: b6622037961ff521b215cbf43d680b1b37438d99
author: robs <robs>
date: Sun Aug 30 11:28:30 EDT 2009
add gsrt format
--- a/ChangeLog
+++ b/ChangeLog
@@ -35,6 +35,7 @@
File formats:
+ o New Grandstream ring-tone (gsrt) format. (robs)
o CVSD encode/decode speed-ups. (Kimberly Rockwell, P. Chaintreuil)
Audio device drivers:
--- a/FEATURES.in
+++ b/FEATURES.in
@@ -13,6 +13,7 @@
* AVR files
* CDDA (Compact Disc Digital Audio format)
* CVS and VMS files (continuous variable slope)
+* Grandstream ring-tone files
* GSM files
* HTK files
* LPC-10 files
--- a/soxformat.7
+++ b/soxformat.7
@@ -325,6 +325,16 @@
.B .u8
format.
.TP
+.B .gsrt
+Grandstream ring-tone files.
+Whilst this file format can contain A-Law, \(*m-law, GSM, G.722,
+G.723, G.726, G.728, or iLBC encoded audio, SoX supports reading and
+writing only A-Law and \(*m-law. E.g.
+.EX
+ sox music.wav -t gsrt ring.bin
+ play ring.bin
+.EE
+.TP
\&\fB.gsm\fR (optional; also with \fB\-t sndfile\fR)
GSM 06.10 Lossy Speech Compression.
A lossy format for compressing speech which is used in the
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -41,22 +41,22 @@
dft_filter flanger pan splice
)
set(formats_srcs
- 8svx dat ima-fmt s3-fmt u3-fmt
- adpcm dvms-fmt ima_rw s4-fmt u4-fmt
- adpcms f4-fmt la-fmt sf ul-fmt
- aifc-fmt f8-fmt lpc10.c skelform voc
- aiff g711 lu-fmt smp vox
- aiff-fmt g721 maud sounder vox-fmt
- al-fmt g723_24 nulfile soundtool wav
- au g723_40 prc sox-fmt wve
- avr g72x raw sphere xa
- cdr gsm.c raw-fmt tx16w
- cvsd hcom s1-fmt u1-fmt
- cvsd-fmt htk s2-fmt u2-fmt
+ 8svx dat htk s2-fmt u2-fmt
+ adpcm dvms-fmt ima-fmt s3-fmt u3-fmt
+ adpcms f4-fmt ima_rw s4-fmt u4-fmt
+ aifc-fmt f8-fmt la-fmt sf ul-fmt
+ aiff g711 lpc10.c skelform voc
+ aiff-fmt g721 lu-fmt smp vox
+ al-fmt g723_24 maud sounder vox-fmt
+ au g723_40 nulfile soundtool wav
+ avr g72x prc sox-fmt wve
+ cdr gsm.c raw sphere xa
+ cvsd gsrt raw-fmt tx16w
+ cvsd-fmt hcom s1-fmt u1-fmt
)
# Uncomment for bit-rot detection on linux
-#set(formats_srcs ${formats_srcs} coreaudio sndio sunaudio)
+#set(formats_srcs ${formats_srcs} coreaudio sndio sunaudio waveaudio)
add_library(lib${PROJECT_NAME}
effects formats_i libsox_i
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -106,7 +106,7 @@
lu-fmt.c 8svx.c aiff-fmt.c aifc-fmt.c au.c avr.c cdr.c cvsd-fmt.c \
dvms-fmt.c dat.c hcom.c htk.c maud.c prc.c sf.c smp.c \
sounder.c soundtool.c sphere.c tx16w.c voc.c vox-fmt.c ima-fmt.c adpcm.c adpcm.h \
- ima_rw.c ima_rw.h wav.c wve.c xa.c nulfile.c f4-fmt.c f8-fmt.c
+ ima_rw.c ima_rw.h wav.c wve.c xa.c nulfile.c f4-fmt.c f8-fmt.c gsrt.c
libsox_la_LIBADD += @GSM_LIBS@ @LIBGSM_LIBADD@
libsox_la_LIBADD += @LPC10_LIBS@ @LIBLPC10_LIBADD@
--- a/src/formats.c
+++ b/src/formats.c
@@ -48,6 +48,7 @@
CHECK(voc , 0, 0, "" , 0, 20, "Creative Voice File\x1a")
CHECK(smp , 0, 0, "" , 0, 17, "SOUND SAMPLE DATA")
CHECK(wve , 0, 0, "" , 0, 15, "ALawSoundFile**")
+ CHECK(gsrt , 0, 0, "" , 16, 9, "ring.bin")
CHECK(amr-wb, 0, 0, "" , 0, 9, "#!AMR-WB\n")
CHECK(prc , 0, 0, "" , 0, 8, "\x37\x00\x00\x10\x6d\x00\x00\x10")
CHECK(sph , 0, 0, "" , 0, 7, "NIST_1A")
@@ -811,7 +812,7 @@
lsx_fail("permission to overwrite `%s' denied", path);
goto error;
}
- if ((ft->fp = fopen(path, "wb")) == NULL) {
+ if ((ft->fp = fopen(path, "w+b")) == NULL) {
lsx_fail("can't open output file `%s': %s", path, strerror(errno));
goto error;
}
--- a/src/formats.h
+++ b/src/formats.h
@@ -29,6 +29,7 @@
FORMAT(dvms)
FORMAT(f4)
FORMAT(f8)
+ FORMAT(gsrt)
FORMAT(hcom)
FORMAT(htk)
FORMAT(ima)
--- /dev/null
+++ b/src/gsrt.c
@@ -1,0 +1,205 @@
+/* libSoX file format: Grandstream ring tone (c) 2009 robs@users.sourceforge.net
+ *
+ * See http://www.grandstream.com/ringtone.html
+ *
+ * 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.1 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,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "sox_i.h"
+#include <time.h>
+
+#define VERSION 0x1000000
+#define MAX_FILE_SIZE 0x10000
+#define HEADER_SIZE 512
+#define PADDING_SIZE 478
+
+static char const id[16] = "ring.bin";
+
+typedef struct {
+ char const * string;
+ int ft_encoding;
+ unsigned bits_per_sample;
+ sox_encoding_t sox_encoding;
+} table_t;
+
+static table_t const table[] = {
+ {NULL, 0, 8, SOX_ENCODING_ULAW},
+ {"G726", 2, 0, SOX_ENCODING_UNKNOWN},
+ {NULL, 3, 0, SOX_ENCODING_GSM},
+ {NULL, 4, 0, SOX_ENCODING_G723},
+ {NULL, 8, 8, SOX_ENCODING_ALAW},
+ {"G722", 9, 0, SOX_ENCODING_UNKNOWN},
+ {"G728", 15, 2, SOX_ENCODING_UNKNOWN},
+ {"iLBC", 98, 0, SOX_ENCODING_UNKNOWN},
+};
+
+static int ft_enc(unsigned bits_per_sample, sox_encoding_t encoding)
+{
+ size_t i;
+ for (i = 0; i < array_length(table); ++i) {
+ table_t const * t = &table[i];
+ if (t->sox_encoding == encoding && t->bits_per_sample == bits_per_sample)
+ return t->ft_encoding;
+ }
+ return -1; /* Should never get here. */
+}
+
+static sox_encoding_t sox_enc(int ft_encoding, unsigned * bits_per_sample)
+{
+ size_t i;
+ for (i = 0; i < array_length(table); ++i) {
+ table_t const * t = &table[i];
+ if (t->ft_encoding == ft_encoding) {
+ *bits_per_sample = t->bits_per_sample;
+ if (t->sox_encoding == SOX_ENCODING_UNKNOWN)
+ lsx_report("unsupported encoding: %s", t->string);
+ return t->sox_encoding;
+ }
+ }
+ *bits_per_sample = 0;
+ return SOX_ENCODING_UNKNOWN;
+}
+
+static int start_read(sox_format_t * ft)
+{
+ off_t num_samples;
+ char read_id[array_length(id)];
+ uint32_t file_size;
+ int16_t ft_encoding;
+ sox_encoding_t encoding;
+ unsigned bits_per_sample;
+
+ lsx_readdw(ft, &file_size);
+ num_samples = file_size? file_size * 2 - HEADER_SIZE : SOX_UNSPEC;
+
+ if (file_size >= 2 && ft->seekable) {
+ int i, checksum = (file_size >> 16) + file_size;
+ for (i = file_size - 2; i; --i) {
+ int16_t int16;
+ lsx_readsw(ft, &int16);
+ checksum += int16;
+ }
+ if (lsx_seeki(ft, sizeof(file_size), SEEK_SET) != 0)
+ return SOX_EOF;
+ if (checksum & 0xffff)
+ lsx_warn("invalid checksum in input file %s", ft->filename);
+ }
+
+ lsx_skipbytes(ft, 2 + 4 + 6); /* Checksum, version, and time stamp. */
+
+ lsx_readchars(ft, read_id, sizeof(read_id));
+ if (memcmp(read_id, id, strlen(id))) {
+ lsx_fail_errno(ft, SOX_EHDR, "gsrt: invalid file name in header");
+ return SOX_EOF;
+ }
+
+ lsx_readsw(ft, &ft_encoding);
+ encoding = sox_enc(ft_encoding, &bits_per_sample);
+ if (encoding != SOX_ENCODING_ALAW &&
+ encoding != SOX_ENCODING_ULAW)
+ ft->handler.read = NULL;
+
+ lsx_skipbytes(ft, PADDING_SIZE);
+
+ return lsx_check_read_params(ft, 1, 8000., encoding,
+ bits_per_sample, num_samples, sox_true);
+}
+
+static int start_write(sox_format_t * ft)
+{
+ int i, encoding = ft_enc(ft->encoding.bits_per_sample, ft->encoding.encoding);
+ time_t now = sox_globals.repeatable? 0 : time(NULL);
+ struct tm const * t = sox_globals.repeatable? gmtime(&now) : localtime(&now);
+
+ int checksum = (VERSION >> 16) + VERSION;
+ checksum += t->tm_year + 1900;
+ checksum += ((t->tm_mon + 1) << 8) + t->tm_mday;
+ checksum += (t->tm_hour << 8) + t->tm_min;
+ for (i = sizeof(id) - 2; i >= 0; i -= 2)
+ checksum += (id[i] << 8) + id[i + 1];
+ checksum += encoding;
+
+ return lsx_writedw(ft, 0)
+ || lsx_writesw(ft, -checksum)
+ || lsx_writedw(ft, VERSION)
+ || lsx_writesw(ft, t->tm_year + 1900)
+ || lsx_writesb(ft, t->tm_mon + 1)
+ || lsx_writesb(ft, t->tm_mday)
+ || lsx_writesb(ft, t->tm_hour)
+ || lsx_writesb(ft, t->tm_min)
+ || lsx_writechars(ft, id, sizeof(id))
+ || lsx_writesw(ft, encoding)
+ || lsx_padbytes(ft, PADDING_SIZE) ? SOX_EOF : SOX_SUCCESS;
+}
+
+static size_t write_samples(
+ sox_format_t * ft, sox_sample_t const * buf, size_t nsamp)
+{
+ size_t n = min(nsamp, MAX_FILE_SIZE - (size_t)ft->tell_off);
+ if (n != nsamp)
+ lsx_warn("audio truncated");
+ return lsx_rawwrite(ft, buf, n);
+}
+
+static int stop_write(sox_format_t * ft)
+{
+ long num_samples = ft->tell_off - HEADER_SIZE;
+
+ if (num_samples & 1)
+ lsx_writeb(ft, 0);
+
+ if (ft->seekable) {
+ unsigned i, file_size = ft->tell_off >> 1;
+ int16_t int16;
+ int checksum;
+ if (!lsx_seeki(ft, sizeof(uint32_t), SEEK_SET)) {
+ lsx_readsw(ft, &int16);
+ checksum = (file_size >> 16) + file_size - int16;
+ if (!lsx_seeki(ft, HEADER_SIZE, SEEK_SET)) {
+ for (i = (num_samples + 1) >> 1; i; --i) {
+ lsx_readsw(ft, &int16);
+ checksum += int16;
+ }
+ if (!lsx_seeki(ft, 0, SEEK_SET)) {
+ lsx_writedw(ft, file_size);
+ lsx_writesw(ft, -checksum);
+ return SOX_SUCCESS;
+ }
+ }
+ }
+ }
+ lsx_warn("can't seek in output file `%s'; "
+ "length in file header will be unspecified", ft->filename);
+ return SOX_SUCCESS;
+}
+
+LSX_FORMAT_HANDLER(gsrt)
+{
+ static char const *const names[] = { "gsrt", NULL };
+ static sox_rate_t const write_rates[] = { 8000, 0 };
+ static unsigned const write_encodings[] = {
+ SOX_ENCODING_ALAW, 8, 0,
+ SOX_ENCODING_ULAW, 8, 0,
+ 0
+ };
+ static sox_format_handler_t const handler = {
+ SOX_LIB_VERSION_CODE, "Grandstream ring tone",
+ names, SOX_FILE_BIG_END | SOX_FILE_MONO,
+ start_read, lsx_rawread, NULL,
+ start_write, write_samples, stop_write,
+ lsx_rawseek, write_encodings, write_rates, 0
+ };
+ return &handler;
+}