Update to wavread.m and wavwrite.m
Michael Zeising <[email protected]> Sun, 07 Oct 2007 12:28:08 +0200
| Newsgroups | gmane.comp.gnu.octave.sources |
|---|---|
| Message-ID | <[email protected]> |
This is a multi-part message in MIME format.
--------------060302050900000805070406
Content-Type: text/plain; charset=ISO-8859-15; format=flowed
Content-Transfer-Encoding: 7bit
Hi there,
I've currently noticed that the sample scaling in my WAV functions is
wrong and causes asymmetries and DC components (thanks to Denis
Sbragion). I've attached an updated version of them and I hope you can
include them into the distribution of octave. Thanks in advance!
Regards,
Michael Zeising
--------------060302050900000805070406
Content-Type: text/x-objcsrc;
name="wavread.m"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="wavread.m"
## Copyright (C) 2007 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}, and return 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} {[@dots{}] =} wavread (@var{filename}, @var{n})
## Read only the first @var{n} samples from each channel.
##
## @deftypefnx {Function File} {[@dots{}] =} 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.
## @seealso{wavwrite}
## @end deftypefn
## Author: Michael Zeising <[email protected]>
## Created: 07 October 2007
function [y, samples_per_sec, bits_per_sample] = wavread (filename, param)
FORMAT_PCM = 0x0001; # PCM (8/16/32 bit)
FORMAT_IEEE_FLOAT = 0x0003; # IEEE float (32/64 bit)
BYTEORDER = "ieee-le";
if (nargin < 1 || nargin > 2)
print_usage ();
endif
if (! ischar (filename))
error ("wavwrite: expecting filename to be a character string");
endif
# open file for binary reading
[fid, msg] = fopen (filename, "rb");
if (fid < 0)
error ("wavread: %s", msg);
endif
## check for RIFF/WAVE header
ck_id = char (fread (fid, 4))';
fseek (fid, 4, SEEK_CUR);
wave_id = char (fread (fid, 4))';
if (ck_id != "RIFF" || wave_id != "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 (true)
if (char (fread (fid, 4))' == "fmt ");
break;
endif
if (i++ == 64)
fclose (fid);
error ("wavread: file contains no format chunk");
endif
endwhile
## format chunk size
ck_size = fread (fid, 1, "uint32", 0, BYTEORDER);
## sample format code
format_tag = fread (fid, 1, "uint16", 0, BYTEORDER);
if (format_tag != FORMAT_PCM && format_tag != FORMAT_IEEE_FLOAT)
fclose (fid);
error ("wavread: sample format %#x is not supported", format_tag);
endif
## number of interleaved channels
channels = fread (fid, 1, "uint16", 0, BYTEORDER);
## sample rate
samples_per_sec = fread (fid, 1, "uint32", 0, BYTEORDER);
## bits per sample
fseek (fid, 6, SEEK_CUR);
bits_per_sample = fread (fid, 1, "uint16", 0, BYTEORDER);
## ignore the rest of the chunk
fseek (fid, ck_size-16, SEEK_CUR);
## find data chunk
i = 1;
while (true)
if (char (fread (fid, 4))' == "data")
break;
endif
if (i++ == 64)
fclose (fid);
error ("wavread: file contains no data chunk");
endif
end
## data chunk size
ck_size = fread (fid, 1, "uint32", 0, BYTEORDER);
## determine sample data type
if (format_tag == FORMAT_PCM)
switch (bits_per_sample)
case 8
format = "uint8";
case 16
format = "int16";
case 24
format = "uint8";
case 32
format = "int32";
otherwise
fclose (fid);
error ("wavread: %d bits sample resolution is not supported with PCM",
bits_per_sample);
endswitch
else
switch (bits_per_sample)
case 32
format = "float32";
case 64
format = "float64";
otherwise
fclose (fid);
error ("wavread: %d bits sample resolution is not supported with IEEE float",
bits_per_sample);
endswitch
endif
## parse arguments
if (nargin == 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)-1) * channels * (bits_per_sample/8), SEEK_CUR) < 0)
warning ("wavread: seeking failed");
endif
length = (param(2)-param(1)+1) * channels;
elseif (size (param, 2) == 4 && char (param) == "size")
## size of the file is requested
fclose (fid);
y = [ck_size/channels/(bits_per_sample/8), channels];
return
else
fclose (fid);
error ("wavread: invalid argument 2");
endif
endif
## read samples and close file
if (bits_per_sample == 24)
length *= 3;
endif
[yi, n] = fread (fid, length, format, 0, BYTEORDER);
fclose (fid);
## check data
if (mod (numel (yi), channels) != 0)
error ("wavread: data in %s doesn't match the number of channels",
filename);
endif
if (bits_per_sample == 24)
yi = reshape (yi, 3, rows(yi)/3)';
yi(yi(:,3) >= 128, 3) -= 256;
yi = yi * [1; 256; 65536];
end
if (format_tag == FORMAT_PCM)
## normalize samples
switch (bits_per_sample)
case 8
yi = (yi - 128)/127;
case 16
yi /= 32767;
case 24
yi /= 8388607;
case 32
yi /= 2147483647;
endswitch
endif
## deinterleave
nr = numel (yi) / channels;
y = reshape (yi, channels, nr)';
endfunction
--------------060302050900000805070406
Content-Type: text/x-objcsrc;
name="wavwrite.m"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="wavwrite.m"
## Copyright (C) 2007 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.
## @seealso{wavread}
## @end deftypefn
## Author: Michael Zeising <[email protected]>
## Created: 07 October 2007
function wavwrite (filename, y, samples_per_sec, bits_per_sample)
BYTEORDER = "ieee-le";
if (nargin < 2 || nargin > 4)
print_usage ();
endif
## test arguments
if (columns (y) < 1)
error ("wavwrite: Y must have at least one column");
endif
if (columns (y) > 2^15-1)
error ("wavwrite: Y has more than 32767 columns (too many for a WAV-file)");
endif
## parse arguments
if (nargin < 3)
samples_per_sec = 8000;
endif
if (nargin < 4)
bits_per_sample = 16;
endif
## determine sample format
switch (bits_per_sample)
case 8
format = "uint8";
case 16
format = "int16";
case 32
format = "int32";
otherwise
error ("wavwrite: sample resolution not supported");
endswitch
## calculate filesize
[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
[fid, msg] = fopen (filename, "wb");
if (fid < 0)
error ("wavwrite: %s", msg)
endif
## write RIFF/WAVE header
c = 0;
c += fwrite (fid, "RIFF", "uchar");
## file size - 8
c += fwrite (fid, ck_size + 36, "uint32", 0, BYTEORDER);
c += fwrite (fid, "WAVEfmt ", "uchar");
## size of fmt chunk
c += fwrite (fid, 16, "uint32", 0, BYTEORDER);
## sample format code (PCM)
c += fwrite (fid, 1, "uint16", 0, BYTEORDER);
## channels
c += fwrite (fid, channels, "uint16", 0, BYTEORDER);
## sample rate
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);
## block align
c += fwrite (fid, channels*bits_per_sample/8, "uint16", 0, BYTEORDER);
c += fwrite (fid, bits_per_sample, "uint16", 0, BYTEORDER);
c += fwrite (fid, "data", "uchar");
c += fwrite (fid, ck_size, "uint32", 0, BYTEORDER);
if (c < 25)
fclose (fid);
error ("wavwrite: writing to file failed");
endif
## interleave samples
yi = reshape (y', n*channels, 1);
## scale samples
switch (bits_per_sample)
case 8
yi = round (yi*127 + 128);
case 16
yi = round (yi*32767);
case 32
yi = round (yi*2147483647);
endswitch
## write to file
c = fwrite (fid, yi, format, 0, BYTEORDER);
fclose (fid);
endfunction
--------------060302050900000805070406
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
Octave-sources mailing list
[email protected]
https://www.cae.wisc.edu/mailman/listinfo/octave-sources
--------------060302050900000805070406--