From sources-request at octave dot org Tue Dec 6 08:07:33 2005 Subject: wavread, wavwrite: Matlab-compatible RIFF/WAVE import and export functions From: Michael Zeising To: sources at octave dot org Date: Tue, 6 Dec 2005 05:29:15 -0600 This is a multi-part message in MIME format. --------------060806010909000807000106 Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 7bit RIFF/WAVE (.wav) is the most spread format for uncompressed PCM data. As I'm using my machine for measuring, I need some fast and flexible functions for handling WAVE data. The functions support 8- and 16-bit (more will follow) multichannel data, they are fully compatible with their Matlab versions and they are well documented. Please consider including them into the distribution. Michael Zeising --------------060806010909000807000106 Content-Type: text/x-objcsrc; name="wavread.m" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="wavread.m" ## 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 -*- ## at deftypefn {Function File} {} @var{y} = wavread(@var{filename}) ## at deftypefnx {Function File} {} [@var{y},@var{Fs},@var{bits}] = wavread(@var{filename}) ## at deftypefnx {Function File} {} [...] = wavread(@var{filename},@var{n}) ## at deftypefnx {Function File} {} [...] = wavread(@var{filename},[@var{n1} @var{n2}]) ## at deftypefnx {Function File} {} [@var{samples} @var{channels}] = wavread(@var{filename},'size') ## Read canonical RIFF/WAVE (.wav) sound file with 8 or 16 bits per sample ## ## at var{y} = wavread(@var{filename}) loads a WAVE file specified by the string ## at var{filename}, returning the sampled data in vector @var{y}. If the file ## contains multichannel data, then at var{y} is a matrix with the channels ## represented as columns. Amplitude values are in the range [-1, +1]. ## ## [ at var{y}, @var{Fs}, @var{bits}] = wavread(@var{filename}) returns the ## sample rate (Fs) in Hertz and the number of bits per sample (bits) used to ## encode the data in the file. ## ## [...] = wavread( at var{filename},@var{n}) returns only the first @var{n} ## samples from each channel in the file. ## ## [...] = wavread( at var{filename},[@var{n1} @var{n2}]) returns only samples ## at var{n1} through @var{n2} from each channel in the file. ## ## [ at var{samples} @var{channels}] = wavread(@var{filename},'size') returns the ## size of the audio data contained in the file. ## ## at end deftypefn ## ## at seealso{wavwrite} ## Author: Michael Zeising ## Created: 06 December 2005 function [y, fs, bits] = wavread(filename, param) byteorder = 'ieee-le'; # open file for binary reading [fid, msg] = fopen(filename, 'rb'); if fid < 0 error(['wavread: ' msg]); end # interpret RIFF/WAVE header h_riff = char(fread(fid, 4))'; # "RIFF" fseek(fid, 4, SEEK_CUR); h_wave = char(fread(fid, 4))'; # "WAVE" h_fmt = char(fread(fid, 4))'; # "fmt " fmt_len = fread(fid, 1, 'ulong', 0, byteorder); # size of fmt chunk fmt_format = fread(fid, 1, 'short', 0, byteorder); # sample format fmt_ch = fread(fid, 1, 'short', 0, byteorder); # channels fs = fread(fid, 1, 'ulong', 0, byteorder); # sample rate fseek(fid, 6, SEEK_CUR); bits = fread(fid, 1, 'short', 0, byteorder); # bits / sample h_data = char(fread(fid, 4))'; # "data" data_len = fread(fid, 1, 'ulong', 0, byteorder); # size of data chunk # check for valid header if ((h_riff ~= 'RIFF') || (h_wave ~= 'WAVE') || (h_fmt ~= 'fmt ') || (h_data ~= 'data') || fmt_format ~= 1 || fmt_len ~= 16) fclose(fid); error('wavread: file contains no canonical RIFF/WAVE format'); end # determine sample format if (bits == 8) format = 'uchar'; elseif (bits == 16) format = 'short'; else fclose(fid); error('wavread: file contains an unsupported sample resolution'); end # parse arguments if exist('param','var') < 1 length = inf; else if size(param)(2) == 1 # number of samples is given length = param*fmt_ch; elseif size(param)(2) == 2 # sample range is given if fseek(fid, param(1)*fmt_ch*(bits/8), SEEK_CUR) < 0 warning('seeking failed') end length = (param(2)-param(1))*fmt_ch; elseif (size(param)(2) == 4) && (char(param) == 'size') # size of the file is requested fclose(fid); y = [data_len/fmt_ch/bits/8 fmt_ch]; return else fclose(fid); error('wavread: invalid argument 2'); end end # read samples [yi, n] = fread(fid, length, format, 0, byteorder); fclose(fid); # normalize samples if (bits == 8) yi = (yi - 127)/127; else yi = yi/32767; end # deinterleave y = []; for (i = 1:fmt_ch) y = [y yi(i:fmt_ch:n)]; end return --------------060806010909000807000106 Content-Type: text/x-objcsrc; name="wavwrite.m" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="wavwrite.m" ## 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 -*- ## at deftypefn {Function File} {} wavwrite(@var{filename}, @var{y}) ## at deftypefnx {Function File} {} wavwrite(@var{filename}, @var{y}, @var{fs}) ## at deftypefnx {Function File} {} wavwrite(@var{filename}, @var{y}, @var{fs}, @var{bits}) ## Write canonical RIFF/WAVE (.wav) sound file with 8 or 16 bits per sample ## ## wavwrite( at var{filename},@var{y}) writes the data stored in @var{y} to a ## RIFF/WAVE file called at var{filename} dot The data has a sample rate of 8000 Hz ## and is assumed to be 16-bit. Each column of the data represents a separate ## channel. ## ## wavwrite( at var{filename},@var{y},@var{fs}) writes the data stored in @var{y} ## to a RIFF/WAVE file called at var{filename} dot The data has a sample rate of ## at var{fs} Hz and is assumed to be 16-bit. ## ## wavwrite( at var{filename},@var{y},@var{fs},@var{bits}) writes the data stored ## in at var{y} to a RIFF/WAVE file called @var{filename}. The data has a sample ## rate of at var{fs} Hz and samples @var{bits} bits wide. ## ## at end deftypefn ## ## at seealso{wavread} ## Author: Michael Zeising ## Created: 06 December 2005 function wavwrite(filename, y, fs, bits) byteorder = 'ieee-le'; # parse arguments if exist('fs','var') < 1 warning('wavwrite: sample rate set to 8000 Hz') fs = 8000; end if exist('bits','var') < 1 warning('wavwrite: sample format set to 16-bit') bits = 16; end # determine sample format if bits == 8 format = 'uchar'; elseif bits == 16 format = 'short'; else error('wavread: unsupported sample resolution'); end # calculate filesize channels = size(y)(2); nsamples = size(y)(1); data_len = nsamples*channels*(bits/8); # size of data chunk # open file for writing binary [fid, msg] = fopen(filename, 'wb'); if fid < 0 error(['wavwrite: ' msg]); end # write RIFF/WAVE header c = 0; c += fwrite(fid, 'RIFF', 'uchar'); c += fwrite(fid, data_len + 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, 1, 'short', 0, byteorder); # sample format (1=PCM) c += fwrite(fid, channels, 'short', 0, byteorder); # channels c += fwrite(fid, fs, 'ulong', 0, byteorder); # sample rate c += fwrite(fid, 0, 'ulong', 0, byteorder); # bytes/sec c += fwrite(fid, 0, 'short', 0, byteorder); # channels*bits/sample/8 c += fwrite(fid, bits, 'short', 0, byteorder); # bits/sample c += fwrite(fid, 'data', 'uchar'); c += fwrite(fid, data_len, 'ulong', 0, byteorder); # size of data chunk if (c < 25) fclose(fid); error('wavread: writing to file failed') end # scale samples if bits == 16 y = floor(y*32767); else y = floor(y*127 + 127); end # interleave samples l = nsamples*channels; for i = 1:channels yi(i:channels:l) = y(:,i); end # write to file c = fwrite(fid, yi, format, 0, byteorder); fclose(fid); return --------------060806010909000807000106--