ref: a5092b2f444acc4875b2e2e5f82a2e1ebda15fc5
parent: 1e0a00d4e1d42f775a426519c97fbb2e7a648fe5
author: Mans Rullgard <mans@mansr.com>
date: Fri Aug 7 09:26:05 EDT 2020
wav: move adpcm/gsm fmt parsing to separate functions
--- a/src/wav.c
+++ b/src/wav.c
@@ -69,6 +69,7 @@
unsigned short formatTag; /* What type of encoding file is using */
unsigned short samplesPerBlock;
unsigned short blockAlign;
+ uint16_t bitsPerSample; /* bits per sample */
size_t dataStart; /* need to for seeking */
int ignoreSize; /* ignoreSize allows us to process 32-bit WAV files that are
* greater then 2 Gb and can't be represented by the
@@ -102,6 +103,43 @@
/* IMA ADPCM Support Functions Section */
/****************************************************************************/
+static int wav_ima_adpcm_fmt(sox_format_t *ft, uint32_t len)
+{
+ priv_t *wav = ft->priv;
+ size_t bytesPerBlock;
+
+ if (len < 2) {
+ lsx_fail_errno(ft, SOX_EOF, "format[%s]: expects cbSize >= %d",
+ wav_format_str(wav->formatTag), 2);
+ return SOX_EOF;
+ }
+
+ if (wav->bitsPerSample != 4) {
+ lsx_fail_errno(ft, SOX_EOF,
+ "Can only handle 4-bit IMA ADPCM in wav files");
+ return SOX_EOF;
+ }
+
+ lsx_readw(ft, &wav->samplesPerBlock);
+
+ bytesPerBlock = lsx_ima_bytes_per_block(ft->signal.channels,
+ wav->samplesPerBlock);
+
+ if (bytesPerBlock != wav->blockAlign || wav->samplesPerBlock % 8 != 1) {
+ lsx_fail_errno(ft, SOX_EOF,
+ "format[%s]: samplesPerBlock(%d) != blockAlign(%d)",
+ wav_format_str(wav->formatTag),
+ wav->samplesPerBlock, wav->blockAlign);
+ return SOX_EOF;
+ }
+
+ wav->packet = lsx_malloc(wav->blockAlign);
+ wav->samples =
+ lsx_malloc(ft->signal.channels * wav->samplesPerBlock * sizeof(short));
+
+ return SOX_SUCCESS;
+}
+
/*
*
* ImaAdpcmReadBlock - Grab and decode complete block of samples
@@ -142,6 +180,74 @@
/* MS ADPCM Support Functions Section */
/****************************************************************************/
+static int wav_ms_adpcm_fmt(sox_format_t *ft, uint32_t len)
+{
+ priv_t *wav = ft->priv;
+ size_t bytesPerBlock;
+ int i, errct = 0;
+
+ if (len < 4) {
+ lsx_fail_errno(ft, SOX_EOF, "format[%s]: expects cbSize >= %d",
+ wav_format_str(wav->formatTag), 4);
+ return SOX_EOF;
+ }
+
+ if (wav->bitsPerSample != 4) {
+ lsx_fail_errno(ft, SOX_EOF,
+ "Can only handle 4-bit MS ADPCM in wav files");
+ return SOX_EOF;
+ }
+
+ lsx_readw(ft, &wav->samplesPerBlock);
+ lsx_readw(ft, &wav->nCoefs);
+ len -= 4;
+
+ bytesPerBlock = lsx_ms_adpcm_bytes_per_block(ft->signal.channels,
+ wav->samplesPerBlock);
+
+ if (bytesPerBlock != wav->blockAlign) {
+ lsx_fail_errno(ft, SOX_EOF,
+ "format[%s]: samplesPerBlock(%d) != blockAlign(%d)",
+ wav_format_str(wav->formatTag),
+ wav->samplesPerBlock, wav->blockAlign);
+ return SOX_EOF;
+ }
+
+ if (wav->nCoefs < 7 || wav->nCoefs > 0x100) {
+ lsx_fail_errno(ft, SOX_EOF,
+ "ADPCM file nCoefs (%.4hx) makes no sense",
+ wav->nCoefs);
+ return SOX_EOF;
+ }
+
+ if (len < 4 * wav->nCoefs) {
+ lsx_fail_errno(ft, SOX_EOF, "wave header error: cbSize too small");
+ return SOX_EOF;
+ }
+
+ wav->packet = lsx_malloc(wav->blockAlign);
+ wav->samples =
+ lsx_malloc(ft->signal.channels * wav->samplesPerBlock * sizeof(short));
+
+ /* nCoefs, lsx_ms_adpcm_i_coefs used by adpcm.c */
+ wav->lsx_ms_adpcm_i_coefs = lsx_malloc(wav->nCoefs * 2 * sizeof(short));
+ wav->ms_adpcm_data = lsx_ms_adpcm_alloc(ft->signal.channels);
+
+ for (i = 0; len >= 2 && i < 2 * wav->nCoefs; i++) {
+ lsx_readsw(ft, &wav->lsx_ms_adpcm_i_coefs[i]);
+ len -= 2;
+
+ if (i < 14)
+ errct +=
+ wav->lsx_ms_adpcm_i_coefs[i] != lsx_ms_adpcm_i_coef[i/2][i%2];
+ }
+
+ if (errct)
+ lsx_warn("base lsx_ms_adpcm_i_coefs differ in %d/14 positions", errct);
+
+ return SOX_SUCCESS;
+}
+
/*
*
* AdpcmReadBlock - Grab and decode complete block of samples
@@ -220,6 +326,36 @@
/****************************************************************************/
/* WAV GSM6.10 support functions */
/****************************************************************************/
+
+static int wav_gsm_fmt(sox_format_t *ft, uint32_t len)
+{
+ priv_t *wav = ft->priv;
+
+ if (len < 2) {
+ lsx_fail_errno(ft, SOX_EOF, "format[%s]: expects wExtSize >= %d",
+ wav_format_str(wav->formatTag), 2);
+ return SOX_EOF;
+ }
+
+ lsx_readw(ft, &wav->samplesPerBlock);
+
+ if (wav->blockAlign != 65) {
+ lsx_fail_errno(ft, SOX_EOF, "format[%s]: expects blockAlign(%d) = %d",
+ wav_format_str(wav->formatTag), wav->blockAlign, 65);
+ return SOX_EOF;
+ }
+
+ if (wav->samplesPerBlock != 320) {
+ lsx_fail_errno(ft, SOX_EOF,
+ "format[%s]: expects samplesPerBlock(%d) = %d",
+ wav_format_str(wav->formatTag),
+ wav->samplesPerBlock, 320);
+ return SOX_EOF;
+ }
+
+ return SOX_SUCCESS;
+}
+
/* create the gsm object, malloc buffer for 160*2 samples */
static int wavgsminit(sox_format_t * ft)
{
@@ -382,9 +518,7 @@
uint16_t wChannels; /* number of channels */
uint32_t dwSamplesPerSecond; /* samples per second per channel */
uint32_t dwAvgBytesPerSec; /* estimate of bytes per second needed */
- uint16_t wBitsPerSample; /* bits per sample */
uint16_t wExtSize = 0; /* extended field for non-PCM */
- size_t bytesPerBlock = 0;
int bytespersample; /* bytes per sample (per channel */
sox_encoding_t enc = SOX_ENCODING_UNKNOWN;;
@@ -398,7 +532,7 @@
lsx_readdw(ft, &dwSamplesPerSecond);
lsx_readdw(ft, &dwAvgBytesPerSec); /* Average bytes/second */
lsx_readw(ft, &wav->blockAlign); /* Block align */
- lsx_readw(ft, &wBitsPerSample); /* bits per sample per channel */
+ lsx_readw(ft, &wav->bitsPerSample); /* bits per sample per channel */
len -= 16;
/* non-PCM formats except alaw and mulaw formats have extended fmt chunk.
@@ -437,7 +571,7 @@
lsx_skipbytes(ft, 14);
len -= 22;
- if (numberOfValidBits != wBitsPerSample) {
+ if (numberOfValidBits != wav->bitsPerSample) {
lsx_fail_errno(ft, SOX_EHDR, "WAVE file fmt with padded samples is not supported yet");
return SOX_EOF;
}
@@ -498,147 +632,35 @@
switch (wav->formatTag) {
case WAVE_FORMAT_ADPCM:
- if (wExtSize < 4) {
- lsx_fail_errno(ft, SOX_EOF, "format[%s]: expects wExtSize >= %d",
- wav_format_str(wav->formatTag), 4);
+ if (wav_ms_adpcm_fmt(ft, len))
return SOX_EOF;
- }
- if (wBitsPerSample != 4) {
- lsx_fail_errno(ft, SOX_EOF,
- "Can only handle 4-bit MS ADPCM in wav files");
- return SOX_EOF;
- }
-
- lsx_readw(ft, &wav->samplesPerBlock);
- lsx_readw(ft, &wav->nCoefs);
- len -= 4;
-
- bytesPerBlock = lsx_ms_adpcm_bytes_per_block(ft->signal.channels,
- wav->samplesPerBlock);
-
- if (bytesPerBlock != wav->blockAlign) {
- lsx_fail_errno(ft, SOX_EOF,
- "format[%s]: samplesPerBlock(%d) != blockAlign(%d)",
- wav_format_str(wav->formatTag),
- wav->samplesPerBlock, wav->blockAlign);
- return SOX_EOF;
- }
-
- if (wav->nCoefs < 7 || wav->nCoefs > 0x100) {
- lsx_fail_errno(ft, SOX_EOF,
- "ADPCM file nCoefs (%.4hx) makes no sense",
- wav->nCoefs);
- return SOX_EOF;
- }
-
- if (wExtSize < 4 + 4 * wav->nCoefs) {
- lsx_fail_errno(ft, SOX_EOF, "wave header error: wExtSize(%d) too small for nCoefs(%d)", wExtSize, wav->nCoefs);
- return SOX_EOF;
- }
-
- wav->packet = lsx_malloc(wav->blockAlign);
- wav->samples =
- lsx_malloc(wChannels * wav->samplesPerBlock * sizeof(short));
-
- /* nCoefs, lsx_ms_adpcm_i_coefs used by adpcm.c */
- wav->lsx_ms_adpcm_i_coefs = lsx_malloc(wav->nCoefs * 2 * sizeof(short));
- wav->ms_adpcm_data = lsx_ms_adpcm_alloc(wChannels);
-
- {
- int i, errct = 0;
-
- for (i = 0; len >= 2 && i < 2 * wav->nCoefs; i++) {
- lsx_readsw(ft, &wav->lsx_ms_adpcm_i_coefs[i]);
- len -= 2;
-
- if (i < 14)
- errct += wav->lsx_ms_adpcm_i_coefs[i] !=
- lsx_ms_adpcm_i_coef[i / 2][i % 2];
- }
-
- if (errct)
- lsx_warn("base lsx_ms_adpcm_i_coefs differ in %d/14 positions",
- errct);
- }
-
bytespersample = 2; /* AFTER de-compression */
break;
case WAVE_FORMAT_IMA_ADPCM:
- if (wExtSize < 2) {
- lsx_fail_errno(ft, SOX_EOF, "format[%s]: expects wExtSize >= %d",
- wav_format_str(wav->formatTag), 2);
+ if (wav_ima_adpcm_fmt(ft, len))
return SOX_EOF;
- }
- if (wBitsPerSample != 4) {
- lsx_fail_errno(ft, SOX_EOF,
- "Can only handle 4-bit IMA ADPCM in wav files");
- return SOX_EOF;
- }
-
- lsx_readw(ft, &wav->samplesPerBlock);
- len -= 2;
-
- bytesPerBlock = lsx_ima_bytes_per_block(ft->signal.channels,
- wav->samplesPerBlock);
-
- if (bytesPerBlock != wav->blockAlign || wav->samplesPerBlock % 8 != 1) {
- lsx_fail_errno(ft, SOX_EOF,
- "format[%s]: samplesPerBlock(%d) != blockAlign(%d)",
- wav_format_str(wav->formatTag),
- wav->samplesPerBlock, wav->blockAlign);
- return SOX_EOF;
- }
-
- wav->packet = lsx_malloc(wav->blockAlign);
- wav->samples =
- lsx_malloc(wChannels * wav->samplesPerBlock * sizeof(short));
-
bytespersample = 2; /* AFTER de-compression */
break;
- /* GSM formats have extended fmt chunk. Check for those cases. */
case WAVE_FORMAT_GSM610:
- if (wExtSize < 2) {
- lsx_fail_errno(ft, SOX_EOF, "format[%s]: expects wExtSize >= %d",
- wav_format_str(wav->formatTag), 2);
+ if (wav_gsm_fmt(ft, len))
return SOX_EOF;
- }
- lsx_readw(ft, &wav->samplesPerBlock);
- len -= 2;
-
- bytesPerBlock = 65;
-
- if (wav->blockAlign != 65) {
- lsx_fail_errno(ft, SOX_EOF,
- "format[%s]: expects blockAlign(%d) = %d",
- wav_format_str(wav->formatTag), wav->blockAlign, 65);
- return SOX_EOF;
- }
-
- if (wav->samplesPerBlock != 320) {
- lsx_fail_errno(ft, SOX_EOF,
- "format[%s]: expects samplesPerBlock(%d) = %d",
- wav_format_str(wav->formatTag),
- wav->samplesPerBlock, 320);
- return SOX_EOF;
- }
-
bytespersample = 2; /* AFTER de-compression */
break;
default:
- bytespersample = (wBitsPerSample + 7) / 8;
+ bytespersample = (wav->bitsPerSample + 7) / 8;
break;
}
/* User options take precedence */
if (!ft->encoding.bits_per_sample ||
- ft->encoding.bits_per_sample == wBitsPerSample)
- ft->encoding.bits_per_sample = wBitsPerSample;
+ ft->encoding.bits_per_sample == wav->bitsPerSample)
+ ft->encoding.bits_per_sample = wav->bitsPerSample;
else
lsx_warn("User options overriding size read in .wav header");