Mercurial > octave
view scripts/audio/wavread.m @ 5565:2eeed655e801
[project @ 2005-12-06 20:38:20 by jwe]
author | jwe |
---|---|
date | Tue, 06 Dec 2005 20:38:21 +0000 |
parents | |
children | 2f5d0d8a7f13 |
line wrap: on
line source
## 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