changeset 74:cb25ba9294f8 octave-forge

Use closed interval [-1,1] rather than open interval [-1,1) internally
author pkienzle
date Tue, 11 Dec 2001 20:26:05 +0000
parents 0add478f2afa
children 4d103d333f56
files FIXES/lin2mu.m FIXES/mu2lin.m main/audio/auload.m main/audio/ausave.m
diffstat 4 files changed, 58 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/FIXES/lin2mu.m	Tue Dec 11 15:13:42 2001 +0000
+++ b/FIXES/lin2mu.m	Tue Dec 11 20:26:05 2001 +0000
@@ -31,10 +31,12 @@
 ## Created: 17 October 1994
 ## Adapted-By: jwe
 
-## Paul Kienzle <pkienzle@kienzle.powernet.co.uk>
+## Paul Kienzle <pkienzle@users.sf.net>
 ##    handle [-1,1] input range
-## 2001-10-22 Paul Kienzle
+## 2001-10-22 Paul Kienzle <pkienzle@users.sf.net>
 ## * restore Octave's guessing behaviour for precision, but issue warning
+## 2001-12-11 Paul Kienzle <pkienzle@users.sf.net>
+## * convert 
 
 function y = lin2mu (x, bit)
 
@@ -59,7 +61,8 @@
 
   ## transform real and 8-bit format to 16-bit
   if (bit == 0)
-    x = 32768 .* x;
+    [-1,1] -> [-32768, 32767]
+    x = round(32767.5 * x - 0.5);
   elseif (bit == 8)
     x = 256 .* x;
   endif
--- a/FIXES/mu2lin.m	Tue Dec 11 15:13:42 2001 +0000
+++ b/FIXES/mu2lin.m	Tue Dec 11 20:26:05 2001 +0000
@@ -31,10 +31,12 @@
 ## Created: 18 October 1994
 ## Adapted-By: jwe
 
-## Paul Kienzle <pkienzle@kienzle.powernet.co.uk>
+## Paul Kienzle <pkienzle@users.sf.net>
 ##    handle [-1,1] input range
 ## 2001-10-23 Paul Kienzle <pkienzle@users.sf.net>
 ## * default to 8-bit as in octave
+## 2001-12-11 Paul Kienzle <pkienzle@users.sf.net>
+## * use asymmetric transformation [-32768,32767]->[-1,1] for real
 
 function y = mu2lin (x, bit)
 
@@ -74,7 +76,8 @@
 
   ## convert to real or 8-bit
   if (bit == 0)
-    y = y/32768;
+    ## [ -32768, 32767 ] -> [ -1, 1 ]
+    y = (y+0.5)/32767.5;
   elseif (bit == 8)
     ld = max (max (abs (y)));
     if (ld < 16384) #% && ld > 0)
--- a/main/audio/auload.m	Tue Dec 11 15:13:42 2001 +0000
+++ b/main/audio/auload.m	Tue Dec 11 20:26:05 2001 +0000
@@ -20,18 +20,27 @@
 ## data, one column per channel, one row per time slice.  Also returns
 ## the sample rate and stored format (one of ulaw, alaw, char, short,
 ## long, float, double). The sample value will be normalized to the
-## range [-1,1) regardless of the stored format.  This does not do any
-## level correction or DC offset correction on the samples.
+## range [-1,1] regardless of the stored format.
 ##
 ## Example
 ##    [x, fs] = auload(file_in_loadpath("sample.wav"));
 ##    auplot(x,fs);
+##
+## Note that translating the asymmetric range [-2^n,2^n-1] into the 
+## symmetric range [-1,1] requires a DC offset of 2/2^n. The inverse 
+## process used by ausave requires a DC offset of -2/2^n, so loading and 
+## saving a file will not change the contents.  Other applications may 
+## compensate for the asymmetry in a different way (including previous 
+## versions of auload/ausave) so you may find small differences in 
+## calculated DC offsets for the same file.
 
 ## 2001-09-04 Paul Kienzle <pkienzle@users.sf.net>
 ## * skip unknown blocks in WAVE format.
 ## 2001-09-05 Paul Kienzle <pkienzle@users.sf.net>
 ## * remove debugging stuff from AIFF format.
 ## * use data length if it is given rather than reading to the end of file.
+## 2001-12-11 Paul Kienzle <pkienzle@users.sf.net>
+## * use closed interval [-1,1] rather than open interval [-1,1) internally
 
 function [data, rate, sampleformat] = auload(path)
 
@@ -324,16 +333,19 @@
 	     -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696, \
 	      -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592, \
 	      -944,   -912,  -1008,   -976,   -816,   -784,   -880,   -848 ];
-    alaw = [ alaw, -alaw]/32768;
+    alaw = ([ alaw,-alaw]+0.5)/32767.5;
     data = alaw(data+1);
   elseif strcmp(sampleformat, 'ulaw')
-    data = mu2lin(data, 16)/32768;
+    data = mu2lin(data, 0);
   elseif strcmp(sampleformat, 'uchar')
-    data = data/128 - 1;
+    ## [ 0, 255 ] -> [ -1, 1 ]
+    data = data/127.5 - 1;
   elseif strcmp(sampleformat, 'short')
-    data = data/32768;
+    ## [ -32768, 32767 ] -> [ -1, 1 ]
+    data = (data+0.5)/32767.5;
   elseif strcmp(sampleformat, 'long')
-    data = data/2^31;
+    ## [ -2^31, 2^31-1 ] -> [ -1, 1 ]
+    data = (data+0.5)/(2^31-0.5);
   end
   data = reshape(data, channels, length(data)/channels)';
 
--- a/main/audio/ausave.m	Tue Dec 11 15:13:42 2001 +0000
+++ b/main/audio/ausave.m	Tue Dec 11 20:26:05 2001 +0000
@@ -18,12 +18,26 @@
 ##
 ## Writes an audio file with the appropriate header. The extension on
 ## the filename determines the layout of the header. Currently supports
-## .wav and .au layouts.  Data is a matrix of audio samples, one row
-## time step, one column per channel. Fs defaults to 8000 Hz.  Format
-## is one of ulaw, alaw, char, short, long, float, double
+## .wav and .au layouts.  Data is a matrix of audio samples in the
+## range [-1,1] (inclusive), one row per time step, one column per 
+## channel. Fs defaults to 8000 Hz.  Format is one of ulaw, alaw, char, 
+## short, long, float, double
+##
+## Note that translating the symmetric range [-1,1] into the asymmetric
+## range [-2^n,2^n-1] requires a DC offset of -2/2^n.  The inverse 
+## process used by auload requires a DC offset of 2/2^n, so loading and 
+## saving a file will not change the contents.  Other applications may 
+## compensate for the asymmetry in a different way (including previous 
+## versions of auload/ausave) so you may find small differences in 
+## calculated DC offsets for the same file.
+
 
 ## 2001-10-23 Paul Kienzle
 ## * force lin2mu to use [-1:1] regardless of its default
+## 2001-12-11 Paul Kienzle <pkienzle@users.sf.net>
+## * use closed interval [-1,1] rather than open interval [-1,1) internally
+## * rescale data if it exceeds the range
+
 function ausave(path, data, rate, sampleformat)
 
   if nargin < 2 || nargin>4
@@ -206,7 +220,14 @@
     error('ausave(filename.ext,...) understands .wav .au and .aiff only');
   end
 
-  ## convert samples from range [-1, 1)
+  ## Make sure the data fits into the sample range
+  scale = max(abs(data(:)));
+  if (scale > 1.0)
+    warning("ausave: audio data exceeds range [-1,1] --- rescaling");
+    data = data / scale;
+  endif
+
+  ## convert samples from range [-1, 1]
   if strcmp(sampleformat, 'alaw')
     error("FIXME: ausave needs linear to alaw conversion\n");
     precision = 'uchar';
@@ -214,13 +235,13 @@
     data = lin2mu(data, 0);
     precision = 'uchar'
   elseif strcmp(sampleformat, 'uchar')
-    data = data*128 + 128;
+    data = round((data+1)*127.5);
     precision = 'uchar';
   elseif strcmp(sampleformat, 'short')
-    data = data*32768;
+    data = round(data*32767.5 - 0.5);
     precision = 'short';
   elseif strcmp(sampleformat, 'long')
-    data = data*2^31;
+    data = round(data*(2^31-0.5) - 0.5);
     precision = 'long';
   else
     precision = sampleformat;