changeset 5565:2eeed655e801

[project @ 2005-12-06 20:38:20 by jwe]
author jwe
date Tue, 06 Dec 2005 20:38:21 +0000
parents 019e68c33798
children 2f5d0d8a7f13
files scripts/ChangeLog scripts/audio/wavread.m scripts/audio/wavwrite.m
diffstat 3 files changed, 414 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/scripts/ChangeLog
+++ b/scripts/ChangeLog
@@ -1,3 +1,7 @@
+2005-12-06  Michael Zeising  <michael@michaels-website.de>
+
+	* audio/wavread.m, audio/wavwrite.m: New files.
+
 2005-12-06  John W. Eaton  <jwe@octave.org>
 
 	* miscellaneous/dir.m: Return Nx1 instead of 1xN struct array.
new file mode 100644
--- /dev/null
+++ b/scripts/audio/wavread.m
@@ -0,0 +1,294 @@
+## Copyright (C) 2005 Michael Zeising
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, write to the Free
+## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+## 02110-1301, USA.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {} @var{y} = wavread(@var{filename})
+## Load the RIFF/WAVE sound file @var{filename}, returning the samples 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})
+## Additionally return the sample rate (@var{fs}) in Hz and the number of bits 
+## per sample (@var{bits}).
+##
+## @deftypefnx {Function File} {} [...] = wavread(@var{filename},@var{n})
+## Read only the first @var{n} samples from each channel.
+##
+## @deftypefnx {Function File} {} [...] = wavread(@var{filename},[@var{n1} @var{n2}])
+## Read only samples @var{n1} through @var{n2} from each channel.
+##
+## @deftypefnx {Function File} {} [@var{samples} @var{channels}] = wavread(@var{filename},'size')
+## Return the number of samples (@var{n}) and channels (@var{ch}) instead of the 
+## audio data.
+##
+## @end deftypefn
+##
+## @seealso{wavwrite}
+
+## Author: Michael Zeising <michael.zeising@stud.uni-erlangen.de>
+## Created: 06 December 2005
+
+function [y, samplesPerSec, bitsPerSample] = wavread (filename, param)
+  FORMAT_PCM        = 0x0001;   # PCM (8/16/32 bit)
+  FORMAT_IEEE_FLOAT = 0x0003;   # IEEE float (32/64 bit)
+  FORMAT_ALAW       = 0x0006;   # 8-bit ITU-T G.711 A-law   (not yet supported)
+  FORMAT_MULAW      = 0x0007;   # 8-bit ITU-T G.711 ยต-law   (not yet supported)
+  FORMAT_IMA_ADPCM  = 0x0011;   # IMA/ADPCM 4:1 compression (not yet supported)
+  BYTEORDER         = "ieee-le";
+
+  # open file for binary reading
+  [fid, msg] = fopen (filename, "rb");
+  if (fid < 0)
+    error ("wavread: %s", msg)
+  endif
+  
+  # check for RIFF/WAVE header
+  ckID = char (fread (fid, 4))';                     # chunk ID: "RIFF"
+  fseek (fid, 4, SEEK_CUR);
+  WAVEID = char (fread (fid, 4))';                   # WAVE ID: "WAVE"
+  if ((ckID ~= "RIFF") || (WAVEID ~= "WAVE"))
+    fclose (fid);
+    error ("wavread: file contains no RIFF/WAVE signature");
+  endif
+  
+  # find format chunk within the next 256 (4*64) bytes
+  i = 1;
+  while 1
+    if (char (fread (fid, 4))' == "fmt ")
+      break
+    endif
+    if (i++ == 64)
+      fclose (fid);
+      error ("wavread: file contains no format chunk") 
+    endif
+  endwhile
+  
+  ckSize = fread (fid, 1, "ulong", 0, BYTEORDER);           # format chunk size
+  
+  formatTag = fread (fid, 1, "short", 0, BYTEORDER);        # sample format code
+  if ((formatTag ~= FORMAT_PCM) && (formatTag ~= FORMAT_IEEE_FLOAT))
+    fclose (fid);
+    error ("wavread: sample format %#x is not supported", formatTag) 
+  endif
+  
+  channels = fread (fid, 1, "short", 0, BYTEORDER);         # number of interleaved channels
+  samplesPerSec = fread (fid, 1, "ulong", 0, BYTEORDER);    # sample rate
+  fseek (fid, 6, SEEK_CUR);
+  bitsPerSample = fread (fid, 1, "short", 0, BYTEORDER);    # bits per sample
+  # ignore the rest of the chunk
+  fseek (fid, ckSize-16, SEEK_CUR);
+  
+  # find data chunk
+  i = 1;
+  while 1
+    if (char (fread(fid, 4))' == "data")
+      break
+    endif
+    if (i++ == 64)
+      fclose (fid);
+      error ("wavread: file contains no data chunk")
+    endif
+  end
+  
+  ckSize = fread (fid, 1, "ulong", 0, BYTEORDER);            # data chunk size
+  
+  # determine sample data type
+  if (formatTag == FORMAT_PCM)
+    switch bitsPerSample
+      case 8
+        format = "int8";
+      case 16 
+        format = "int16";
+      case 32 
+        format = "int32";
+      otherwise
+        fclose (fid);
+        error ("wavread: %d bits sample resolution is not supported with PCM", bitsPerSample);
+    endswitch
+  else
+    switch bitsPerSample
+      case 32 
+        format = "float32";
+      case 64 
+        format = "float64";
+      otherwise
+        fclose (fid);
+        error ("wavread: %d bits sample resolution is not supported with IEEE float", bitsPerSample);
+    endswitch
+  endif
+  
+  # parse arguments
+  if (exist ("param","var") < 1)
+    length = inf;
+  else
+    if (size(param)(2) == 1)                                 # number of samples is given
+      length = param * channels;
+    elseif (size(param)(2) == 2)                             # sample range is given
+      if fseek(fid, param(1) * channels * (bitsPerSample/8), SEEK_CUR) < 0
+        warning ("wavread: seeking failed")
+      endif
+      length = (param(2)-param(1)) * channels;
+    elseif ((size (param)(2) == 4) && (char(param) == "size"))   # size of the file is requested
+      fclose (fid);
+      y = [ckSize/channels/bitsPerSample/8 channels];
+      return
+    else
+      fclose (fid);
+      error ("wavread: invalid argument 2");
+    endif
+  endif
+  
+  # read samples
+  [yi, n] = fread (fid, length, format, 0, BYTEORDER);
+  
+  fclose (fid);
+  
+  if (formatTag == FORMAT_PCM)
+    # normalize samples
+    switch bitsPerSample
+      case 8
+        yi = (yi - 127)/127;      # 8-bit samples are unsigned
+      case {16,32}
+        yi = yi/((2 ** bitsPerSample) / 2 - 1);
+    endswitch
+  endif
+  
+  # deinterleave
+  y = [];
+  for (i = 1:channels)
+    y = [y yi(i:channels:n)];
+  endfor
+  
+endfunction
+## Copyright (C) 2005 Michael Zeising
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, write to the Free
+## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+## 02110-1301, USA.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {} wavwrite(@var{filename}, @var{y})
+## Write @var{y} to the canonical RIFF/WAVE sound file @var{filename}. A sample 
+## rate of 8000 Hz and 16-bit samples are assumed. Each column of the data 
+## represents a separate channel.
+##
+## @deftypefnx {Function File} {} wavwrite(@var{filename}, @var{y}, @var{fs})
+## Set the sample rate to @var{fs} Hz.
+##
+## @deftypefnx {Function File} {} wavwrite(@var{filename}, @var{y}, @var{fs}, @var{bits})
+## Set the sample rate to @var{fs} Hz and resolution to @var{bits} bits.
+##
+## @end deftypefn
+##
+## @seealso{wavread}
+
+## Author: Michael Zeising <michael.zeising@stud.uni-erlangen.de>
+## Created: 06 December 2005
+
+function wavwrite (filename, y, samplesPerSec, bitsPerSample)
+  BYTEORDER = "ieee-le";
+  
+  # parse arguments
+  if (exist ("samplesPerSec","var") < 1)
+    warning ("wavwrite: sample rate set to 8000 Hz")
+    samplesPerSec = 8000;
+  endif
+  if (exist ("bitsPerSample","var") < 1)
+    warning ("wavwrite: sample resolution set to 16-bit")
+    bitsPerSample = 16;
+  endif
+  
+  # determine sample format
+  switch bitsPerSample
+    case 8  
+      format = "int8";
+    case 16 
+      format = "int16";
+    case 32 
+      format = "int32";
+    otherwise
+      fclose (fid);
+      error ("wavread: sample resolution not supported");
+  endswitch
+  
+  # calculate filesize
+  channels = size(y)(2);
+  n = size(y)(1);
+  
+  ckSize = n*channels*(bitsPerSample/8);       # size of data chunk
+  
+  # open file for writing binary
+  [fid, msg] = fopen (filename, "wb");
+  if (fid < 0)
+    error ("wavwrite: %s", msg)
+  endif
+  
+  # write RIFF/WAVE header
+  c = 0;
+  c += fwrite (fid, "RIFF",        "uchar");
+  c += fwrite (fid, ckSize + 36,   "ulong", 0, BYTEORDER);   # file size - 8
+  c += fwrite (fid, "WAVEfmt ",    "uchar");
+  c += fwrite (fid, 16,            "ulong", 0, BYTEORDER);   # size of fmt chunk
+  c += fwrite (fid, 0x0001,        "short", 0, BYTEORDER);   # sample format code (PCM)
+  c += fwrite (fid, channels,      "short", 0, BYTEORDER);   # channels
+  c += fwrite (fid, samplesPerSec, "ulong", 0, BYTEORDER);   # sample rate
+  c += fwrite (fid, samplesPerSec*channels*bitsPerSample/8, "ulong", 0, BYTEORDER);   # bytes per second
+  c += fwrite (fid, channels*bitsPerSample/8,               "short", 0, BYTEORDER);   # block align
+  c += fwrite (fid, bitsPerSample, "short", 0, BYTEORDER);   # bits/sample
+  c += fwrite (fid, "data",        "uchar");
+  c += fwrite (fid, ckSize,        "ulong", 0, BYTEORDER);   # size of data chunk
+  
+  if (c < 25)
+    fclose (fid);
+    error ("wavread: writing to file failed")
+  endif
+  
+  # scale samples
+  switch bitsPerSample
+    case 8
+      y = floor (y*127 + 127);
+    case {16,32}
+      y = floor (y*((2 ** bitsPerSample) / 2 - 1));
+  endswitch
+  
+  # interleave samples
+  l = n*channels;
+  for (i = 1:channels)
+    yi(i:channels:l) = y(:,i);
+  endfor
+  
+  # write to file
+  c = fwrite (fid, yi, format, 0, BYTEORDER);
+  
+  fclose (fid);
+  
+endfunction
new file mode 100644
--- /dev/null
+++ b/scripts/audio/wavwrite.m
@@ -0,0 +1,116 @@
+## Copyright (C) 2005 Michael Zeising
+##
+## This file is part of Octave.
+##
+## Octave is free software; you can redistribute it and/or modify it
+## under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2, or (at your option)
+## any later version.
+##
+## Octave is distributed in the hope that it will be useful, but
+## WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+## General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with Octave; see the file COPYING.  If not, write to the Free
+## Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+## 02110-1301, USA.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {} wavwrite(@var{filename}, @var{y})
+## Write @var{y} to the canonical RIFF/WAVE sound file @var{filename}. A sample 
+## rate of 8000 Hz and 16-bit samples are assumed. Each column of the data 
+## represents a separate channel.
+##
+## @deftypefnx {Function File} {} wavwrite(@var{filename}, @var{y}, @var{fs})
+## Set the sample rate to @var{fs} Hz.
+##
+## @deftypefnx {Function File} {} wavwrite(@var{filename}, @var{y}, @var{fs}, @var{bits})
+## Set the sample rate to @var{fs} Hz and resolution to @var{bits} bits.
+##
+## @end deftypefn
+##
+## @seealso{wavread}
+
+## Author: Michael Zeising <michael.zeising@stud.uni-erlangen.de>
+## Created: 06 December 2005
+
+function wavwrite (filename, y, samplesPerSec, bitsPerSample)
+  BYTEORDER = "ieee-le";
+  
+  # parse arguments
+  if (exist ("samplesPerSec","var") < 1)
+    warning ("wavwrite: sample rate set to 8000 Hz")
+    samplesPerSec = 8000;
+  endif
+  if (exist ("bitsPerSample","var") < 1)
+    warning ("wavwrite: sample resolution set to 16-bit")
+    bitsPerSample = 16;
+  endif
+  
+  # determine sample format
+  switch bitsPerSample
+    case 8  
+      format = "int8";
+    case 16 
+      format = "int16";
+    case 32 
+      format = "int32";
+    otherwise
+      fclose (fid);
+      error ("wavread: sample resolution not supported");
+  endswitch
+  
+  # calculate filesize
+  channels = size(y)(2);
+  n = size(y)(1);
+  
+  ckSize = n*channels*(bitsPerSample/8);       # size of data chunk
+  
+  # open file for writing binary
+  [fid, msg] = fopen (filename, "wb");
+  if (fid < 0)
+    error ("wavwrite: %s", msg)
+  endif
+  
+  # write RIFF/WAVE header
+  c = 0;
+  c += fwrite (fid, "RIFF",        "uchar");
+  c += fwrite (fid, ckSize + 36,   "ulong", 0, BYTEORDER);   # file size - 8
+  c += fwrite (fid, "WAVEfmt ",    "uchar");
+  c += fwrite (fid, 16,            "ulong", 0, BYTEORDER);   # size of fmt chunk
+  c += fwrite (fid, 0x0001,        "short", 0, BYTEORDER);   # sample format code (PCM)
+  c += fwrite (fid, channels,      "short", 0, BYTEORDER);   # channels
+  c += fwrite (fid, samplesPerSec, "ulong", 0, BYTEORDER);   # sample rate
+  c += fwrite (fid, samplesPerSec*channels*bitsPerSample/8, "ulong", 0, BYTEORDER);   # bytes per second
+  c += fwrite (fid, channels*bitsPerSample/8,               "short", 0, BYTEORDER);   # block align
+  c += fwrite (fid, bitsPerSample, "short", 0, BYTEORDER);   # bits/sample
+  c += fwrite (fid, "data",        "uchar");
+  c += fwrite (fid, ckSize,        "ulong", 0, BYTEORDER);   # size of data chunk
+  
+  if (c < 25)
+    fclose (fid);
+    error ("wavread: writing to file failed")
+  endif
+  
+  # scale samples
+  switch bitsPerSample
+    case 8
+      y = floor (y*127 + 127);
+    case {16,32}
+      y = floor (y*((2 ** bitsPerSample) / 2 - 1));
+  endswitch
+  
+  # interleave samples
+  l = n*channels;
+  for (i = 1:channels)
+    yi(i:channels:l) = y(:,i);
+  endfor
+  
+  # write to file
+  c = fwrite (fid, yi, format, 0, BYTEORDER);
+  
+  fclose (fid);
+  
+endfunction