changeset 12701:de3e90a420e3 stable

Overhaul wavwrite, wavread and fix normalization problem (Bug #33420). * wavwrite.m: Remove ancient non-Matlab calling form of function. Update tests and add test to verify proper clipping of out-of-range values. * wavread.m: Use correct normalization constant to put values in range [-1,1). Add test to stop fntests.m from reporting this as untested function.
author Rik <octave@nomad.inbox5.com>
date Sat, 04 Jun 2011 07:20:42 -0700
parents 9843b3b055e0
children 013cd94d8d7f
files scripts/audio/wavread.m scripts/audio/wavwrite.m
diffstat 2 files changed, 52 insertions(+), 56 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/audio/wavread.m	Sat Jun 04 07:15:42 2011 -0700
+++ b/scripts/audio/wavread.m	Sat Jun 04 07:20:42 2011 -0700
@@ -22,9 +22,9 @@
 ## in vector @var{y}.  If the file contains multichannel data, then
 ## @var{y} is a matrix with the channels represented as columns.
 ##
-## @deftypefnx {Function File} {[@var{y}, @var{Fs}, @var{bits}] =} wavread (@var{filename})
+## @deftypefnx {Function File} {[@var{y}, @var{Fs}, @var{bps}] =} wavread (@var{filename})
 ## Additionally return the sample rate (@var{fs}) in Hz and the number of bits
-## per sample (@var{bits}).
+## per sample (@var{bps}).
 ##
 ## @deftypefnx {Function File} {[@dots{}] =} wavread (@var{filename}, @var{n})
 ## Read only the first @var{n} samples from each channel.
@@ -75,7 +75,7 @@
   endif
 
   riff_type = char (fread (fid, 4))';
-  if(! strcmp (riff_type, "WAVE"))
+  if (! strcmp (riff_type, "WAVE"))
     fclose (fid);
     error ("wavread: file contains no WAVE signature");
   endif
@@ -157,7 +157,7 @@
   if (nargin == 1)
     length = 8 * data_size / bits_per_sample;
   else
-    nparams = size (param, 2);
+    nparams = numel (param);
     if (nparams == 1)
       ## Number of samples is given.
       length = param * channels;
@@ -174,7 +174,7 @@
       return;
     else
       fclose (fid);
-      error ("wavread: invalid argument 2");
+      error ("wavread: invalid PARAM argument");
     endif
   endif
 
@@ -201,13 +201,13 @@
     ## Normalize samples.
     switch (bits_per_sample)
       case 8
-        yi = (yi - 128)/127;
+        yi = (yi - 128)/128;
       case 16
-        yi /= 32767;
+        yi /= 32768;
       case 24
-        yi /= 8388607;
+        yi /= 8388608;
       case 32
-        yi /= 2147483647;
+        yi /= 2147483648;
     endswitch
   endif
 
@@ -239,3 +239,8 @@
     chunk_size = -1;
   endif
 endfunction
+
+
+%% Tests for wavread/wavwrite pair are in wavrite.m
+%!assert(1)  # stop fntests.m from reporting no tests for wavread
+
--- a/scripts/audio/wavwrite.m	Sat Jun 04 07:15:42 2011 -0700
+++ b/scripts/audio/wavwrite.m	Sat Jun 04 07:20:42 2011 -0700
@@ -18,10 +18,10 @@
 
 ## -*- texinfo -*-
 ## @deftypefn  {Function File} {} wavwrite (@var{y}, @var{filename})
-## @deftypefnx {Function File} {} wavwrite (@var{y}, @var{fs}, @var{filename})
-## @deftypefnx {Function File} {} wavwrite (@var{y}, @var{fs}, @var{bits}, @var{filename})
+## @deftypefnx {Function File} {} wavwrite (@var{y}, @var{Fs}, @var{filename})
+## @deftypefnx {Function File} {} wavwrite (@var{y}, @var{Fs}, @var{bps}, @var{filename})
 ## Write @var{y} to the canonical RIFF/WAVE sound file @var{filename}
-## with sample rate @var{fs} and bits per sample @var{bits}.  The
+## with sample rate @var{Fs} and bits per sample @var{bps}.  The
 ## default sample rate is 8000 Hz with 16-bits per sample.  Each column
 ## of the data represents a separate channel.
 ## @seealso{wavread}
@@ -34,13 +34,6 @@
 
   BYTEORDER = "ieee-le";
 
-  ## For backward compatibility with previous versions of Octave, also
-  ## accept the inputs
-  ##
-  ##   wavwrite (filename, y)
-  ##   wavwrite (filename, y, fs)
-  ##   wavwrite (filename, y, fs, bits)
-
   if (nargin < 2 || nargin > 4)
     print_usage ();
   endif
@@ -49,22 +42,11 @@
   samples_per_sec = 8000;
   bits_per_sample = 16;
 
-  if (ischar (y))
-    filename = y;
-    y = varargin{1};
-    if (nargin > 2)
-      samples_per_sec = varargin{2};
-      if (nargin > 3)
-        bits_per_sample = varargin{3};
-      endif
-    endif
-  else
-    filename = varargin{end};
-    if (nargin > 2)
-      samples_per_sec = varargin{1};
-      if (nargin > 3)
-        bits_per_sample = varargin{2};
-      endif
+  filename = varargin{end};
+  if (nargin > 2)
+    samples_per_sec = varargin{1};
+    if (nargin > 3)
+      bits_per_sample = varargin{2};
     endif
   endif
 
@@ -72,7 +54,7 @@
   if (columns (y) < 1)
     error ("wavwrite: Y must have at least one column");
   endif
-  if (columns (y) > 2^15-1)
+  if (columns (y) > 0x7FFF)
     error ("wavwrite: Y has more than 32767 columns (too many for a WAV-file)");
   endif
 
@@ -89,17 +71,16 @@
   endswitch
 
   ## calculate filesize
-  [n, channels] = size(y);
+  [n, channels] = size (y);
 
   ## size of data chunk
   ck_size = n*channels*(bits_per_sample/8);
 
-  ## open file for writing binary
-
   if (! ischar (filename))
     error ("wavwrite: expecting FILENAME to be a character string");
   endif
 
+  ## open file for writing binary
   [fid, msg] = fopen (filename, "wb");
   if (fid < 0)
     error ("wavwrite: %s", msg);
@@ -126,8 +107,8 @@
   c += fwrite (fid, samples_per_sec, "uint32", 0, BYTEORDER);
 
   ## bytes per second
-  bps = samples_per_sec*channels*bits_per_sample/8;
-  c += fwrite (fid, bps, "uint32", 0, BYTEORDER);
+  byteps = samples_per_sec*channels*bits_per_sample/8;
+  c += fwrite (fid, byteps, "uint32", 0, BYTEORDER);
 
   ## block align
   c += fwrite (fid, channels*bits_per_sample/8, "uint16", 0, BYTEORDER);
@@ -147,11 +128,11 @@
   ## scale samples
   switch (bits_per_sample)
     case 8
-      yi = round (yi*127 + 128);
+      yi = round (yi*128 + 128);
     case 16
-      yi = round (yi*32767);
+      yi = round (yi*32768);
     case 32
-      yi = round (yi*2147483647);
+      yi = round (yi*2147483648);
   endswitch
 
   ## write to file
@@ -161,29 +142,39 @@
 
 endfunction
 
+
 %!test
-%! A = [1:10; 1:10]/10;
-%! wavwrite("a.wav", A);
-%! [B, samples_per_sec, bits_per_sample] = wavread("a.wav");
-%! assert(A,B, 10^(-4));
+%! A = [-1:0.1:1; -1:0.1:1];
+%! wavwrite (A, "a.wav");
+%! [B, samples_per_sec, bits_per_sample] = wavread ("a.wav");
+%! assert(A,B, 1/2^15);
 %! assert(samples_per_sec, 8000);
 %! assert(bits_per_sample, 16);
 %! delete ("a.wav");
 %
 %!test
-%! A=[1:10; 1:10] / 10;
-%! wavwrite("a.wav", A, 4000);
-%! [B, samples_per_sec, bits_per_sample] = wavread("a.wav");
-%! assert(A,B, 10^(-4));
+%! A = [-1:0.1:1; -1:0.1:1];
+%! wavwrite (A, 4000, "a.wav");
+%! [B, samples_per_sec, bits_per_sample] = wavread ("a.wav");
+%! assert(A,B, 1/2^15);
 %! assert(samples_per_sec, 4000);
 %! assert(bits_per_sample, 16);
 %! delete ("a.wav");
 %
 %!test
-%! A=[1:10; 1:10] / 10;
-%! wavwrite("a.wav", A, 4000, 8);
-%! [B, samples_per_sec, bits_per_sample] = wavread("a.wav");
-%! assert(A,B, 10^(-2));
+%! A = [-1:0.1:1; -1:0.1:1];
+%! wavwrite (A, 4000, 8, "a.wav");
+%! [B, samples_per_sec, bits_per_sample] = wavread ("a.wav");
+%! assert(A,B, 1/128);
 %! assert(samples_per_sec, 4000);
 %! assert(bits_per_sample, 8);
 %! delete ("a.wav");
+%
+%!test
+%! A = [-2:2];
+%! wavwrite (A, "a.wav");
+%! B = wavread ("a.wav");
+%! B *= 32768;
+%! assert(B, [-32768 -32768 0 32767 32767]);
+%! delete ("a.wav");
+