shithub: sox

Download patch

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;
+}