ref: bd9940ebc5929cf32aafba1f118525fdaf393cab
parent: 84145f47ba249412f48ec7618ffc55f09ac72af9
author: robs <robs>
date: Wed Mar 5 12:12:42 EST 2008
Added some VOC ADPCMs
--- a/AUTHORS
+++ b/AUTHORS
@@ -15,8 +15,8 @@
format support, libao playback, Secret Rabbit Code
resampling; many fixes and much cleanup.
Rob Sykes robs@users.sourceforge.net
- Formats: M3U, PLS, FLAC, AMR, HTK, 24bit support for popular
- formats.
+ Formats: M3U, PLS, FLAC, AMR, HTK, VOC ADPCM,
+ 24bit support for popular formats.
Effects: key, tempo, pad, bass, treble, new reverb, new
flanger, soft-knee companding, speed via resampling, filters
makeover inc. gnuplot & octave plotting, splice, remix, norm;
--- a/ChangeLog
+++ b/ChangeLog
@@ -36,6 +36,7 @@
o Au/snd: added support for 32-bit integer and 64-bit float PCM
encoding/decoding; display name of unsupported encoding. (robs)
o Can now write .amb (.wav variant) files [FR 1902232]. (robs)
+ o Can now read 2,3,4 bit ADPCM .voc files. (robs)
Effects:
--- a/soxformat.7
+++ b/soxformat.7
@@ -533,8 +533,8 @@
and sample data with a new sample rate is rejected.
Silence with a different sample rate is generated appropriately.
On output, silence is not detected, nor are impossible sample rates.
-Note, this version now supports playing VOC files with multiple
-blocks and supports playing files containing \(*m-law and A-law samples.
+SoX supports reading (but not writing) VOC files with multiple
+blocks, and files containing \(*m-law, A-law, and 2/3/4-bit ADPCM samples.
.TP
.B .vorbis
See
--- a/src/adpcms.c
+++ b/src/adpcms.c
@@ -14,12 +14,12 @@
* Fifth Floor, 51 Franklin Street, Boston, MA 02111-1301, USA.
*/
-/* ADPCM CODECs: IMA, OKI. (c) 2007 robs@users.sourceforge.net */
+/* ADPCM CODECs: IMA, OKI, CL. (c) 2007-8 robs@users.sourceforge.net */
#include "sox_i.h"
#include "adpcms.h"
-static int const ima_steps[89] = { /* ~16-bit precision */
+static int const ima_steps[89] = { /* ~16-bit precision; 4 bit code */
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,
@@ -26,62 +26,78 @@
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 };
+ 32767};
-static int const oki_steps[49] = { /* ~12-bit precision */
+static int const oki_steps[49] = { /* ~12-bit precision; 4 bit code */
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 };
+ 11584, 12736, 14016, 15408, 16960, 18656, 20512, 22576, 24832};
static int const step_changes[8] = {-1, -1, -1, -1, 2, 4, 6, 8};
-static void adpcm_init(adpcm_t state, int type)
+/* Creative Labs ~8 bit precision; 4, 3, & 2 bit codes: */
+static int const cl4_steps[4] = {0x100, 0x200, 0x400, 0x800};
+static int const cl4_changes[8] = {-1, 0, 0, 0, 0, 1, 1, 1};
+
+static int const cl3_steps[5] = {0x100, 0x200, 0x400, 0x800, 0xA00};
+static int const cl3_changes[4] = {-1, 0, 0, 1};
+
+static int const cl2_steps[6] = {0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000};
+static int const cl2_changes[2] = {-1, 1};
+
+static adpcm_setup_t const setup_table[] = {
+ {88, 8, 2, ima_steps, step_changes, ~0},
+ {48, 8, 2, oki_steps, step_changes, ~15},
+ { 3, 8, 0, cl4_steps, cl4_changes , ~255},
+ { 4, 4, 0, cl3_steps, cl3_changes , ~255},
+ { 5, 2, 0, cl2_steps, cl2_changes , ~255},
+};
+
+void adpcm_init(adpcm_t * p, int type, int first_sample)
{
- 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;
- state->errors = 0;
+ p->setup = setup_table[type];
+ p->last_output = first_sample;
+ p->step_index = 0;
+ p->errors = 0;
}
#define min_sample -0x8000
#define max_sample 0x7fff
-static int adpcm_decode(int code, adpcm_t state)
+int adpcm_decode(int code, adpcm_t * p)
{
- int s = ((code & 7) << 1) | 1;
- s = ((state->steps[state->step_index] * s) >> 3) & state->mask;
- if (code & 8)
+ int s = ((code & (p->setup.sign - 1)) << 1) | 1;
+ s = ((p->setup.steps[p->step_index] * s) >> (p->setup.shift + 1)) & p->setup.mask;
+ if (code & p->setup.sign)
s = -s;
- s += state->last_output;
+ s += p->last_output;
if (s < min_sample || s > max_sample) {
- int grace = (state->steps[state->step_index] >> 3) & state->mask;
+ int grace = (p->setup.steps[p->step_index] >> (p->setup.shift + 1)) & p->setup.mask;
if (s < min_sample - grace || s > max_sample + grace) {
sox_debug_most("code=%i step=%i grace=%i s=%i",
- code & 15, state->steps[state->step_index], grace, s);
- state->errors++;
+ code & (2 * p->setup.sign - 1), p->setup.steps[p->step_index], grace, s);
+ p->errors++;
}
s = s < min_sample? min_sample : max_sample;
}
- 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;
+ p->step_index += p->setup.changes[code & (p->setup.sign - 1)];
+ p->step_index = range_limit(p->step_index, 0, p->setup.max_step_index);
+ return p->last_output = s;
}
-static int adpcm_encode(int sample, adpcm_t state)
+int adpcm_encode(int sample, adpcm_t * p)
{
- int delta = sample - state->last_output;
+ int delta = sample - p->last_output;
int sign = 0;
int code;
if (delta < 0) {
- sign = 0x08;
+ sign = p->setup.sign;
delta = -delta;
}
- code = 4 * delta / state->steps[state->step_index];
- code = sign | min(code, 7);
- adpcm_decode(code, state); /* Update encoder state */
+ code = (delta << p->setup.shift) / p->setup.steps[p->step_index];
+ code = sign | min(code, p->setup.sign - 1);
+ adpcm_decode(code, p); /* Update encoder state */
return code;
}
@@ -111,7 +127,7 @@
state->store.byte = 0;
state->store.flag = 0;
- adpcm_init(&state->encoder, (type == SOX_ENCODING_OKI_ADPCM) ? 1 : 0);
+ adpcm_init(&state->encoder, (type == SOX_ENCODING_OKI_ADPCM) ? 1 : 0, 0);
}
/******************************************************************************
--- a/src/adpcms.h
+++ b/src/adpcms.h
@@ -16,18 +16,28 @@
/* ADPCM CODECs: IMA, OKI. (c) 2007 robs@users.sourceforge.net */
-typedef struct adpcm_struct
-{
- int last_output;
- int step_index;
+typedef struct {
int max_step_index;
+ int sign;
+ int shift;
int const * steps;
+ int const * changes;
int mask;
+} adpcm_setup_t;
+
+typedef struct {
+ adpcm_setup_t setup;
+ int last_output;
+ int step_index;
int errors;
-} * adpcm_t;
+} adpcm_t;
+void adpcm_init(adpcm_t * p, int type, int first_sample);
+int adpcm_decode(int code, adpcm_t * p);
+int adpcm_encode(int sample, adpcm_t * p);
+
typedef struct adpcm_io {
- struct adpcm_struct encoder;
+ adpcm_t encoder;
struct {
uint8_t byte; /* write store */
uint8_t flag;
--- a/src/misc.c
+++ b/src/misc.c
@@ -42,6 +42,8 @@
"A-law",
"G.721 ADPCM",
"G.723 ADPCM",
+ "CL ADPCM (from 8-bit)",
+ "CL ADPCM (from 16-bit)",
"MS ADPCM",
"IMA ADPCM",
"OKI ADPCM",
@@ -76,6 +78,8 @@
case SOX_ENCODING_ALAW: return bits_per_sample == 8? 13: 0;
case SOX_ENCODING_ULAW: return bits_per_sample == 8? 14: 0;
+ case SOX_ENCODING_CL_ADPCM: return bits_per_sample? 8: 0;
+ case SOX_ENCODING_CL_ADPCM16: return bits_per_sample == 4? 13: 0;
case SOX_ENCODING_MS_ADPCM: return bits_per_sample == 4? 14: 0;
case SOX_ENCODING_IMA_ADPCM: return bits_per_sample == 4? 13: 0;
case SOX_ENCODING_OKI_ADPCM: return bits_per_sample == 4? 12: 0;
--- a/src/sox.h
+++ b/src/sox.h
@@ -188,6 +188,8 @@
SOX_ENCODING_ALAW , /* A-law signed logs: non-US telephony */
SOX_ENCODING_G721 , /* G.721 4-bit ADPCM */
SOX_ENCODING_G723 , /* G.723 3 or 5 bit ADPCM */
+ SOX_ENCODING_CL_ADPCM , /* Creative Labs 8 --> 2,3,4 bit Compressed PCM */
+ SOX_ENCODING_CL_ADPCM16, /* Creative Labs 16 --> 4 bit Compressed PCM */
SOX_ENCODING_MS_ADPCM , /* Microsoft Compressed PCM */
SOX_ENCODING_IMA_ADPCM , /* IMA Compressed PCM */
SOX_ENCODING_OKI_ADPCM , /* Dialogic/OKI Compressed PCM */
--- a/src/voc.c
+++ b/src/voc.c
@@ -20,7 +20,7 @@
* For sox-12-17 by Annonymous (see notes ANN)
* Added comments and notes for each procedure.
* Fixed so this now works with pipes, input does not have to
- * be seekable anymore (in sox_vocstartread() )
+ * be seekable anymore (in startread() )
* Added support for uLAW and aLaw (aLaw not tested).
* Fixed support of multi-part VOC files, and files with
* block 9 but no audio in the block....
@@ -159,21 +159,24 @@
#include "sox_i.h"
#include "g711.h"
+#include "adpcms.h"
+#include <assert.h>
#include <string.h>
/* Private data for VOC file */
typedef struct vocstuff {
- long rest; /* bytes remaining in current block */
- long rate; /* rate code (byte) of this chunk */
- int silent; /* sound or silence? */
- long srate; /* rate code (byte) of silence */
- sox_size_t blockseek; /* start of current output block */
- long samples; /* number of samples output */
- uint16_t format; /* VOC audio format */
- int size; /* word length of data */
- unsigned char channels; /* number of sound channels */
- long total_size; /* total size of all audio in file */
- int extended; /* Has an extended block been read? */
+ long block_remaining; /* bytes remaining in current block */
+ long rate; /* rate code (byte) of this chunk */
+ int silent; /* sound or silence? */
+ long srate; /* rate code (byte) of silence */
+ sox_size_t blockseek; /* start of current output block */
+ long samples; /* number of samples output */
+ uint16_t format; /* VOC audio format */
+ int size; /* word length of data */
+ unsigned char channels; /* number of sound channels */
+ long total_size; /* total size of all audio in file */
+ int extended; /* Has an extended block been read? */
+ adpcm_t adpcm;
} *vs_t;
#define VOC_TERM 0
@@ -188,14 +191,14 @@
#define VOC_DATA_16 9
/* ANN: Format encoding types */
-#define VOC_FMT_LIN8U 0 /* 8 bit unsigned linear PCM */
-#define VOC_FMT_CRLADPCM4 1 /* Creative 8-bit to 4-bit ADPCM */
-#define VOC_FMT_CRLADPCM3 2 /* Creative 8-bit to 3-bit ADPCM */
-#define VOC_FMT_CRLADPCM2 3 /* Creative 8-bit to 2-bit ADPCM */
-#define VOC_FMT_LIN16 4 /* 16-bit signed PCM */
-#define VOC_FMT_ALAW 6 /* CCITT a-Law 8-bit PCM */
-#define VOC_FMT_MU255 7 /* CCITT u-Law 8-bit PCM */
-#define VOC_FMT_CRLADPCM4A 0x200 /* Creative 16-bit to 4-bit ADPCM */
+#define VOC_FMT_LIN8U 0 /* 8 bit unsigned linear PCM */
+#define VOC_FMT_CRLADPCM4 1 /* Creative 8-bit to 4-bit ADPCM */
+#define VOC_FMT_CRLADPCM3 2 /* Creative 8-bit to 3-bit ADPCM */
+#define VOC_FMT_CRLADPCM2 3 /* Creative 8-bit to 2-bit ADPCM */
+#define VOC_FMT_LIN16 4 /* 16-bit signed PCM */
+#define VOC_FMT_ALAW 6 /* CCITT a-Law 8-bit PCM */
+#define VOC_FMT_MU255 7 /* CCITT u-Law 8-bit PCM */
+#define VOC_FMT_CRLADPCM4A 0x200 /* Creative 16-bit to 4-bit ADPCM */
/* Prototypes for internal functions */
static int getblock(sox_format_t *);
@@ -206,196 +209,237 @@
#define SOX_ULAW_BYTE_TO_SAMPLE(d) ((sox_sample_t)(sox_ulaw2linear16(d)) << 16)
/* public VOC functions for SOX */
+
/*-----------------------------------------------------------------
- * sox_vocstartread() -- start reading a VOC file
+ * startread() -- start reading a VOC file
*-----------------------------------------------------------------*/
-static int sox_vocstartread(sox_format_t * ft)
+static int startread(sox_format_t * ft)
{
- int rtn = SOX_SUCCESS;
- char header[20];
- vs_t v = (vs_t) ft->priv;
- unsigned short sbseek;
- int rc;
- int ii; /* for getting rid of lseek */
- unsigned char uc;
+ int rtn = SOX_SUCCESS;
+ char header[20];
+ vs_t v = (vs_t) ft->priv;
+ unsigned short sbseek;
+ int rc;
+ int ii; /* for getting rid of lseek */
+ unsigned char uc;
- if (sox_readbuf(ft, header, 20) != 20)
- {
- sox_fail_errno(ft,SOX_EHDR,"unexpected EOF in VOC header");
- return(SOX_EOF);
- }
- if (strncmp(header, "Creative Voice File\032", 19))
- {
- sox_fail_errno(ft,SOX_EHDR,"VOC file header incorrect");
- return(SOX_EOF);
- }
+ if (sox_readbuf(ft, header, 20) != 20) {
+ sox_fail_errno(ft, SOX_EHDR, "unexpected EOF in VOC header");
+ return (SOX_EOF);
+ }
+ if (strncmp(header, "Creative Voice File\032", 19)) {
+ sox_fail_errno(ft, SOX_EHDR, "VOC file header incorrect");
+ return (SOX_EOF);
+ }
- /* read the offset to data, from start of file */
- /* after this read we have read 20 bytes of header + 2 */
- sox_readw(ft, &sbseek);
+ /* read the offset to data, from start of file */
+ /* after this read we have read 20 bytes of header + 2 */
+ sox_readw(ft, &sbseek);
- /* ANN: read to skip the header, instead of lseek */
- /* this should allow use with pipes.... */
- for (ii=22; ii<sbseek; ii++)
- sox_readb(ft, &uc);
+ /* ANN: read to skip the header, instead of lseek */
+ /* this should allow use with pipes.... */
+ for (ii = 22; ii < sbseek; ii++)
+ sox_readb(ft, &uc);
- v->rate = -1;
- v->rest = 0;
- v->total_size = 0; /* ANN added */
- v->extended = 0;
- v->format = VOC_FMT_LIN8U;
+ v->rate = -1;
+ v->block_remaining = 0;
+ v->total_size = 0; /* ANN added */
+ v->extended = 0;
- /* read until we get the format information.... */
- rc = getblock(ft);
- if (rc)
- return rc;
+ /* read until we get the format information.... */
+ rc = getblock(ft);
+ if (rc)
+ return rc;
- /* get rate of data */
- if (v->rate == -1)
- {
- sox_fail_errno(ft,SOX_EOF,"Input .voc file had no sound!");
- return(SOX_EOF);
- }
+ /* get rate of data */
+ if (v->rate == -1) {
+ sox_fail_errno(ft, SOX_EOF, "Input .voc file had no sound!");
+ return (SOX_EOF);
+ }
- /* setup word length of data */
- ft->encoding.bits_per_sample = v->size;
+ /* setup word length of data */
- /* ANN: Check VOC format and map to the proper libSoX format value */
- switch (v->format) {
- case VOC_FMT_LIN8U: /* 0 8 bit unsigned linear PCM */
- ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
- break;
- case VOC_FMT_CRLADPCM4: /* 1 Creative 8-bit to 4-bit ADPCM */
- sox_fail ("Unsupported VOC format CRLADPCM4 %d", v->format);
- rtn=SOX_EOF;
- break;
- case VOC_FMT_CRLADPCM3: /* 2 Creative 8-bit to 3-bit ADPCM */
- sox_fail ("Unsupported VOC format CRLADPCM3 %d", v->format);
- rtn=SOX_EOF;
- break;
- case VOC_FMT_CRLADPCM2: /* 3 Creative 8-bit to 2-bit ADPCM */
- sox_fail ("Unsupported VOC format CRLADPCM2 %d", v->format);
- rtn=SOX_EOF;
- break;
- case VOC_FMT_LIN16: /* 4 16-bit signed PCM */
- ft->encoding.encoding = SOX_ENCODING_SIGN2;
- break;
- case VOC_FMT_ALAW: /* 6 CCITT a-Law 8-bit PCM */
- ft->encoding.encoding = SOX_ENCODING_ALAW;
- break;
- case VOC_FMT_MU255: /* 7 CCITT u-Law 8-bit PCM */
- ft->encoding.encoding = SOX_ENCODING_ULAW;
- break;
- case VOC_FMT_CRLADPCM4A: /*0x200 Creative 16-bit to 4-bit ADPCM */
- sox_fail ("Unsupported VOC format CRLADPCM4A %d", v->format);
- rtn=SOX_EOF;
- break;
- default:
- sox_fail ("Unknown VOC format %d", v->format);
- rtn=SOX_EOF;
- break;
- }
+ /* ANN: Check VOC format and map to the proper libSoX format value */
+ switch (v->format) {
+ case VOC_FMT_LIN8U: /* 0 8 bit unsigned linear PCM */
+ ft->encoding.encoding = SOX_ENCODING_UNSIGNED;
+ v->size = 8;
+ break;
+ case VOC_FMT_CRLADPCM4: /* 1 Creative 8-bit to 4-bit ADPCM */
+ ft->encoding.encoding = SOX_ENCODING_CL_ADPCM;
+ v->size = 4;
+ break;
+ case VOC_FMT_CRLADPCM3: /* 2 Creative 8-bit to 3-bit ADPCM */
+ ft->encoding.encoding = SOX_ENCODING_CL_ADPCM;
+ v->size = 3;
+ break;
+ case VOC_FMT_CRLADPCM2: /* 3 Creative 8-bit to 2-bit ADPCM */
+ ft->encoding.encoding = SOX_ENCODING_CL_ADPCM;
+ v->size = 2;
+ break;
+ case VOC_FMT_LIN16: /* 4 16-bit signed PCM */
+ ft->encoding.encoding = SOX_ENCODING_SIGN2;
+ v->size = 16;
+ break;
+ case VOC_FMT_ALAW: /* 6 CCITT a-Law 8-bit PCM */
+ ft->encoding.encoding = SOX_ENCODING_ALAW;
+ v->size = 8;
+ break;
+ case VOC_FMT_MU255: /* 7 CCITT u-Law 8-bit PCM */
+ ft->encoding.encoding = SOX_ENCODING_ULAW;
+ v->size = 8;
+ break;
+ case VOC_FMT_CRLADPCM4A: /*0x200 Creative 16-bit to 4-bit ADPCM */
+ ft->encoding.encoding = SOX_ENCODING_CL_ADPCM16;
+ v->size = 4;
+ break;
+ default:
+ sox_fail("Unknown VOC format %d", v->format);
+ rtn = SOX_EOF;
+ break;
+ }
+ ft->encoding.bits_per_sample = v->size;
- /* setup number of channels */
- if (ft->signal.channels == 0)
- ft->signal.channels = v->channels;
+ /* setup number of channels */
+ if (ft->signal.channels == 0)
+ ft->signal.channels = v->channels;
- return(SOX_SUCCESS);
+ return (SOX_SUCCESS);
}
/*-----------------------------------------------------------------
- * sox_vocread() -- read data from a VOC file
+ * read() -- read data from a VOC file
* ANN: Major changes here to support multi-part files and files
* that do not have audio in block 9's.
*-----------------------------------------------------------------*/
-static sox_size_t sox_vocread(sox_format_t * ft, sox_sample_t *buf, sox_size_t len)
+static sox_size_t read_samples(sox_format_t * ft, sox_sample_t * buf,
+ sox_size_t len)
{
- vs_t v = (vs_t) ft->priv;
- sox_size_t done = 0;
- int rc = 0;
- int16_t sw;
- unsigned char uc;
+ vs_t v = (vs_t) ft->priv;
+ sox_size_t done = 0;
+ int rc = 0;
+ int16_t sw;
+ unsigned char uc;
- /* handle getting another cont. buffer */
- if (v->rest == 0)
- {
- rc = getblock(ft);
- if (rc)
- return 0;
- }
+ if (v->block_remaining == 0) { /* handle getting another cont. buffer */
+ rc = getblock(ft);
+ if (rc)
+ return 0;
+ }
+
+ if (v->block_remaining == 0) /* if no more data, return 0, i.e., done */
+ return 0;
- /* if no more data, return 0, i.e., done */
- if (v->rest == 0)
- return 0;
+ if (v->silent) {
+ for (; v->block_remaining && (done < len); v->block_remaining--, done++)
+ *buf++ = 0; /* Fill in silence */
+ } else { /* not silence; read len samples of audio from the file */
+ sox_size_t per = max(1, 9 / v->size);
- /* if silence, fill it in with 0's */
- if (v->silent) {
- /* Fill in silence */
- for(;v->rest && (done < len); v->rest--, done++)
- *buf++ = 0x80000000;
+ for (; (done + per <= len); done += per) {
+ if (v->block_remaining == 0) { /* IF no more in this block, get another */
+ while (v->block_remaining == 0) { /* until have either EOF or a block with data */
+ rc = getblock(ft);
+ if (rc)
+ break;
}
- /* else, not silence, read the block */
- else {
- /* read len samples of audio from the file */
+ if (rc) /* IF EOF, break out, no more data, next will return 0 */
+ break;
+ }
- /* for(;v->rest && (done < len); v->rest--, done++) { */
- for(; (done < len); done++) {
+ /* Read the data in the file */
+ if (v->size <= 4) {
+ if (!v->adpcm.setup.sign) {
+ if (sox_readb(ft, &uc) == SOX_EOF) {
+ sox_warn("VOC input: short file");
+ v->block_remaining = 0;
+ return done;
+ }
+ *buf = SOX_UNSIGNED_8BIT_TO_SAMPLE(uc,);
+ adpcm_init(&v->adpcm, 6 - v->size, SOX_SAMPLE_TO_SIGNED_16BIT(*buf, ft->clips));
+ ++buf;
+ --v->block_remaining;
+ ++done;
+ }
+ if (sox_readb(ft, &uc) == SOX_EOF) {
+ sox_warn("VOC input: short file");
+ v->block_remaining = 0;
+ return done;
+ }
+ switch (v->size) {
+ case 2:
+ if (v->format == VOC_FMT_CRLADPCM2) {
+ int u = uc;
- /* IF no more in this block, get another */
- if (v->rest == 0) {
+ *buf++ =
+ SOX_SIGNED_16BIT_TO_SAMPLE(adpcm_decode (u >> 6, &v->adpcm),);
+ *buf++ =
+ SOX_SIGNED_16BIT_TO_SAMPLE(adpcm_decode (u >> 4, &v->adpcm),);
+ *buf++ =
+ SOX_SIGNED_16BIT_TO_SAMPLE(adpcm_decode (u >> 2, &v->adpcm),);
+ *buf++ =
+ SOX_SIGNED_16BIT_TO_SAMPLE(adpcm_decode (u , &v->adpcm),);
+ }
+ break;
+ case 3:
+ if (v->format == VOC_FMT_CRLADPCM3) {
+ int u = uc;
- /* DO until we have either EOF or a block with data */
- while (v->rest == 0) {
- rc = getblock(ft);
- if (rc)
- break;
- }
- /* ENDDO ... */
+ *buf++ =
+ SOX_SIGNED_16BIT_TO_SAMPLE(adpcm_decode (u >> 5, &v->adpcm),);
+ *buf++ =
+ SOX_SIGNED_16BIT_TO_SAMPLE(adpcm_decode (u >> 2, &v->adpcm),);
+ *buf++ = /* A bit from nowhere! */
+ SOX_SIGNED_16BIT_TO_SAMPLE(adpcm_decode (u << 1, &v->adpcm),);
+ }
+ break;
+ case 4:
+ if (v->format == VOC_FMT_CRLADPCM4) {
+ int u = uc;
- /* IF EOF, break out, no more data, next will return 0 */
- if (rc)
- break;
- }
- /* ENDIF no more data in block */
-
- /* Read the data in the file */
- switch(v->size) {
- case 8:
- if (sox_readb(ft, &uc) == SOX_EOF) {
- sox_warn("VOC input: short file");
- v->rest = 0;
- return done;
- }
- /* IF uLaw,alaw, expand to linear, else convert??? */
- /* ANN: added uLaw and aLaw support */
- if (v->format == VOC_FMT_MU255) {
- *buf++ = SOX_ULAW_BYTE_TO_SAMPLE(uc);
- } else if (v->format == VOC_FMT_ALAW) {
- *buf++ = SOX_ALAW_BYTE_TO_SAMPLE(uc);
- } else {
- *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(uc,);
- }
- break;
- case 16:
- sox_readw(ft, (unsigned short *)&sw);
- if (sox_eof(ft))
- {
- sox_warn("VOC input: short file");
- v->rest = 0;
- return done;
- }
- *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(sw,);
- v->rest--; /* Processed 2 bytes so update */
- break;
- }
- /* decrement count of processed bytes */
- v->rest--; /* Processed 2 bytes so update */
+ *buf++ =
+ SOX_SIGNED_16BIT_TO_SAMPLE(adpcm_decode (u >> 4, &v->adpcm),);
+ *buf++ =
+ SOX_SIGNED_16BIT_TO_SAMPLE(adpcm_decode (u , &v->adpcm),);
+ }
+ break;
+ }
+ } else
+ switch (v->size) {
+ case 8:
+ if (sox_readb(ft, &uc) == SOX_EOF) {
+ sox_warn("VOC input: short file");
+ v->block_remaining = 0;
+ return done;
}
+ if (v->format == VOC_FMT_MU255) {
+ *buf++ = SOX_ULAW_BYTE_TO_SAMPLE(uc);
+ } else if (v->format == VOC_FMT_ALAW) {
+ *buf++ = SOX_ALAW_BYTE_TO_SAMPLE(uc);
+ } else {
+ *buf++ = SOX_UNSIGNED_8BIT_TO_SAMPLE(uc,);
+ }
+ break;
+ case 16:
+ sox_readw(ft, (unsigned short *) &sw);
+ if (sox_eof(ft)) {
+ sox_warn("VOC input: short file");
+ v->block_remaining = 0;
+ return done;
+ }
+ *buf++ = SOX_SIGNED_16BIT_TO_SAMPLE(sw,);
+ v->block_remaining--; /* Processed 2 bytes so update */
+ break;
}
- v->total_size+=done;
- return done;
+ /* decrement count of processed bytes */
+ v->block_remaining--;
+ }
+ }
+ v->total_size += done;
+ return done;
}
+
/* When saving samples in VOC format the following outline is followed:
* If an 8-bit mono sample then use a VOC_DATA header.
* If an 8-bit stereo sample then use a VOC_EXTENDED header followed
@@ -409,58 +453,55 @@
* which will work with the oldest software (eg. an 8-bit mono sample
* will be able to be played with a really old SB VOC player.)
*/
-static int sox_vocstartwrite(sox_format_t * ft)
+static int startwrite(sox_format_t * ft)
{
- vs_t v = (vs_t) ft->priv;
+ vs_t v = (vs_t) ft->priv;
- if (! ft->seekable)
- {
- sox_fail_errno(ft,SOX_EOF,
- "Output .voc file must be a file, not a pipe");
- return(SOX_EOF);
- }
+ if (!ft->seekable) {
+ sox_fail_errno(ft, SOX_EOF,
+ "Output .voc file must be a file, not a pipe");
+ return (SOX_EOF);
+ }
- v->samples = 0;
+ v->samples = 0;
- /* File format name and a ^Z (aborts printing under DOS) */
- sox_writes(ft, "Creative Voice File\032");
- sox_writew(ft, 26); /* size of header */
- sox_writew(ft, 0x10a); /* major/minor version number */
- sox_writew(ft, 0x1129); /* checksum of version number */
+ /* File format name and a ^Z (aborts printing under DOS) */
+ sox_writes(ft, "Creative Voice File\032");
+ sox_writew(ft, 26); /* size of header */
+ sox_writew(ft, 0x10a); /* major/minor version number */
+ sox_writew(ft, 0x1129); /* checksum of version number */
- if (ft->signal.channels == 0)
- ft->signal.channels = 1;
-
- return(SOX_SUCCESS);
+ return (SOX_SUCCESS);
}
/*-----------------------------------------------------------------
- * sox_vocwrite() -- write a VOC file
+ * write() -- write a VOC file
*-----------------------------------------------------------------*/
-static sox_size_t sox_vocwrite(sox_format_t * ft, const sox_sample_t *buf, sox_size_t len)
+static sox_size_t write_samples(sox_format_t * ft, const sox_sample_t * buf,
+ sox_size_t len)
{
- vs_t v = (vs_t) ft->priv;
- unsigned char uc;
- int16_t sw;
- sox_size_t done = 0;
+ vs_t v = (vs_t) ft->priv;
+ unsigned char uc;
+ int16_t sw;
+ sox_size_t done = 0;
- if (v->samples == 0) {
- /* No silence packing yet. */
- v->silent = 0;
- blockstart(ft);
- }
- v->samples += len;
- while(done < len) {
- if (ft->encoding.bits_per_sample == 8) {
- uc = SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips);
- sox_writeb(ft, uc);
- } else {
- sw = (int) SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips);
- sox_writesw(ft,sw);
- }
- done++;
- }
- return done;
+ if (v->samples == 0) {
+ /* No silence packing yet. */
+ v->silent = 0;
+ blockstart(ft);
+ }
+ v->samples += len;
+ while (done < len) {
+ if (ft->encoding.bits_per_sample == 8) {
+ uc = SOX_SAMPLE_TO_UNSIGNED_8BIT(*buf++, ft->clips);
+ sox_writeb(ft, uc);
+ } else {
+ sw = (int) SOX_SAMPLE_TO_SIGNED_16BIT(*buf++, ft->clips);
+ sox_writesw(ft, sw);
+ }
+ done++;
+ }
+ return done;
}
/*-----------------------------------------------------------------
@@ -469,37 +510,37 @@
*-----------------------------------------------------------------*/
static void blockstop(sox_format_t * ft)
{
- vs_t v = (vs_t) ft->priv;
- sox_sample_t datum;
+ vs_t v = (vs_t) ft->priv;
+ sox_sample_t datum;
- sox_writeb(ft, 0); /* End of file block code */
- sox_seeki(ft, (sox_ssize_t)v->blockseek, 0); /* seek back to block length */
- sox_seeki(ft, 1, 1); /* seek forward one */
- if (v->silent) {
- sox_writesw(ft, v->samples);
- } else {
- if (ft->encoding.bits_per_sample == 8) {
- if (ft->signal.channels > 1) {
- sox_seeki(ft, 8, 1); /* forward 7 + 1 for new block header */
- }
- }
- v->samples += 2; /* adjustment: SBDK pp. 3-5 */
- datum = (v->samples * (ft->encoding.bits_per_sample >> 3)) & 0xff;
- sox_writesb(ft, datum); /* low byte of length */
- datum = ((v->samples * (ft->encoding.bits_per_sample >> 3)) >> 8) & 0xff;
- sox_writesb(ft, datum); /* middle byte of length */
- datum = ((v->samples * (ft->encoding.bits_per_sample >> 3))>> 16) & 0xff;
- sox_writesb(ft, datum); /* high byte of length */
- }
+ sox_writeb(ft, 0); /* End of file block code */
+ sox_seeki(ft, (sox_ssize_t) v->blockseek, 0); /* seek back to block length */
+ sox_seeki(ft, 1, 1); /* seek forward one */
+ if (v->silent) {
+ sox_writesw(ft, v->samples);
+ } else {
+ if (ft->encoding.bits_per_sample == 8) {
+ if (ft->signal.channels > 1) {
+ sox_seeki(ft, 8, 1); /* forward 7 + 1 for new block header */
+ }
+ }
+ v->samples += 2; /* adjustment: SBDK pp. 3-5 */
+ datum = (v->samples * (ft->encoding.bits_per_sample >> 3)) & 0xff;
+ sox_writesb(ft, datum); /* low byte of length */
+ datum = ((v->samples * (ft->encoding.bits_per_sample >> 3)) >> 8) & 0xff;
+ sox_writesb(ft, datum); /* middle byte of length */
+ datum = ((v->samples * (ft->encoding.bits_per_sample >> 3)) >> 16) & 0xff;
+ sox_writesb(ft, datum); /* high byte of length */
+ }
}
/*-----------------------------------------------------------------
- * sox_vocstopwrite() -- stop writing a VOC file
+ * stopwrite() -- stop writing a VOC file
*-----------------------------------------------------------------*/
-static int sox_vocstopwrite(sox_format_t * ft)
+static int stopwrite(sox_format_t * ft)
{
- blockstop(ft);
- return(SOX_SUCCESS);
+ blockstop(ft);
+ return (SOX_SUCCESS);
}
/*-----------------------------------------------------------------
@@ -512,226 +553,176 @@
*-----------------------------------------------------------------*/
static int getblock(sox_format_t * ft)
{
- vs_t v = (vs_t) ft->priv;
- unsigned char uc, block;
- uint32_t sblen;
- uint16_t new_rate_16;
- uint32_t new_rate_32;
- uint32_t i;
- uint32_t trash;
+ vs_t v = (vs_t) ft->priv;
+ unsigned char uc, block;
+ uint24_t sblen;
+ uint16_t new_rate_16;
+ uint32_t new_rate_32;
+ uint32_t i;
+ uint32_t trash;
- v->silent = 0;
- /* DO while we have no audio to read */
- while (v->rest == 0) {
- /* IF EOF, return EOF
- * ANN: was returning SUCCESS */
- if (sox_eof(ft))
- return SOX_EOF;
+ v->silent = 0;
+ /* DO while we have no audio to read */
+ while (v->block_remaining == 0) {
+ if (sox_eof(ft))
+ return SOX_EOF;
- if (sox_readb(ft, &block) == SOX_EOF)
- return SOX_EOF;
+ if (sox_readb(ft, &block) == SOX_EOF)
+ return SOX_EOF;
- /* IF TERM block (end of file), return EOF */
- if (block == VOC_TERM)
- return SOX_EOF;
+ if (block == VOC_TERM)
+ return SOX_EOF;
- /* IF EOF after reading block type, return EOF
- * ANN: was returning SUCCESS */
- if (sox_eof(ft))
- return SOX_EOF;
- /*
- * Size is an 24-bit value. Currently there is no util
- * func to read this so do it this cross-platform way
- *
- */
- sox_readb(ft, &uc);
- sblen = uc;
- sox_readb(ft, &uc);
- sblen |= ((uint32_t) uc) << 8;
- sox_readb(ft, &uc);
- sblen |= ((uint32_t) uc) << 16;
+ if (sox_eof(ft))
+ return SOX_EOF;
- /* Based on VOC block type, process the block */
- /* audio may be in one or multiple blocks */
- switch(block) {
- case VOC_DATA:
- sox_readb(ft, &uc);
- /* When DATA block preceeded by an EXTENDED */
- /* block, the DATA blocks rate value is invalid */
- if (!v->extended) {
- if (uc == 0)
- {
- sox_fail_errno(ft, SOX_EFMT, "Sample rate is zero?");
- return(SOX_EOF);
- }
- if ((v->rate != -1) && (uc != v->rate))
- {
- sox_fail_errno(ft,SOX_EFMT,
- "sample rate codes differ: %ld != %d", v->rate, uc);
- return(SOX_EOF);
- }
- v->rate = uc;
- ft->signal.rate = 1000000.0/(256 - v->rate);
- v->channels = 1;
- }
- sox_readb(ft, &uc);
- if (uc != 0)
- {
- sox_fail_errno(ft,SOX_EFMT,
- "only interpret 8-bit data!");
- return(SOX_EOF);
- }
- v->extended = 0;
- v->rest = sblen - 2;
- v->size = 8;
- return (SOX_SUCCESS);
- case VOC_DATA_16:
- sox_readdw(ft, &new_rate_32);
- if (new_rate_32 == 0)
- {
- sox_fail_errno(ft,SOX_EFMT,
- "Sample rate is zero?");
- return(SOX_EOF);
- }
- if ((v->rate != -1) && ((long)new_rate_32 != v->rate))
- {
- sox_fail_errno(ft,SOX_EFMT,
- "sample rate codes differ: %ld != %d",
- v->rate, new_rate_32);
- return(SOX_EOF);
- }
- v->rate = new_rate_32;
- ft->signal.rate = new_rate_32;
- sox_readb(ft, &uc);
- switch (uc)
- {
- case 8: v->size = 8; break;
- case 16: v->size = 16; break;
- default:
- sox_fail_errno(ft,SOX_EFMT,
- "Don't understand size %d", uc);
- return(SOX_EOF);
- }
- sox_readb(ft, &(v->channels));
- sox_readw(ft, &(v->format)); /* ANN: added format */
- sox_readb(ft, (unsigned char *)&trash); /* notused */
- sox_readb(ft, (unsigned char *)&trash); /* notused */
- sox_readb(ft, (unsigned char *)&trash); /* notused */
- sox_readb(ft, (unsigned char *)&trash); /* notused */
- v->rest = sblen - 12;
- return (SOX_SUCCESS);
- case VOC_CONT:
- v->rest = sblen;
- return (SOX_SUCCESS);
- case VOC_SILENCE:
- {
- unsigned short period;
+ sox_read3(ft, &sblen);
+
+ /* Based on VOC block type, process the block */
+ /* audio may be in one or multiple blocks */
+ switch (block) {
+ case VOC_DATA:
+ sox_readb(ft, &uc);
+ /* When DATA block preceeded by an EXTENDED */
+ /* block, the DATA blocks rate value is invalid */
+ if (!v->extended) {
+ if (uc == 0) {
+ sox_fail_errno(ft, SOX_EFMT, "Sample rate is zero?");
+ return (SOX_EOF);
+ }
+ if ((v->rate != -1) && (uc != v->rate)) {
+ sox_fail_errno(ft, SOX_EFMT,
+ "sample rate codes differ: %ld != %d", v->rate,
+ uc);
+ return (SOX_EOF);
+ }
+ v->rate = uc;
+ ft->signal.rate = 1000000.0 / (256 - v->rate);
+ v->channels = 1;
+ }
+ sox_readb(ft, &uc);
+ v->format = uc;
+ v->extended = 0;
+ v->block_remaining = sblen - 2;
+ return (SOX_SUCCESS);
+ case VOC_DATA_16:
+ sox_readdw(ft, &new_rate_32);
+ if (new_rate_32 == 0) {
+ sox_fail_errno(ft, SOX_EFMT, "Sample rate is zero?");
+ return (SOX_EOF);
+ }
+ if ((v->rate != -1) && ((long) new_rate_32 != v->rate)) {
+ sox_fail_errno(ft, SOX_EFMT, "sample rate codes differ: %ld != %d",
+ v->rate, new_rate_32);
+ return (SOX_EOF);
+ }
+ v->rate = new_rate_32;
+ ft->signal.rate = new_rate_32;
+ sox_readb(ft, &uc);
+ v->size = uc;
+ sox_readb(ft, &(v->channels));
+ sox_readw(ft, &(v->format)); /* ANN: added format */
+ sox_readb(ft, (unsigned char *) &trash); /* notused */
+ sox_readb(ft, (unsigned char *) &trash); /* notused */
+ sox_readb(ft, (unsigned char *) &trash); /* notused */
+ sox_readb(ft, (unsigned char *) &trash); /* notused */
+ v->block_remaining = sblen - 12;
+ return (SOX_SUCCESS);
+ case VOC_CONT:
+ v->block_remaining = sblen;
+ return (SOX_SUCCESS);
+ case VOC_SILENCE:
+ {
+ unsigned short period;
- sox_readw(ft, &period);
- sox_readb(ft, &uc);
- if (uc == 0)
- {
- sox_fail_errno(ft,SOX_EFMT, "Silence sample rate is zero");
- return(SOX_EOF);
- }
- /*
- * Some silence-packed files have gratuitously
- * different sample rate codes in silence.
- * Adjust period.
- */
- if ((v->rate != -1) && (uc != v->rate))
- period = (period * (256 - uc))/(256 - v->rate);
- else
- v->rate = uc;
- v->rest = period;
- v->silent = 1;
- return (SOX_SUCCESS);
- }
- case VOC_MARKER:
- sox_readb(ft, &uc);
- sox_readb(ft, &uc);
- /* Falling! Falling! */
- case VOC_TEXT:
- {
- /* TODO: Could add to comment in SF? */
-
- /* Note, if this is sent to stderr, studio */
- /* will not be able to read the VOC file */
-
- uint32_t i = sblen;
- char c/*, line_buf[80];
- int len = 0*/;
+ sox_readw(ft, &period);
+ sox_readb(ft, &uc);
+ if (uc == 0) {
+ sox_fail_errno(ft, SOX_EFMT, "Silence sample rate is zero");
+ return (SOX_EOF);
+ }
+ /*
+ * Some silence-packed files have gratuitously
+ * different sample rate codes in silence.
+ * Adjust period.
+ */
+ if ((v->rate != -1) && (uc != v->rate))
+ period = (period * (256. - uc)) / (256 - v->rate) + .5;
+ else
+ v->rate = uc;
+ v->block_remaining = period;
+ v->silent = 1;
+ return (SOX_SUCCESS);
+ }
+ case VOC_MARKER:
+ sox_readb(ft, &uc);
+ sox_readb(ft, &uc);
+ /* Falling! Falling! */
+ case VOC_TEXT:
+ {
+ uint32_t i = sblen;
+ char c /*, line_buf[80];
+ * int len = 0 */ ;
- while (i--)
- {
- sox_readb(ft, (unsigned char *)&c);
- /* FIXME: this needs to be tested but I couldn't
- * find a voc file with a VOC_TEXT chunk :(
- if (c != '\0' && c != '\r')
- line_buf[len++] = c;
- if (len && (c == '\0' || c == '\r' ||
- i == 0 || len == sizeof(line_buf) - 1))
- {
- sox_report("%s", line_buf);
- line_buf[len] = '\0';
- len = 0;
- }
- */
- }
- }
- continue; /* get next block */
- case VOC_LOOP:
- case VOC_LOOPEND:
- sox_debug("skipping repeat loop");
- for(i = 0; i < sblen; i++)
- sox_readb(ft, (unsigned char *)&trash);
- break;
- case VOC_EXTENDED:
- /* An Extended block is followed by a data block */
- /* Set this byte so we know to use the rate */
- /* value from the extended block and not the */
- /* data block. */
- v->extended = 1;
- sox_readw(ft, &new_rate_16);
- if (new_rate_16 == 0)
- {
- sox_fail_errno(ft,SOX_EFMT, "Sample rate is zero?");
- return(SOX_EOF);
- }
- if ((v->rate != -1) && (new_rate_16 != v->rate))
- {
- sox_fail_errno(ft,SOX_EFMT,
- "sample rate codes differ: %ld != %d",
- v->rate, new_rate_16);
- return(SOX_EOF);
- }
- v->rate = new_rate_16;
- sox_readb(ft, &uc);
- if (uc != 0)
- {
- sox_fail_errno(ft,SOX_EFMT,
- "only interpret 8-bit data!");
- return(SOX_EOF);
- }
- sox_readb(ft, &uc);
- if (uc)
- ft->signal.channels = 2; /* Stereo */
- /* Needed number of channels before finishing
- compute for rate */
- ft->signal.rate = (256000000/(65536 - v->rate))/
- ft->signal.channels;
- /* An extended block must be followed by a data */
- /* block to be valid so loop back to top so it */
- /* can be grabed. */
- continue;
- default:
- sox_debug("skipping unknown block code %d", block);
- for(i = 0; i < sblen; i++)
- sox_readb(ft, (unsigned char *)&trash);
- }
- }
- return SOX_SUCCESS;
-}
+ sox_warn("VOC TEXT");
+ while (i--) {
+ sox_readb(ft, (unsigned char *) &c);
+ /* FIXME: this needs to be tested but I couldn't
+ * find a voc file with a VOC_TEXT chunk :(
+ if (c != '\0' && c != '\r')
+ line_buf[len++] = c;
+ if (len && (c == '\0' || c == '\r' ||
+ i == 0 || len == sizeof(line_buf) - 1))
+ {
+ sox_report("%s", line_buf);
+ line_buf[len] = '\0';
+ len = 0;
+ }
+ */
+ }
+ }
+ continue; /* get next block */
+ case VOC_LOOP:
+ case VOC_LOOPEND:
+ sox_debug("skipping repeat loop");
+ for (i = 0; i < sblen; i++)
+ sox_readb(ft, (unsigned char *) &trash);
+ break;
+ case VOC_EXTENDED:
+ /* An Extended block is followed by a data block */
+ /* Set this byte so we know to use the rate */
+ /* value from the extended block and not the */
+ /* data block. */
+ v->extended = 1;
+ sox_readw(ft, &new_rate_16);
+ if (new_rate_16 == 0) {
+ sox_fail_errno(ft, SOX_EFMT, "Sample rate is zero?");
+ return (SOX_EOF);
+ }
+ if ((v->rate != -1) && (new_rate_16 != v->rate)) {
+ sox_fail_errno(ft, SOX_EFMT, "sample rate codes differ: %ld != %d",
+ v->rate, new_rate_16);
+ return (SOX_EOF);
+ }
+ v->rate = new_rate_16;
+ sox_readb(ft, &uc); /* bits_per_sample */
+ sox_readb(ft, &uc);
+ ft->signal.channels = uc? 2 : 1; /* Stereo */
+ /* Needed number of channels before finishing
+ * compute for rate */
+ ft->signal.rate = (256e6 / (65536 - v->rate)) / ft->signal.channels;
+ /* An extended block must be followed by a data */
+ /* block to be valid so loop back to top so it */
+ /* can be grabed. */
+ continue;
+ default:
+ sox_debug("skipping unknown block code %d", block);
+ for (i = 0; i < sblen; i++)
+ sox_readb(ft, (unsigned char *) &trash);
+ }
+ }
+ return SOX_SUCCESS;
+}
/*-----------------------------------------------------------------
* vlockstart() -- start an output block
@@ -738,68 +729,69 @@
*-----------------------------------------------------------------*/
static void blockstart(sox_format_t * ft)
{
- vs_t v = (vs_t) ft->priv;
+ vs_t v = (vs_t) ft->priv;
- v->blockseek = sox_tell(ft);
- if (v->silent) {
- sox_writeb(ft, VOC_SILENCE); /* Silence block code */
- sox_writeb(ft, 0); /* Period length */
- sox_writeb(ft, 0); /* Period length */
- sox_writesb(ft, v->rate); /* Rate code */
- } else {
- if (ft->encoding.bits_per_sample == 8) {
- /* 8-bit sample section. By always setting the correct */
- /* rate value in the DATA block (even when its preceeded */
- /* by an EXTENDED block) old software can still play stereo */
- /* files in mono by just skipping over the EXTENDED block. */
- /* Prehaps the rate should be doubled though to make up for */
- /* double amount of samples for a given time???? */
- if (ft->signal.channels > 1) {
- sox_writeb(ft, VOC_EXTENDED); /* Voice Extended block code */
- sox_writeb(ft, 4); /* block length = 4 */
- sox_writeb(ft, 0); /* block length = 4 */
- sox_writeb(ft, 0); /* block length = 4 */
- v->rate = 65536 - (256000000.0/(2*(float)ft->signal.rate));
- sox_writesw(ft,v->rate); /* Rate code */
- sox_writeb(ft, 0); /* File is not packed */
- sox_writeb(ft, 1); /* samples are in stereo */
- }
- sox_writeb(ft, VOC_DATA); /* Voice Data block code */
- sox_writeb(ft, 0); /* block length (for now) */
- sox_writeb(ft, 0); /* block length (for now) */
- sox_writeb(ft, 0); /* block length (for now) */
- v->rate = 256 - (1000000.0/(float)ft->signal.rate);
- sox_writesb(ft, (int) v->rate);/* Rate code */
- sox_writeb(ft, 0); /* 8-bit raw data */
- } else {
- sox_writeb(ft, VOC_DATA_16); /* Voice Data block code */
- sox_writeb(ft, 0); /* block length (for now) */
- sox_writeb(ft, 0); /* block length (for now) */
- sox_writeb(ft, 0); /* block length (for now) */
- v->rate = ft->signal.rate;
- sox_writedw(ft, (unsigned)v->rate); /* Rate code */
- sox_writeb(ft, 16); /* Sample Size */
- sox_writeb(ft, ft->signal.channels); /* Sample Size */
- sox_writew(ft, 0x0004); /* Encoding */
- sox_writeb(ft, 0); /* Unused */
- sox_writeb(ft, 0); /* Unused */
- sox_writeb(ft, 0); /* Unused */
- sox_writeb(ft, 0); /* Unused */
- }
- }
+ v->blockseek = sox_tell(ft);
+ if (v->silent) {
+ sox_writeb(ft, VOC_SILENCE); /* Silence block code */
+ sox_writeb(ft, 0); /* Period length */
+ sox_writeb(ft, 0); /* Period length */
+ sox_writesb(ft, v->rate); /* Rate code */
+ } else {
+ if (ft->encoding.bits_per_sample == 8) {
+ /* 8-bit sample section. By always setting the correct */
+ /* rate value in the DATA block (even when its preceeded */
+ /* by an EXTENDED block) old software can still play stereo */
+ /* files in mono by just skipping over the EXTENDED block. */
+ /* Prehaps the rate should be doubled though to make up for */
+ /* double amount of samples for a given time???? */
+ if (ft->signal.channels > 1) {
+ sox_writeb(ft, VOC_EXTENDED); /* Voice Extended block code */
+ sox_writeb(ft, 4); /* block length = 4 */
+ sox_writeb(ft, 0); /* block length = 4 */
+ sox_writeb(ft, 0); /* block length = 4 */
+ v->rate = 65536 - (256000000.0 / (2 * ft->signal.rate)) + .5;
+ sox_writesw(ft, v->rate); /* Rate code */
+ sox_writeb(ft, 0); /* File is not packed */
+ sox_writeb(ft, 1); /* samples are in stereo */
+ }
+ sox_writeb(ft, VOC_DATA); /* Voice Data block code */
+ sox_writeb(ft, 0); /* block length (for now) */
+ sox_writeb(ft, 0); /* block length (for now) */
+ sox_writeb(ft, 0); /* block length (for now) */
+ v->rate = 256 - (1000000.0 / ft->signal.rate) + .5;
+ sox_writesb(ft, v->rate); /* Rate code */
+ sox_writeb(ft, 0); /* 8-bit raw data */
+ } else {
+ sox_writeb(ft, VOC_DATA_16); /* Voice Data block code */
+ sox_writeb(ft, 0); /* block length (for now) */
+ sox_writeb(ft, 0); /* block length (for now) */
+ sox_writeb(ft, 0); /* block length (for now) */
+ v->rate = ft->signal.rate + .5;
+ sox_writedw(ft, (unsigned) v->rate); /* Rate code */
+ sox_writeb(ft, 16); /* Sample Size */
+ sox_writeb(ft, ft->signal.channels); /* Sample Size */
+ sox_writew(ft, 0x0004); /* Encoding */
+ sox_writeb(ft, 0); /* Unused */
+ sox_writeb(ft, 0); /* Unused */
+ sox_writeb(ft, 0); /* Unused */
+ sox_writeb(ft, 0); /* Unused */
+ }
+ }
}
SOX_FORMAT_HANDLER(voc)
{
- static char const * const names[] = {"voc", NULL};
+ static char const *const names[] = { "voc", NULL };
static unsigned const write_encodings[] = {
SOX_ENCODING_SIGN2, 16, 0,
SOX_ENCODING_UNSIGNED, 8, 0,
- 0};
+ 0
+ };
static sox_format_handler_t const handler = {
- names, SOX_FILE_LIT_END|SOX_FILE_MONO|SOX_FILE_STEREO,
- sox_vocstartread, sox_vocread, NULL,
- sox_vocstartwrite, sox_vocwrite, sox_vocstopwrite,
+ names, SOX_FILE_LIT_END | SOX_FILE_MONO | SOX_FILE_STEREO,
+ startread, read_samples, NULL,
+ startwrite, write_samples, stopwrite,
NULL, write_encodings, NULL
};
return &handler;