shithub: sox

Download patch

ref: 361710b16b1b6e564351178000d871f66a334849
parent: f8ce704d16fe11b50067f4397674f703cfa4ae54
author: cbagwell <cbagwell>
date: Tue Nov 30 16:39:29 EST 1999

Additional adpcm updates.
Additional updates to configure.in for new alsa support.

--- a/configure.in
+++ b/configure.in
@@ -3,7 +3,7 @@
 dnl configure.in
 dnl
 
-AC_REVISION([configure.in 0.3])
+AC_REVISION([configure.in 0.4])
 AC_INIT(sox.c)
 dnl AC_CONFIG_HEADER(config.h)
 
@@ -29,7 +29,7 @@
 	[gsminc=auto])
 
 AC_ARG_WITH(alsa_dsp,
-	[  --with-alsa-dsp         Force support for /dev/snd/pcm00 (ALSA)],
+	[  --with-alsa-dsp         Force support for /dev/snd/pcmABXY (ALSA)],
 	[alsa_dsp="$withval"],
 	[alsa_dsp=auto])
 
@@ -133,17 +133,19 @@
 if test "$alsa_dsp" = auto
 then
 	AC_CACHE_CHECK(
-		[whether /dev/snd/pcm00 is functional (ALSA)],
+		[whether /proc/asound is functional (ALSA)],
 		ac_cv_dev_alsa_dsp,
 		AC_TRY_RUN(
 			[
+			void *opendir(const char *);
+			void *closedir(const char *);
 			int
 			main()
 				{
-				int fd = open("/dev/snd/pcm00", 0);
-				if (fd != -1)
+				void *vp = opendir("/proc/asound");
+				if (vp != 0)
 					{
-					close(fd);
+					closedir(vp);
 					return 0;
 					}
 				return 1;
@@ -156,11 +158,19 @@
 
 	if test "$ac_cv_dev_alsa_dsp" = yes
 	then
-		alsa_dsp=yes
+		AC_CHECK_HEADERS(linux/asound.h, alsa_dsp=yes)
+		if test "$alsa_dsp" = auto
+		then
+			AC_WARN([No asound.h to compile with ALSA /dev/snd/pcmABXY])
+		fi
 	fi
 fi
 if test "$alsa_dsp" = yes
 then
+	if test "$ac_cv_dev_alsa_dsp" = ""
+	then
+		AC_CHECK_HEADERS(linux/asound.h)
+	fi
 	CFLAGS="$CFLAGS -DALSA_PLAYER"
 	NEED_ALSA=1
 	PLAY_SUPPORT=1
@@ -173,6 +183,8 @@
 		ac_cv_dev_oss_dsp,
 		AC_TRY_RUN(
 			[
+			int open(const char *, int);
+			int close(int);
 			int
 			main()
 				{
@@ -202,7 +214,7 @@
 then
 	if test "$ac_cv_dev_oss_dsp" = ""
 	then
-		AC_CHECK_HEADERS(sys/soundcard.h machine/soundcard.h,)
+		AC_CHECK_HEADERS(sys/soundcard.h machine/soundcard.h)
 	fi
 	CFLAGS="$CFLAGS -DOSS_PLAYER"
 	NEED_OSS=1
@@ -216,6 +228,8 @@
 		ac_cv_dev_sun_audio,
 		AC_TRY_RUN(
 			[
+			int open(const char *, int);
+			int close(int);
 			int
 			main()
 				{
@@ -234,8 +248,7 @@
 		)
 	if test "$ac_cv_dev_sun_audio" = yes
 	then
-		AC_CHECK_HEADER(sys/audioio.h, sun_audio=yes)
-		AC_CHECK_HEADER(sun/audioio.h, sun_audio=yes)
+		AC_CHECK_HEADER(sys/audioio.h, sun/audioio.h, sun_audio=yes)
 		if test "$sun_audio" = auto
 		then
 			AC_WARN([No audioio.h to compile with SUN /dev/audio])
@@ -246,7 +259,7 @@
 then
 	if test "$ac_cv_dev_sun_audio" = ""
 	then
-		AC_CHECK_HEADERS(sys/audioio.h, sun/audioio.h,)
+		AC_CHECK_HEADERS(sys/audioio.h sun/audioio.h)
 	fi
 	CFLAGS="$CFLAGS -DSUNAUDIO_PLAYER"
 	NEED_SUNAU=1
--- a/src/adpcm.c
+++ b/src/adpcm.c
@@ -110,6 +110,8 @@
 /* AdpcmBlockExpandI() outputs interleaved samples into one output buffer */
 const char *AdpcmBlockExpandI(
 	int chans,          /* total channels             */
+	int nCoef,
+	const short *iCoef,
 	const u_char *ibuff,/* input buffer[blockAlign]   */
 	SAMPL *obuff,       /* output samples, n*chans    */
 	int n               /* samples to decode PER channel */
@@ -124,12 +126,13 @@
 	ip = ibuff;
 	for (ch = 0; ch < chans; ch++) {
 		u_char bpred = *ip++;
-		if (bpred >= 7) {
-			errmsg = "MSADPCM bpred >= 7, arbitrarily using 0\n";
+		if (bpred >= nCoef) {
+			errmsg = "MSADPCM bpred >= nCoef, arbitrarily using 0\n";
 			bpred = 0;
 		}
-		state[ch].iCoef[0] = iCoef[(int)bpred][0];
-		state[ch].iCoef[1] = iCoef[(int)bpred][1];
+		state[ch].iCoef[0] = iCoef[(int)bpred*2+0];
+		state[ch].iCoef[1] = iCoef[(int)bpred*2+1];
+		
 	}
 
 	for (ch = 0; ch < chans; ch++)
@@ -373,8 +376,8 @@
 	const SAMPL *ip,    /* ip[n*chans] is interleaved input samples */
 	int n,              /* samples to encode PER channel */
 	int *st,            /* input/output steps, 16<=st[i] */
-	u_char *obuff,      /* output buffer[blockAlign] */
-	int blockAlign,     /* >= 7*chans + n/2          */
+	u_char *obuff,      /* output buffer[blockAlign]     */
+	int blockAlign,     /* >= 7*chans + chans*(n-2)/2.0    */
 	int opt             /* non-zero allows some cpu-intensive code to improve output */
 )
 {
@@ -389,3 +392,50 @@
 	for (ch=0; ch<chans; ch++)
 		AdpcmMashChannel(ch, chans, ip, n, st+ch, obuff, opt);
 }
+
+/*
+ * AdpcmSamplesIn(dataLen, chans, blockAlign, samplesPerBlock)
+ *  returns the number of samples/channel which would be
+ *  in the dataLen, given the other parameters ...
+ *  if input samplesPerBlock is 0, then returns the max
+ *  samplesPerBlock which would go into a block of size blockAlign
+ *  Yes, it is confusing usage.
+ */
+ULONG AdpcmSamplesIn(
+	ULONG dataLen,
+	unsigned short chans,
+	unsigned short blockAlign,
+	unsigned short samplesPerBlock
+)
+{
+	ULONG m, n;
+
+	if (samplesPerBlock) {
+		n = (dataLen / blockAlign) * samplesPerBlock;
+		m = (dataLen % blockAlign);
+	} else {
+		n = 0;
+		m = blockAlign;
+	}
+	if (m >= 7*chans) {
+		m -= 7*chans;          /* bytes beyond block-header */
+		m = (2*m)/chans + 2;   /* nibbles/chans + 2 in header */
+		if (samplesPerBlock && m > samplesPerBlock) m = samplesPerBlock;
+		n += m;
+	}
+	return n;
+	/* wSamplesPerBlock = 2*(wBlockAlign - 7*wChannels)/wChannels + 2; */
+}
+
+ULONG AdpcmBytesPerBlock(
+	unsigned short chans,
+	unsigned short samplesPerBlock
+)
+{
+	ULONG n;
+	n = 7*chans;  /* header */ 
+	if (samplesPerBlock > 2)
+		n += (((ULONG)samplesPerBlock-2)*chans + 1)/2;
+	return n;
+}
+
--- a/src/adpcm.h
+++ b/src/adpcm.h
@@ -7,6 +7,7 @@
 #ifndef LONG
 #define LONG long
 #endif
+/* FIXME: This breaks on Alphas! */
 #ifndef ULONG
 #define ULONG u_long
 #endif
@@ -17,6 +18,8 @@
 /* AdpcmBlockExpandI() outputs interleaved samples into one output buffer */
 extern const char *AdpcmBlockExpandI(
 	int chans,          /* total channels             */
+	int nCoef,
+	const short *iCoef,
 	const u_char *ibuff,/* input buffer[blockAlign]   */
 	SAMPL *obuff,       /* output samples, n*chans    */
 	int n               /* samples to decode PER channel, REQUIRE n % 8 == 1  */
@@ -32,3 +35,29 @@
 	int opt             /* non-zero allows some cpu-intensive code to improve output */
 );
 
+/* Some helper functions for computing samples/block and blockalign */
+
+/*
+ * AdpcmSamplesIn(dataLen, chans, blockAlign, samplesPerBlock)
+ *  returns the number of samples/channel which would be
+ *  in the dataLen, given the other parameters ...
+ *  if input samplesPerBlock is 0, then returns the max
+ *  samplesPerBlock which would go into a block of size blockAlign
+ *  Yes, it is confusing usage.
+ */
+extern ULONG AdpcmSamplesIn(
+	ULONG dataLen,
+	unsigned short chans,
+	unsigned short blockAlign,
+	unsigned short samplesPerBlock
+);
+
+/*
+ * ULONG AdpcmBytesPerBlock(chans, samplesPerBlock)
+ *   return minimum blocksize which would be required
+ *   to encode number of chans with given samplesPerBlock
+ */
+extern ULONG AdpcmBytesPerBlock(
+	unsigned short chans,
+	unsigned short samplesPerBlock
+);
--- a/src/ima_rw.c
+++ b/src/ima_rw.c
@@ -333,6 +333,61 @@
 		ImaMashChannel(ch, chans, ip, n, st+ch, obuff, opt);
 }
 
+/*
+ * ImaSamplesIn(dataLen, chans, blockAlign, samplesPerBlock)
+ *  returns the number of samples/channel which would go
+ *  in the dataLen, given the other parameters ...
+ *  if input samplesPerBlock is 0, then returns the max
+ *  samplesPerBlock which would go into a block of size blockAlign
+ *  Yes, it is confusing.
+ */
+ULONG ImaSamplesIn(
+  ULONG dataLen,
+  unsigned short chans,
+  unsigned short blockAlign,
+  unsigned short samplesPerBlock
+)
+{
+  ULONG m, n;
+
+  if (samplesPerBlock) {
+    n = (dataLen / blockAlign) * samplesPerBlock;
+    m = (dataLen % blockAlign);
+  } else {
+    n = 0;
+    m = blockAlign;
+  }
+  if (m >= 4*chans) {
+    m -= 4*chans;    /* number of bytes beyond block-header */
+    m /= 4*chans;    /* number of 4-byte blocks/channel beyond header */
+    m = 8*m + 1;     /* samples/chan beyond header + 1 in header */
+    if (samplesPerBlock && m > samplesPerBlock) m = samplesPerBlock;
+    n += m;
+  }
+  return n;
+  /*wSamplesPerBlock = ((wBlockAlign - 4*wChannels)/(4*wChannels))*8 + 1;*/
+}
+
+/*
+ * ULONG ImaBytesPerBlock(chans, samplesPerBlock)
+ *   return minimum blocksize which would be required
+ *   to encode number of chans with given samplesPerBlock
+ */
+ULONG ImaBytesPerBlock(
+  unsigned short chans,
+  unsigned short samplesPerBlock
+)
+{
+  ULONG n;
+  /* per channel, ima has blocks of len 4, the 1st has 1st sample, the others
+   * up to 8 samples per block,
+   * so number of later blocks is (nsamp-1 + 7)/8, total blocks/chan is
+   * (nsamp-1+7)/8 + 1 = (nsamp+14)/8
+   */
+  n = ((ULONG)samplesPerBlock + 14)/8 * 4 * chans;
+  return n;
+}
+
 #if 0
 static void ImaMashChannel(int ch, const SAMPL *ip, int n, int *st)
 {
--- a/src/ima_rw.h
+++ b/src/ima_rw.h
@@ -21,6 +21,10 @@
 #ifndef SAMPL
 #	define SAMPL short
 #endif
+/* FIXME: This breaks on Alphas! */
+#ifndef ULONG
+#	define ULONG unsigned long
+#endif
 
 /* #undef STRICT_IMA makes code a bit faster, but not
  * strictly compatible with the real IMA spec, which
@@ -62,5 +66,32 @@
 	int *st,            /* input/output state[chans], REQUIRE 0 <= st[ch] <= ISSTMAX */
 	u_char *obuff,      /* output buffer[blockAlign] */
 	int opt             /* non-zero allows some cpu-intensive code to improve output */
+);
+
+/* Some helper functions for computing samples/block and blockalign */
+
+/*
+ * ImaSamplesIn(dataLen, chans, blockAlign, samplesPerBlock)
+ *  returns the number of samples/channel which would go
+ *  in the dataLen, given the other parameters ...
+ *  if input samplesPerBlock is 0, then returns the max
+ *  samplesPerBlock which would go into a block of size blockAlign
+ *  Yes, it is confusing usage.
+ */
+extern ULONG ImaSamplesIn(
+	ULONG dataLen,
+	unsigned short chans,
+	unsigned short blockAlign,
+	unsigned short samplesPerBlock
+);
+
+/*
+ * ULONG ImaBytesPerBlock(chans, samplesPerBlock)
+ *   return minimum blocksize which would be required
+ *   to encode number of chans with given samplesPerBlock
+ */
+extern ULONG ImaBytesPerBlock(
+	unsigned short chans,
+	unsigned short samplesPerBlock
 );
 
--- a/src/wav.c
+++ b/src/wav.c
@@ -86,20 +86,18 @@
     LONG	   numSamples;
     LONG	   dataLength;     /* needed for ADPCM writing */
     unsigned short formatTag;	   /* What type of encoding file is using */
-    
-    /* The following are only needed for ADPCM wav files */
     unsigned short samplesPerBlock;
-    unsigned short bytesPerBlock;
     unsigned short blockAlign;
+    
+    /* following used by *ADPCM wav files */
     unsigned short nCoefs;	    /* ADPCM: number of coef sets */
     short	  *iCoefs;	    /* ADPCM: coef sets           */
     unsigned char *packet;	    /* Temporary buffer for packets */
     short	  *samples;	    /* interleaved samples buffer */
-    short	  *samplePtr;       /* Pointer to current samples */
+    short	  *samplePtr;       /* Pointer to current sample  */
     short	  *sampleTop;       /* End of samples-buffer      */
-    unsigned short blockSamplesRemaining;/* Samples remaining in each channel */    
-    /* state holds step-size info for ADPCM or IMA_ADPCM writes */
-    int 	   state[16];       /* last, because maybe longer */
+    unsigned short blockSamplesRemaining;/* Samples remaining per channel */    
+    int 	   state[16];       /* step-size info for *ADPCM writes */
 
     /* following used by GSM 6.10 wav */
 #ifdef HAVE_LIBGSM
@@ -122,9 +120,16 @@
 void rawwrite(P3(ft_t, LONG *, LONG));
 void wavwritehdr(P2(ft_t, int));
 
+
 /****************************************************************************/
 /* IMA ADPCM Support Functions Section                                      */
 /****************************************************************************/
+
+/*
+ *
+ * ImaAdpcmReadBlock - Grab and decode complete block of samples
+ *
+ */
 unsigned short  ImaAdpcmReadBlock(ft)
 ft_t ft;    
 {
@@ -134,27 +139,22 @@
 
     /* Pull in the packet and check the header */
     bytesRead = fread(wav->packet,1,wav->blockAlign,ft->fp);
+    samplesThisBlock = wav->samplesPerBlock;
     if (bytesRead < wav->blockAlign) 
     { 
 	/* If it looks like a valid header is around then try and */
 	/* work with partial blocks.  Specs say it should be null */
 	/* padded but I guess this is better than trailing quiet. */
-	if (bytesRead >= (4 * ft->info.channels))
-	{   /* SJB: FIXME this is incorrect */
-	    samplesThisBlock = (wav->blockAlign - (3 * ft->info.channels));
-	}
-	else
+	samplesThisBlock = ImaSamplesIn(0, ft->info.channels, bytesRead, 0);
+	if (samplesThisBlock == 0) 
 	{
 	    warn ("Premature EOF on .wav input file");
 	    return 0;
 	}
     }
-    else
-	samplesThisBlock = wav->samplesPerBlock;
     
     wav->samplePtr = wav->samples;
     
-
     /* For a full block, the following should be true: */
     /* wav->samplesPerBlock = blockAlign - 8byte header + 1 sample in header */
     ImaBlockExpandI(ft->info.channels, wav->packet, wav->samples, samplesThisBlock);
@@ -165,6 +165,7 @@
 /****************************************************************************/
 /* MS ADPCM Support Functions Section                                       */
 /****************************************************************************/
+
 /*
  *
  * AdpcmReadBlock - Grab and decode complete block of samples
@@ -180,25 +181,21 @@
 
     /* Pull in the packet and check the header */
     bytesRead = fread(wav->packet,1,wav->blockAlign,ft->fp);
+    samplesThisBlock = wav->samplesPerBlock;
     if (bytesRead < wav->blockAlign) 
     {
 	/* If it looks like a valid header is around then try and */
 	/* work with partial blocks.  Specs say it should be null */
-	/* padded but I guess this is better than trailing quite. */
-	if (bytesRead >= (7 * ft->info.channels))
-	{   /* SJB: FIXME this is incorrect */
-	    samplesThisBlock = (wav->blockAlign - (6 * ft->info.channels));
-	}
-	else
+	/* padded but I guess this is better than trailing quiet. */
+	samplesThisBlock = AdpcmSamplesIn(0, ft->info.channels, bytesRead, 0);
+	if (samplesThisBlock == 0) 
 	{
 	    warn ("Premature EOF on .wav input file");
 	    return 0;
 	}
     }
-    else
-	samplesThisBlock = wav->samplesPerBlock;
     
-    errmsg = AdpcmBlockExpandI(ft->info.channels, wav->packet, wav->samples, samplesThisBlock);
+    errmsg = AdpcmBlockExpandI(ft->info.channels, wav->nCoefs, wav->iCoefs, wav->packet, wav->samples, samplesThisBlock);
 
     if (errmsg)
 	warn((char*)errmsg);
@@ -207,8 +204,9 @@
 }
 
 /****************************************************************************/
-/* Common ADPCM Support Function                                            */
+/* Common ADPCM Write Function                                              */
 /****************************************************************************/
+
 static void xxxAdpcmWriteBlock(ft)
 ft_t ft;
 {
@@ -441,17 +439,22 @@
     unsigned short wExtSize = 0;    /* extended field for non-PCM */
 
     ULONG    wDataLength;	    /* length of sound data in bytes */
+    ULONG    bytesPerBlock = 0;
     ULONG    bytespersample;	    /* bytes per sample (per channel */
 
-    /* This is needed for rawread() */
+    if (sizeof(struct wavstuff)> PRIVSIZE)
+      fail("struct wav_t too big (%d); increase PRIVSIZE in st.h and recompile sox",sizeof(struct wavstuff));
+    /* This is needed for rawread(), rshort, etc */
     rawstartread(ft);
 
     endptr = (char *) &littlendian;
     if (!*endptr) ft->swap = ft->swap ? 0 : 1;
 
+#if 0
     /* If you need to seek around the input file. */
-    if (0 && ! ft->seekable)
+    if (! ft->seekable)
 	fail("WAVE input file must be a file, not a pipe");
+#endif
 
     if ( fread(magic, 1, 4, ft->fp) != 4 || strncmp("RIFF", magic, 4))
 	fail("WAVE: RIFF header not found");
@@ -561,7 +564,7 @@
 	ft->info.channels = wChannels;
     else
 	warn("User options overriding channels read in .wav header");
-	
+
     if (ft->info.rate == 0 || ft->info.rate == wSamplesPerSecond)
 	ft->info.rate = wSamplesPerSecond;
     else
@@ -587,17 +590,21 @@
 
     switch (wav->formatTag)
     {
+    /* ULONG max_spb; */
     case WAVE_FORMAT_ADPCM:
 	if (wExtSize < 4)
-	    fail("wave header error: format[%s] expects wExtSize >= %d",
-			    wav_format_str(wav->formatTag), 4);
+	    fail("format[%s]: expects wExtSize >= %d",
+			wav_format_str(wav->formatTag), 4);
 
 	if (wBitsPerSample != 4)
 	    fail("Can only handle 4-bit MS ADPCM in wav files");
 
 	wav->samplesPerBlock = rshort(ft);
-	wav->bytesPerBlock = ((wav->samplesPerBlock-2)*ft->info.channels + 1)/2
-		             + 7*ft->info.channels;
+	bytesPerBlock = AdpcmBytesPerBlock(ft->info.channels, wav->samplesPerBlock);
+	if (bytesPerBlock > wav->blockAlign)
+	    fail("format[%s]: samplesPerBlock(%d) incompatible with blockAlign(%d)",
+		wav_format_str(wav->formatTag), wav->samplesPerBlock, wav->blockAlign);
+
 	wav->nCoefs = rshort(ft);
 	if (wav->nCoefs < 7 || wav->nCoefs > 0x100) {
 	    fail("ADPCM file nCoefs (%.4hx) makes no sense\n", wav->nCoefs);
@@ -610,15 +617,17 @@
 
 	wav->samples = (short *)malloc(wChannels*wav->samplesPerBlock*sizeof(short));
 
-	/* SJB: will need iCoefs later for adpcm.c */
+	/* nCoefs, iCoefs used by adpcm.c */
 	wav->iCoefs = (short *)malloc(wav->nCoefs * 2 * sizeof(short));
 	{
-	    int i;
+	    int i, errct=0;
 	    for (i=0; len>=2 && i < 2*wav->nCoefs; i++) {
 		wav->iCoefs[i] = rshort(ft);
-		/* fprintf(stderr,"iCoefs[%2d] %4d\n",i,wav->iCoefs[i]); */
 		len -= 2;
+		if (i<14) errct += (wav->iCoefs[i] != iCoef[i/2][i%2]);
+		/* fprintf(stderr,"iCoefs[%2d] %4d\n",i,wav->iCoefs[i]); */
 	    }
+	    if (errct) warn("base iCoefs differ in %d/14 positions",errct);
 	}
 
 	bytespersample = WORD;  /* AFTER de-compression */
@@ -626,7 +635,7 @@
 
     case WAVE_FORMAT_IMA_ADPCM:
 	if (wExtSize < 2)
-	    fail("wave header error: format[%s] expects wExtSize >= %d",
+	    fail("format[%s]: expects wExtSize >= %d",
 		    wav_format_str(wav->formatTag), 2);
 
 	if (wBitsPerSample != 4)
@@ -633,7 +642,11 @@
 	    fail("Can only handle 4-bit IMA ADPCM in wav files");
 
 	wav->samplesPerBlock = rshort(ft);
-	wav->bytesPerBlock = (wav->samplesPerBlock + 7)/2 * ft->info.channels;/* FIXME */
+	bytesPerBlock = ImaBytesPerBlock(ft->info.channels, wav->samplesPerBlock);
+	if (bytesPerBlock > wav->blockAlign || wav->samplesPerBlock%8 != 1)
+	    fail("format[%s]: samplesPerBlock(%d) incompatible with blockAlign(%d)",
+		wav_format_str(wav->formatTag), wav->samplesPerBlock, wav->blockAlign);
+
 	wav->packet = (unsigned char *)malloc(wav->blockAlign);
 	len -= 2;
 
@@ -646,14 +659,15 @@
     /* GSM formats have extended fmt chunk.  Check for those cases. */
     case WAVE_FORMAT_GSM610:
 	if (wExtSize < 2)
-	    fail("wave header error: format[%s] expects wExtSize >= %d",
+	    fail("format[%s]: expects wExtSize >= %d",
 		    wav_format_str(wav->formatTag), 2);
 	wav->samplesPerBlock = rshort(ft);
+	bytesPerBlock = 65;
 	if (wav->blockAlign != 65)
-	    fail("wave header error: format[%s] expects blockAlign(%d) = %d",
+	    fail("format[%s]: expects blockAlign(%d) = %d",
 		    wav_format_str(wav->formatTag), wav->blockAlign, 65);
 	if (wav->samplesPerBlock != 320)
-	    fail("wave header error: format[%s] expects samplesPerBlock(%d) = %d",
+	    fail("format[%s]: expects samplesPerBlock(%d) = %d",
 		    wav_format_str(wav->formatTag), wav->samplesPerBlock, 320);
 	bytespersample = WORD;  /* AFTER de-compression */
 	len -= 2;
@@ -720,13 +734,8 @@
     {
 
     case WAVE_FORMAT_ADPCM:
-	/* Compute easiest part of number of samples.  For every block, there
-	   are samplesPerBlock samples to read. */
-	wav->numSamples = (((wDataLength / wav->blockAlign) * wav->samplesPerBlock) * ft->info.channels);
-	/* Next, for any partial blocks, subtract overhead from it and it
-	   will leave # of samples to read. */
-	wav->numSamples += 
-		((wDataLength % wav->blockAlign) - (6 * ft->info.channels)) * ft->info.channels;
+	wav->numSamples = 
+	    AdpcmSamplesIn(wDataLength, ft->info.channels, wav->blockAlign, wav->samplesPerBlock);
 	/*report("datalen %d, numSamples %d",wDataLength, wav->numSamples);*/
 	wav->blockSamplesRemaining = 0;	       /* Samples left in buffer */
 	break;
@@ -734,11 +743,9 @@
     case WAVE_FORMAT_IMA_ADPCM:
 	/* Compute easiest part of number of samples.  For every block, there
 	   are samplesPerBlock samples to read. */
-	wav->numSamples = (((wDataLength / wav->blockAlign) * wav->samplesPerBlock) * ft->info.channels);
-	/* Next, for any partial blocks, substract overhead from it and it
-	   will leave # of samples to read. */
-	wav->numSamples +=
-		((wDataLength % wav->blockAlign) - (3 * ft->info.channels)) * ft->info.channels;
+	wav->numSamples = 
+	    ImaSamplesIn(wDataLength, ft->info.channels, wav->blockAlign, wav->samplesPerBlock);
+	/*report("datalen %d, numSamples %d",wDataLength, wav->numSamples);*/
 	wav->blockSamplesRemaining = 0;	       /* Samples left in buffer */
 	initImaTable();
 	break;
@@ -766,12 +773,12 @@
     {
     case WAVE_FORMAT_ADPCM:
 	report("        %d Extsize, %d Samps/block, %d bytes/block %d Num Coefs",
-		wExtSize,wav->samplesPerBlock,wav->bytesPerBlock,wav->nCoefs);
+		wExtSize,wav->samplesPerBlock,bytesPerBlock,wav->nCoefs);
 	break;
 
     case WAVE_FORMAT_IMA_ADPCM:
 	report("        %d Extsize, %d Samps/block, %d bytes/block",
-		wExtSize,wav->samplesPerBlock,wav->bytesPerBlock);
+		wExtSize,wav->samplesPerBlock,bytesPerBlock);
 	break;
 
 #ifdef HAVE_LIBGSM
@@ -904,6 +911,9 @@
 	int	littlendian = 1;
 	char	*endptr;
 
+  if (sizeof(struct wavstuff)> PRIVSIZE)
+    fail("struct wav_t too big (%d); increase PRIVSIZE in st.h and recompile sox",sizeof(struct wavstuff));
+
 	endptr = (char *) &littlendian;
 	if (!*endptr) ft->swap = ft->swap ? 0 : 1;
 
@@ -1103,7 +1113,7 @@
 			wBlockAlign = wChannels * 64; /* reasonable default */
 			wBitsPerSample = 4;
 	    		wExtSize = 2;
-			wSamplesPerBlock = ((wBlockAlign - 4*wChannels)/(4*wChannels))*8 + 1;
+			wSamplesPerBlock = ImaSamplesIn(0, wChannels, wBlockAlign, 0);
 			break;
 		case ADPCM:
 			/* warn("Experimental support writing ADPCM style.\n"); */
@@ -1113,7 +1123,7 @@
 			wBlockAlign = wChannels * 128; /* reasonable default */
 			wBitsPerSample = 4;
 	    		wExtSize = 4+4*7;      /* Ext fmt data length */
-			wSamplesPerBlock = 2*(wBlockAlign - 7*wChannels)/wChannels + 2;
+			wSamplesPerBlock = AdpcmSamplesIn(0, wChannels, wBlockAlign, 0);
 			break;
 		case GSM:
 #ifdef HAVE_LIBGSM
@@ -1169,9 +1179,8 @@
 	if (wFormatTag != WAVE_FORMAT_PCM) /* PCM omits the "fact" chunk */
 	    wRiffLength += (8+wFactSize);
 	
-	/* wAvgBytesPerSec <-- this is BEFORE compression, isn't it? */
-	/* if (wFormatTag != WAVE_FORMAT_GSM610)  GSM set this above */
-	wAvgBytesPerSec = ft->info.rate * wChannels * bytespersample;
+	/* wAvgBytesPerSec <-- this is BEFORE compression, isn't it? guess not. */
+	wAvgBytesPerSec = (double)wBlockAlign*ft->info.rate / (double)wSamplesPerBlock + 0.5;
 
 	/* figured out header info, so write it */
 	fputs("RIFF", ft->fp);