# HG changeset patch # User Rik # Date 1653805313 25200 # Node ID 13a7af4ca0da3e3571174c94601a3c044e3f290c # Parent b949f8a631e277182fb772e37112f2e81f7375c3 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. diff -r b949f8a631e2 -r 13a7af4ca0da scripts/audio/lin2mu.m --- 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 lin2mu () -%!warning assert (lin2mu (2), 219) -%!error lin2mu (1, 2) -%!error lin2mu (1, [1,2]) -%!error lin2mu (1, ones (1, 2)) -%!error lin2mu ({2:5}) +%!error lin2mu (1, 2) +%!error lin2mu (1, [1,2]) +%!error lin2mu (1, ones (1, 2)) +%!error lin2mu ({2:5}) diff -r b949f8a631e2 -r 13a7af4ca0da scripts/audio/mu2lin.m --- 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 mu2lin () +%!error mu2lin (1, 2) +%!error mu2lin (1, [1,2]) +%!error mu2lin (1, ones (1, 2)) +%!error mu2lin ({2:5})