changeset 31047:13a7af4ca0da

Update lin2mu, mu2lin functions. * lin2mu.m: Rewrite docstring. Use default argument for input 'n' to simply input validation. Eliminate warning abut no precision certified. Add stricter input validation 'n' input. Use inplace operators for better performnace. Update BIST tests. * mu2lin.m: Rewrite docstring. Use default argument for input 'n' to simply input validation. Add BIST tests for function.
author Rik <rik@octave.org>
date Sat, 28 May 2022 23:21:53 -0700
parents b949f8a631e2
children faca2c7d5345
files scripts/audio/lin2mu.m scripts/audio/mu2lin.m
diffstat 2 files changed, 71 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/audio/lin2mu.m	Sat May 28 18:28:42 2022 -0700
+++ b/scripts/audio/lin2mu.m	Sat May 28 23:21:53 2022 -0700
@@ -24,47 +24,41 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {@var{y} =} lin2mu (@var{x}, @var{n})
+## @deftypefn  {} {@var{y} =} lin2mu (@var{x})
+## @deftypefnx {} {@var{y} =} lin2mu (@var{x}, @var{n})
 ## Convert audio data from linear to mu-law.
 ##
-## Mu-law values use 8-bit unsigned integers.  Linear values use @var{n}-bit
-## signed integers or floating point values in the range -1 @leq{} @var{x}
-## @leq{} 1 if @var{n} is 0.
-##
-## If @var{n} is not specified it defaults to 0, 8, or 16 depending on
-## the range of values in @var{x}.
+## Linear values use floating point values in the range -1 @leq{} @var{x}
+## @leq{} 1 if @var{n} is 0 (default), or @var{n}-bit signed integers if @var{n}
+## is 8 or 16.  Mu-law values are 8-bit unsigned integers in the range
+## 0 @leq{} @var{y} @leq{} 255.
 ## @seealso{mu2lin}
 ## @end deftypefn
 
-
-function y = lin2mu (x, n)
+function y = lin2mu (x, n = 0)
 
   if (nargin < 1)
     print_usage ();
   endif
 
-  if (nargin == 1)
-    range = max (abs (x (:)));
-    if (range <= 1)
+  ## Convert to floating point integers per Matlab.
+  x = double (x);
+
+  if (nargin == 2)
+    if (! isscalar (n) && ! isreal (n)
+        || (n != 0 && n != 8 && n != 16))
+      error ("lin2mu: N must be either 0, 8, or 16");
+    elseif (isempty (n))
       n = 0;
-    elseif (range <= 128)
-      n = 8;
-      warning ("lin2mu: no precision specified, so using %d", n);
-    else
-      n = 16;
-    endif
-  else
-    if (n != 0 && n != 8 && n != 16)
-      error ("lin2mu: N must be either 0, 8 or 16");
     endif
   endif
 
   ## Transform real and n-bit format to 16-bit.
   if (n == 0)
     ## [-1,1] -> [-32768, 32768]
-    x = 32768 * x;
+    x *= 32768;
   elseif (n != 16)
-    x = 2^(16-n) .* x;
+    x *= 256;
   endif
 
   ## Determine sign of x, set sign(0) = 1.
@@ -81,6 +75,7 @@
 
 endfunction
 
+
 ## Test functionality
 %!test
 %! x = -1:1;
@@ -95,15 +90,14 @@
 %!assert (lin2mu (0, 8), 255)
 %!assert (lin2mu (0, 16), 255)
 %!assert (lin2mu (2, 8), 219)
-%!assert (lin2mu (3, []), 255)
+%!assert (lin2mu (3, []), 128)
 %!assert (lin2mu (3, 16), 255)
 %!assert (lin2mu (repmat (-0.23, 1, 1000), 0), repmat (34, 1, 1000))
 %!assert (lin2mu (ones (2, 2), 0), repmat (128, 2))
 
 ## Test input validation
 %!error <Invalid call> lin2mu ()
-%!warning <no precision specified, so using 8> assert (lin2mu (2), 219)
-%!error <N must be either 0, 8 or 16> lin2mu (1, 2)
-%!error <N must be either 0, 8 or 16> lin2mu (1, [1,2])
-%!error <N must be either 0, 8 or 16> lin2mu (1, ones (1, 2))
-%!error <abs: not defined for cell> lin2mu ({2:5})
+%!error <N must be either 0, 8, or 16> lin2mu (1, 2)
+%!error <N must be either 0, 8, or 16> lin2mu (1, [1,2])
+%!error <N must be either 0, 8, or 16> lin2mu (1, ones (1, 2))
+%!error <invalid conversion> lin2mu ({2:5})
--- a/scripts/audio/mu2lin.m	Sat May 28 18:28:42 2022 -0700
+++ b/scripts/audio/mu2lin.m	Sat May 28 23:21:53 2022 -0700
@@ -24,14 +24,20 @@
 ########################################################################
 
 ## -*- texinfo -*-
-## @deftypefn {} {@var{y} =} mu2lin (@var{x}, @var{n})
+## @deftypefn  {} {@var{y} =} mu2lin (@var{x})
+## @deftypefnx {} {@var{y} =} mu2lin (@var{x}, @var{n})
 ## Convert audio data from mu-law to linear.
 ##
-## Mu-law values are 8-bit unsigned integers.  Linear values use @var{n}-bit
-## signed integers or floating point values in the range -1 @leq{} @var{y}
-## @leq{} 1 if @var{n} is 0.
+## Mu-law values are 8-bit unsigned integers in the range 0 @leq{} @var{y}
+## @leq{} 255.  Linear values use floating point values in the range
+## -@var{linmax} @leq{} @var{x} @var{linmax} (where
+## @code{@var{linmax} = 32124/32768 =~ 0.98}) when @var{n} is zero (default).
+## If @var{n} is 8 or 16 then @var{n}-bit signed integers are used instead.
 ##
-## If @var{n} is not specified it defaults to 0.
+## Programming Note: @code{mu2lin} maps maximum mu-law inputs to values
+## slightly below the maximum ([-0.98, +0.98]) representable with a linear
+## scale.  Because of this, @code{mu2lin (lin2mu (@var{x}))} might not
+## reproduce the original input.
 ## @seealso{lin2mu}
 ## @end deftypefn
 
@@ -41,8 +47,13 @@
     print_usage ();
   endif
 
-  if (n != 0 && n != 8 && n != 16)
-    error ("mu2lin: N must be either 0, 8, or 16");
+  if (nargin == 2)
+    if (! isscalar (n) && ! isreal (n)
+        || (n != 0 && n != 8 && n != 16))
+      error ("lin2mu: N must be either 0, 8, or 16");
+    elseif (isempty (n))
+      n = 0;
+    endif
   endif
 
   ulaw = [32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956, ...
@@ -74,7 +85,7 @@
     ## [ -32768, 32767 ] -> [ -1, 1)
     y /= 32768;
   elseif (n == 8)
-    ld = max (abs (y (:)));
+    ld = max (abs (y(:)));
     if (ld < 16384 && ld > 0)
       sc = 64 / ld;
     else
@@ -84,3 +95,32 @@
   endif
 
 endfunction
+
+
+## Test functionality
+%!shared linmax
+%! linmax = 32124 / 32768;
+
+%!test
+%! x = [0, 128, 255];
+%! y = x';
+%! assert (mu2lin (x), (mu2lin (y))');
+%! assert (mu2lin (x), [-linmax, +linmax, 0]);
+
+%!assert (mu2lin ([]), [])
+%!assert (mu2lin (255), 0)
+%!assert (mu2lin (255, 0), 0)
+%!assert (mu2lin (255, 8), 0)
+%!assert (mu2lin (255, 16), 0)
+%!assert (mu2lin (128, []), linmax)
+%!assert (mu2lin (128, 8), 125)
+%!assert (mu2lin (128, 16), 32124)
+%!assert (mu2lin (zeros (1, 1000), 0), repmat (-linmax, 1, 1000))
+%!assert (mu2lin (255*ones (2, 2), 0), zeros (2, 2))
+
+## Test input validation
+%!error <Invalid call> mu2lin ()
+%!error <N must be either 0, 8, or 16> mu2lin (1, 2)
+%!error <N must be either 0, 8, or 16> mu2lin (1, [1,2])
+%!error <N must be either 0, 8, or 16> mu2lin (1, ones (1, 2))
+%!error mu2lin ({2:5})