ref: 47d73971bb09ec0a6073626c181d8fb095038179
parent: 0a33c800bb999148b32439fdfdc6bbbeaf5f898d
author: cbagwell <cbagwell>
date: Tue Sep 28 22:31:37 EDT 2004
Add float support to .au and make float routines work with normalized data
--- a/Changelog
+++ b/Changelog
@@ -54,6 +54,10 @@
o Donnie Smith updated the silence effect so that its possible
to remove silence from the middle of a sound file by
using a negative value for stop_periods.
+ o Changed float routines to only work with normalized values
+ from -1:1.
+ o Modifed .au handler to be able to read and write 32-bit
+ and 64-bit float data. Only tested reading so far.
sox-12.17.5
-----------
--- a/src/au.c
+++ b/src/au.c
@@ -94,6 +94,10 @@
*encoding = ST_ENCODING_SIGN2;
*size = ST_SIZE_WORD;
break;
+ case SUN_FLOAT:
+ *encoding = ST_ENCODING_FLOAT;
+ *size = ST_SIZE_32BIT;
+ break;
default:
st_report("encoding: 0x%lx", encoding);
return(ST_EOF);
@@ -208,7 +212,7 @@
if(st_auencodingandsize(encoding, &(ft->info.encoding),
&(ft->info.size)) == ST_EOF)
{
- st_fail_errno(ft,ST_EFMT,"Unsupported encoding in Sun/NeXT header.\nOnly U-law, signed bytes, signed words, and ADPCM are supported.");
+ st_fail_errno(ft,ST_EFMT,"Unsupported encoding in Sun/NeXT header.\nOnly U-law, signed bytes, signed words, ADPCM, and 32-bit floats are supported.");
return(ST_EOF);
}
switch (encoding) {
@@ -392,6 +396,8 @@
sun_encoding = SUN_LIN_8;
else if (encoding == ST_ENCODING_SIGN2 && size == ST_SIZE_WORD)
sun_encoding = SUN_LIN_16;
+ else if (encoding == ST_ENCODING_FLOAT && size == ST_SIZE_32BIT)
+ sun_encoding = SUN_FLOAT;
else
sun_encoding = -1;
return sun_encoding;
--- a/src/misc.c
+++ b/src/misc.c
@@ -240,12 +240,16 @@
/* Read float. */
int st_readf(ft_t ft, float *f)
{
- if (st_read(ft, f, sizeof(float), 1) != 1)
+ uint32_t datum, *dp;
+
+ dp = &datum;
+ if (st_read(ft, dp, sizeof(float), 1) != 1)
{
return(ST_EOF);
}
if (ft->swap)
- *f = st_swapf(*f);
+ datum = st_swapdw(datum);
+ *f = *((float *)dp);
return ST_SUCCESS;
}
@@ -267,12 +271,20 @@
/* Read double. */
int st_readdf(ft_t ft, double *d)
{
- if (st_read(ft, d, sizeof(double), 1) != 1)
+ uint32_t datum[2], *dp;
+
+ dp = &datum[0];
+ if (st_read(ft, dp, sizeof(double), 1) != 1)
{
return(ST_EOF);
}
if (ft->swap)
- *d = st_swapd(*d);
+ {
+ datum[0] = st_swapd(datum[0]);
+ datum[1] = st_swapd(datum[1]);
+ }
+ *d = *((float *)dp);
+
return ST_SUCCESS;
}
--- a/src/raw.c
+++ b/src/raw.c
@@ -301,12 +301,17 @@
while (len)
{
float datum;
+ uint32_t int_datum, *ip;
- datum = *((float *)buf2);
+ /* If swapping is needed, do this before converting to a float. */
+ int_datum = *((uint32_t *)buf2);
buf2++; buf2++; buf2++; buf2++;
if (swap)
- datum = st_swapf(datum);
+ int_datum = st_swapdw(int_datum);
+ ip = &int_datum;
+ datum = *((float *)ip);
+
*buf1++ = ST_FLOAT_DWORD_TO_SAMPLE(datum);
len--;
}
@@ -317,12 +322,23 @@
while (len)
{
double datum;
+ uint32_t int_datum[2], *ip;
- datum = *((double *)buf2);
+ /* If swapping needs to occur, do this before moving into
+ * float data.
+ */
+ int_datum[0] = *((uint32_t *)buf2);
buf2++; buf2++; buf2++; buf2++;
+ if (swap)
+ int_datum[0] = st_swapdw(int_datum[0]);
+
+ int_datum[1] = *((uint32_t *)buf2);
buf2++; buf2++; buf2++; buf2++;
if (swap)
- datum = st_swapd(datum);
+ int_datum[1] = st_swapdw(int_datum[1]);
+
+ ip = &int_datum[0];
+ datum = *((double *)ip);
*buf1++ = ST_FLOAT_DDWORD_TO_SAMPLE(datum);
len--;
--- a/src/st.h
+++ b/src/st.h
@@ -32,6 +32,15 @@
#define ST_SAMPLE_MAX 0x7fffffffL
#define ST_SAMPLE_MIN (-ST_SAMPLE_MAX - 1L)
+/* The following is the stepsize to be used when converting
+ * normalized float data (-1 to 1) to a 32-bit signed sample.
+ * FIXME: This is is an approximation because signed integers
+ * have one more value on the negative and so sample/SCALE
+ * doesn't map exactly to -1:1.
+ */
+#define ST_SAMPLE_FLOAT_DWORD_SCALE 2147483647.0
+#define ST_SAMPLE_FLOAT_DDWORD_SCALE 9223372036854775807.0
+
#define ST_UNSIGNED_BYTE_TO_SAMPLE(d) ((st_sample_t)((d) ^ 0x80) << 24)
#define ST_SIGNED_BYTE_TO_SAMPLE(d) ((st_sample_t)(d) << 24)
#define ST_UNSIGNED_WORD_TO_SAMPLE(d) ((st_sample_t)((d) ^ 0x8000) << 16)
@@ -38,9 +47,10 @@
#define ST_SIGNED_WORD_TO_SAMPLE(d) ((st_sample_t)(d) << 16)
#define ST_UNSIGNED_DWORD_TO_SAMPLE(d) ((st_sample_t)((d) ^ 0x80000000L))
#define ST_SIGNED_DWORD_TO_SAMPLE(d) ((st_sample_t)d)
-#define ST_FLOAT_DWORD_TO_SAMPLE(d) ((st_sample_t)d)
-#define ST_FLOAT_DDWORD_TO_SAMPLE(d) ((st_sample_t)d)
-
+/* FIXME: This is an approximation because it
+ * doesn't account for -1.0 mapping to -FLOAT_SCALE-1. */
+#define ST_FLOAT_DWORD_TO_SAMPLE(d) ((st_sample_t)(d*ST_SAMPLE_FLOAT_DWORD_SCALE))
+#define ST_FLOAT_DDWORD_TO_SAMPLE(d) ((st_sample_t)(d*ST_SAMPLE_FLOAT_DDWORD_SCALE))
#define ST_SAMPLE_TO_UNSIGNED_BYTE(d) ((uint8_t)((d) >> 24) ^ 0x80)
#define ST_SAMPLE_TO_SIGNED_BYTE(d) ((int8_t)((d) >> 24))
#define ST_SAMPLE_TO_UNSIGNED_WORD(d) ((uint16_t)((d) >> 16) ^ 0x8000)
@@ -47,9 +57,12 @@
#define ST_SAMPLE_TO_SIGNED_WORD(d) ((int16_t)((d) >> 16))
#define ST_SAMPLE_TO_UNSIGNED_DWORD(d) ((uint32_t)(d) ^ 0x80000000L)
#define ST_SAMPLE_TO_SIGNED_DWORD(d) ((int32_t)(d))
-#define ST_SAMPLE_TO_FLOAT_DWORD(d) ((float)(d))
-#define ST_SAMPLE_TO_FLOAT_DDWORD(d) ((double)(d))
-
+/* FIXME: This is an approximation because its impossible to
+ * to reach 1. Something like floor(d/(SCALE+0.5)) would probably
+ * get it right.
+ */
+#define ST_SAMPLE_TO_FLOAT_DWORD(d) ((float)(d/(ST_SAMPLE_FLOAT_DWORD_SCALE+1)))
+#define ST_SAMPLE_TO_FLOAT_DDWORD(d) ((double)((double)d/(ST_SAMPLE_FLOAT_DDWORD_SCALE+1)))
/* Maximum value size type can hold. (Minimum is 0). */
#define ST_SIZE_MAX 0xffffffffL