ref: b0aa26c836d4397fce0a86d100e1b76116e5ced0
parent: 9343c9427158a36841cbece5baff21bd26505c7d
author: robs <robs>
date: Tue Jan 9 17:05:18 EST 2007
Fix [ 1160154 ] VOX to WAV conversion problem.
--- a/ChangeLog
+++ b/ChangeLog
@@ -87,6 +87,7 @@
bit reversal) [FR# 1621702]. (robs)
o Add seek support for GSM data in WAV files. Rafal Maszkowski
o Fix [1627972] AIFF read bug when MARK chunk present. (Richard Fuller)
+ o Fix [1160154] VOX to WAV conversion problem. (robs)
sox-12.18.2
-----------
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,12 +13,12 @@
lib_LTLIBRARIES = libst.la
include_HEADERS = st.h stconfig.h ststdint.h
-formats = 8svx.c adpcm.c adpcm.h aiff.c au.c auto.c avr.c cdr.c \
- cvsd.c cvsdfilt.h dat.c flac.c g711.c g711.h g721.c \
+formats = 8svx.c adpcm.c adpcm.h adpcms.c adpcms.h aiff.c au.c auto.c avr.c \
+ cdr.c cvsd.c cvsdfilt.h dat.c flac.c g711.c g711.h g721.c \
g723_16.c g723_24.c g723_40.c g72x.c g72x.h gsm.c hcom.c \
- ima_rw.c ima_rw.h maud.c mp3.c nulfile.c prc.c raw.c \
- sf.c sfircam.h smp.c sndrtool.c sphere.c tx16w.c voc.c vorbis.c \
- vox.c wav.c wav.h wve.c xa.c
+ ima_rw.c ima_rw.h maud.c mp3.c nulfile.c prc.c \
+ raw.c sf.c sfircam.h smp.c sndrtool.c sphere.c tx16w.c voc.c \
+ vorbis.c vox.c wav.c wav.h wve.c xa.c
effects = avg.c band.c bandpass.c biquad.c biquad.h breject.c btrworth.c \
btrworth.h chorus.c compand.c dcshift.c deemphas.c earwax.c \
--- /dev/null
+++ b/src/adpcms.c
@@ -1,0 +1,76 @@
+/*
+ * 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.
+ */
+
+/* ADPCM CODECs: IMA, OKI. (c) 2007 robs@users.sourceforge.net */
+
+#include "adpcms.h"
+#include "st.h"
+
+#define range_limit(x,min,max)((x)<(min)?(min):(x)>(max)?(max):(x))
+
+static int const ima_steps[89] = { /* ~16-bit precision */
+ 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
+ 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230,
+ 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963,
+ 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
+ 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442,
+ 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794,
+ 32767 };
+
+static int const oki_steps[49] = { /* ~12-bit precision */
+ 256, 272, 304, 336, 368, 400, 448, 496, 544, 592, 656, 720, 800, 880, 960,
+ 1056, 1168, 1280, 1408, 1552, 1712, 1888, 2080, 2288, 2512, 2768, 3040, 3344,
+ 3680, 4048, 4464, 4912, 5392, 5936, 6528, 7184, 7904, 8704, 9568, 10528,
+ 11584, 12736, 14016, 15408, 16960, 18656, 20512, 22576, 24832 };
+
+static int const step_changes[8] = {-1, -1, -1, -1, 2, 4, 6, 8};
+
+void adpcm_init(adpcm_t state, int type)
+{
+ state->last_output = 0;
+ state->step_index = 0;
+ state->max_step_index = type? 48 : 88;
+ state->steps = type? oki_steps : ima_steps;
+ state->mask = type? ~15 : ~0;
+}
+
+int adpcm_decode(int code, adpcm_t state)
+{
+ int s = ((code & 7) << 1) | 1;
+ s = ((state->steps[state->step_index] * s) >> 3) & state->mask;
+ if (code & 8)
+ s = -s;
+ s = state->last_output + s;
+ s = range_limit(s, -0x8000, 0x7fff);
+ state->step_index += step_changes[code & 0x07];
+ state->step_index = range_limit(state->step_index, 0, state->max_step_index);
+ return state->last_output = s;
+}
+
+int adpcm_encode(int sample, adpcm_t state)
+{
+ int delta = sample - state->last_output;
+ int sign = 0;
+ int code;
+ if (delta < 0) {
+ sign = 0x08;
+ delta = -delta;
+ }
+ code = 4 * delta / state->steps[state->step_index];
+ code = sign | min(code, 7);
+ adpcm_decode(code, state); /* Update encoder state */
+ return code;
+}
--- /dev/null
+++ b/src/adpcms.h
@@ -1,0 +1,12 @@
+typedef struct adpcm_struct
+{
+ int last_output;
+ int step_index;
+ int max_step_index;
+ int const * steps;
+ int mask;
+} * adpcm_t;
+
+int adpcm_decode(int code, adpcm_t state); /* 4-bit -> 16-bit */
+int adpcm_encode(int sample, adpcm_t state); /* 16-bit -> 4-bit */
+void adpcm_init(adpcm_t state, int type /* 0:IMA, 1:OKI */);
--- a/src/vox.c
+++ b/src/vox.c
@@ -1,3 +1,4 @@
+
/************************************************************************
* SOX *
* *
@@ -5,25 +6,15 @@
* *
* Project : SOX *
* File : vox.c *
- * Version : V12.17.4 *
* *
* Version History : V12.17.4 - Tony Seebregts *
* 5 May 2004 *
- * 1. Original *
* *
* Description : SOX file format handler for Dialogic/Oki ADPCM VOX *
* files. *
* *
- * Notes : 1. Based on the vox/devox code samples at: *
+ * Notes : Coded from SOX skeleton code supplied with SOX source. *
* *
- * http://www.cis.ksu.edu/~tim/vox *
- * *
- * 2. Coded from SOX skeleton code supplied with SOX source. *
- * *
- * 3. Tested under: *
- * - Windows 2000 SP3/Visual C++ V6.0 *
- * - Windows 2000 SP3/Digital Mars V7.51 *
- * *
************************************************************************/
/************************************************************************
@@ -39,36 +30,21 @@
* *
************************************************************************/
+#include "adpcms.h"
#include "st_i.h"
+typedef struct voxstuff
+{
+ struct adpcm_struct encoder;
-typedef struct voxstuff { struct { short last; /* ADPCM codec state */
- short index;
- } state;
+ struct {
+ uint8_t byte; /* write store */
+ uint8_t flag;
+ } store;
+ st_fileinfo_t file;
+} *vox_t;
- struct { uint8_t byte; /* write store */
- uint8_t flag;
- } store;
- st_fileinfo_t file;
- } *vox_t;
-
-static short STEPSIZE[49] = { 16, 17, 19, 21, 23, 25, 28,
- 31, 34, 37, 41, 45, 50, 55,
- 60, 66, 73, 80, 88, 97, 107,
- 118, 130, 143, 157, 173, 190, 209,
- 230, 253, 279, 307, 337, 371, 408,
- 449, 494, 544, 598, 658, 724, 796,
- 876, 963, 1060,1166,1282,1411,1552
- };
-
-static short STEPADJUST[8] = { -1,-1,-1,-1,2,4,6,8 };
-
-
-static uint8_t envox (short, vox_t);
-static short devox (uint8_t,vox_t);
-
-
/******************************************************************************
* Function : st_voxstartread
* Description: Initialises the file parameters and ADPCM codec state.
@@ -82,34 +58,33 @@
* rates but the codecs allows any user specified rate.
******************************************************************************/
-static int st_voxstartread (ft_t ft)
- { vox_t state = (vox_t) ft->priv;
+static int st_voxstartread(ft_t ft)
+{
+ vox_t state = (vox_t) ft->priv;
- /* ... setup file info */
+ /* ... setup file info */
- state->file.buf = (char *)xmalloc(ST_BUFSIZ);
- state->file.size = ST_BUFSIZ;
- state->file.count = 0;
- state->file.pos = 0;
- state->file.eof = 0;
+ state->file.buf = (char *) xmalloc(ST_BUFSIZ);
+ state->file.size = ST_BUFSIZ;
+ state->file.count = 0;
+ state->file.pos = 0;
+ state->file.eof = 0;
- ft->signal.size = ST_SIZE_WORD;
- ft->signal.encoding = ST_ENCODING_OKI_ADPCM;
- ft->signal.channels = 1;
- if (ft->signal.rate == 0) {
- st_warn("'%s': sample rate not specified; trying 8kHz", ft->filename);
- ft->signal.rate = 8000;
- }
+ ft->signal.size = ST_SIZE_WORD;
+ ft->signal.encoding = ST_ENCODING_OKI_ADPCM;
+ ft->signal.channels = 1;
+ if (ft->signal.rate == 0) {
+ st_warn("'%s': sample rate not specified; trying 8kHz", ft->filename);
+ ft->signal.rate = 8000;
+ }
- /* ... initialise CODEC state */
+ adpcm_init(&state->encoder, 1);
- state->state.last = 0;
- state->state.index = 0;
- state->store.byte = 0;
- state->store.flag = 0;
+ state->store.byte = 0;
+ state->store.flag = 0;
- return (ST_SUCCESS);
- }
+ return (ST_SUCCESS);
+}
/******************************************************************************
@@ -125,47 +100,22 @@
* Notes :
******************************************************************************/
-static st_size_t st_voxread (ft_t ft,st_sample_t *buffer,st_size_t length)
- { vox_t state = (vox_t) ft->priv;
- int count = 0;
- int N;
- uint8_t byte;
- short word;
+static st_size_t st_voxread(ft_t ft, st_sample_t * buffer, st_size_t len)
+{
+ vox_t state = (vox_t) ft->priv;
+ st_size_t n;
+ uint8_t byte;
- /* ... round length down to nearest even number */
+ for (n = 0; n < (len&~1) && st_readb(ft, &byte) == ST_SUCCESS; n += 2) {
+ short word = adpcm_decode(byte >> 4, &state->encoder);
+ *buffer++ = ST_SIGNED_WORD_TO_SAMPLE(word, ft->clippedCount);
- N = length/2;
- N *=2;
+ word = adpcm_decode(byte, &state->encoder);
+ *buffer++ = ST_SIGNED_WORD_TO_SAMPLE(word, ft->clippedCount);
+ }
+ return n;
+}
- /* ... loop until buffer full or EOF */
-
- while (count < N)
- { /* ... refill buffer */
-
- if (state->file.pos >= state->file.count)
- { state->file.count = st_readbuf (ft,state->file.buf,1,state->file.size);
- state->file.pos = 0;
-
- if (state->file.count == 0)
- break;
- }
-
- /* ... decode two nybbles stored as a byte */
-
- byte = state->file.buf[state->file.pos++];
-
- word = devox ((uint8_t) ((byte >> 4) & 0x0F),state);
- *buffer++ = ST_SIGNED_WORD_TO_SAMPLE (word * 16,);
-
- word = devox ((uint8_t) (byte & 0x0F),state);
- *buffer++ = ST_SIGNED_WORD_TO_SAMPLE (word * 16,);
-
- count += 2;
- }
-
- return count;
- }
-
/******************************************************************************
* Function : st_voxstopread
* Description: Frees the internal buffer allocated in st_voxstartread.
@@ -175,14 +125,16 @@
* Notes :
******************************************************************************/
-static int st_voxstopread (ft_t ft)
- { vox_t state = (vox_t) ft->priv;
- free (state->file.buf);
-
- return (ST_SUCCESS);
- }
+static int st_voxstopread(ft_t ft)
+{
+ vox_t state = (vox_t) ft->priv;
+ free(state->file.buf);
+ return (ST_SUCCESS);
+}
+
+
/******************************************************************************
* Function : st_voxstartwrite
* Description: Initialises the file parameters and ADPCM codec state.
@@ -196,31 +148,30 @@
* rates but the codecs allows any user specified rate.
******************************************************************************/
-static int st_voxstartwrite (ft_t ft)
- { vox_t state = (vox_t) ft->priv;
+static int st_voxstartwrite(ft_t ft)
+{
+ vox_t state = (vox_t) ft->priv;
- /* ... setup file info */
+ /* ... setup file info */
- state->file.buf = (char *)xmalloc(ST_BUFSIZ);
- state->file.size = ST_BUFSIZ;
- state->file.count = 0;
- state->file.pos = 0;
- state->file.eof = 0;
+ state->file.buf = (char *) xmalloc(ST_BUFSIZ);
+ state->file.size = ST_BUFSIZ;
+ state->file.count = 0;
+ state->file.pos = 0;
+ state->file.eof = 0;
- ft->signal.size = ST_SIZE_WORD;
- ft->signal.encoding = ST_ENCODING_OKI_ADPCM;
- ft->signal.channels = 1;
+ ft->signal.size = ST_SIZE_WORD;
+ ft->signal.encoding = ST_ENCODING_OKI_ADPCM;
+ ft->signal.channels = 1;
- /* ... initialise CODEC state */
+ adpcm_init(&state->encoder, 1);
- state->state.last = 0;
- state->state.index = 0;
- state->store.byte = 0;
- state->store.flag = 0;
+ state->store.byte = 0;
+ state->store.flag = 0;
- return (ST_SUCCESS);
- }
+ return (ST_SUCCESS);
+}
/******************************************************************************
* Function : st_voxwrite
@@ -235,44 +186,44 @@
* Notes :
******************************************************************************/
-static st_size_t st_voxwrite (ft_t ft,const st_sample_t *buffer,st_size_t length)
- { vox_t state = (vox_t) ft->priv;
- st_size_t count = 0;
- uint8_t byte = state->store.byte;
- uint8_t flag = state->store.flag;
- short word;
+static st_size_t st_voxwrite(ft_t ft, const st_sample_t * buffer, st_size_t length)
+{
+ vox_t state = (vox_t) ft->priv;
+ st_size_t count = 0;
+ uint8_t byte = state->store.byte;
+ uint8_t flag = state->store.flag;
+ short word;
- while (count < length)
- { word = ST_SAMPLE_TO_SIGNED_WORD (*buffer++, ft->clippedCount);
- word /= 16;
+ while (count < length) {
+ word = ST_SAMPLE_TO_SIGNED_WORD(*buffer++, ft->clippedCount);
- byte <<= 4;
- byte |= envox (word,state) & 0x0F;
+ byte <<= 4;
+ byte |= adpcm_encode(word, &state->encoder) & 0x0F;
- flag++;
- flag %= 2;
+ flag++;
+ flag %= 2;
- if (flag == 0)
- { state->file.buf[state->file.count++] = byte;
+ if (flag == 0) {
+ state->file.buf[state->file.count++] = byte;
- if (state->file.count >= state->file.size)
- { st_writebuf (ft,state->file.buf,1,state->file.count);
+ if (state->file.count >= state->file.size) {
+ st_writebuf(ft, state->file.buf, 1, state->file.count);
- state->file.count = 0;
- }
- }
+ state->file.count = 0;
+ }
+ }
- count++;
- }
+ count++;
+ }
- /* ... keep last byte across calls */
+ /* ... keep last byte across calls */
- state->store.byte = byte;
- state->store.flag = flag;
-
- return (count);
- }
+ state->store.byte = byte;
+ state->store.flag = flag;
+ return (count);
+}
+
/******************************************************************************
* Function : st_voxstopwrite
* Description: Flushes any leftover samples and frees the internal buffer
@@ -283,132 +234,29 @@
* Notes :
******************************************************************************/
-static int st_voxstopwrite (ft_t ft)
- { vox_t state = (vox_t) ft->priv;
- uint8_t byte = state->store.byte;
- uint8_t flag = state->store.flag;
+static int st_voxstopwrite(ft_t ft)
+{
+ vox_t state = (vox_t) ft->priv;
+ uint8_t byte = state->store.byte;
+ uint8_t flag = state->store.flag;
- /* ... flush remaining samples */
+ /* ... flush remaining samples */
- if (flag != 0)
- { byte <<= 4;
- byte |= envox (0,state) & 0x0F;
+ if (flag != 0) {
+ byte <<= 4;
+ byte |= adpcm_encode(0, &state->encoder) & 0x0F;
- state->file.buf[state->file.count++] = byte;
- }
+ state->file.buf[state->file.count++] = byte;
+ }
- if (state->file.count > 0)
- st_writebuf (ft,state->file.buf,1,state->file.count);
+ if (state->file.count > 0)
+ st_writebuf(ft, state->file.buf, 1, state->file.count);
- free (state->file.buf);
-
- return (ST_SUCCESS);
- }
+ free(state->file.buf);
-/******************************************************************************
- * Function : envox
- * Description: Internal utility routine to encode 12 bit signed PCM to
- * OKI ADPCM code
- * Parameters : sample - 12 bit linear PCM sample
- * state - CODEC state
- * Returns : uint8_t - ADPCM nibble (in low order nibble)
- * Exceptions :
- * Notes :
- ******************************************************************************/
+ return (ST_SUCCESS);
+}
-static uint8_t envox (short sample,vox_t state)
- { uint8_t code;
- short dn;
- short ss;
-
- ss = STEPSIZE[state->state.index];
- code = 0x00;
-
- if ((dn = sample - state->state.last) < 0)
- { code = 0x08;
- dn = -dn;
- }
-
- if (dn >= ss)
- { code = code | 0x04;
- dn -= ss;
- }
-
- if (dn >= ss/2)
- { code = code | 0x02;
- dn -= ss/2;
- }
-
- if (dn >= ss/4)
- { code = code | 0x01;
- }
-
- /* ... use decoder to set the estimate of last sample and
- adjust the step index */
-
- state->state.last = devox (code,state);
-
- return (code);
- }
-
-
-/******************************************************************************
- * Function : devox
- * Description: Internal utility routine to decode OKI ADPCM 4-bit samples to
- * 12-bit signed PCM.
- * Parameters : code - ADPCM code (nibble)
- * state - CODEC state
- * Returns : short - 12 bit signed PCM sample
- * Exceptions :
- * Notes :
- ******************************************************************************/
-
-static short devox (uint8_t code,vox_t state)
- { short dn;
- short ss;
- short sample;
-
- ss = STEPSIZE[state->state.index];
- dn = ss/8;
-
- if (code & 0x01)
- dn += ss/4;
-
- if (code & 0x02)
- dn += ss/2;
-
- if (code & 0x04)
- dn += ss;
-
- if (code & 0x08)
- dn = -dn;
-
- sample = state->state.last + dn;
-
- /* ... clip to 12 bits */
-
- if (sample > 2047)
- sample = 2047;
-
- if (sample < -2048)
- sample = -2048;
-
- /* ... adjust step size */
-
- state->state.last = sample;
- state->state.index += STEPADJUST[code & 0x07];
-
- if (state->state.index < 0)
- state->state.index = 0;
-
- if (state->state.index > 48)
- state->state.index = 48;
-
- /* ... done */
-
- return (sample);
- }
-
static const char *voxnames[] = {
"vox",
NULL
@@ -429,5 +277,5 @@
const st_format_t *st_vox_format_fn(void)
{
- return &st_vox_format;
+ return &st_vox_format;
}