% WAVREAD WAVREAD Read a WAV Audio File % % Usage % % The wavread function (attempts) to read the contents of a linear PCM % audio WAV file. This function could definitely use improvements - it is % based on a very simplistic notion of a WAV file. The simplest form for % its use is % % y = wavread(filename) % % where filename is the name of the WAV file to read. If no extension % is provided, FreeMat will add a '.wav' extension. This loads the data % from the WAV file into y, and returns it in double precision, % normalized format. If you want additional information on, for example, % the WAV sampling rate or bit depth, you can request it via % % [y, SamplingRate, BitDepth] = wavread(filename) % % where SamplingRate and BitDepth are the sampling rate (in Hz) and % the bit depth of the original data in the WAV file. If you only want to % load part of the WAV file, you can use % % [...] = wavread(filename, N) % % where N indicates the number of samples to read from the file. % Alternately, you can indicate a range of samples to load via % % [...] = wavread(filename, [N1 N2]) % % which returns only the indicated samples from each channel in the file. % By default, the output format is double precision. You can cntrol % the format of the output by indicating % % [...] = wavread(filename, format) % % where format is either 'double' for double precision output, or % 'native' for native precision output (meaning whatever bitdepth that % was present in the original file). Finally, you can use the 'size' flag % % y_siz = wavread(filename,'size') % % which returns a vector [samples channels] indicating the size of the % data present in the WAV file. function varargout = wavread(varargin); % Originally based on : % http://ccrma.stanford.edu/workshops/dsp2006/xjs/software/octave/wavread.m % which was public domain % with some significant changes to make it work with FreeMat, and to % more closely match the MATLAB API. % First study the input arguments to figure out what is needed here if (nargin == 0) error('wavread requires at least one argument'); end filename = varargin{1}; varargin(1) = []; nargin = nargin-1; range = [1,inf]; format = 'double'; sizeflag = false; while (nargin > 0) if (isstr(varargin{1})) if (strcmp(varargin{1},'size')) sizeflag = true; elseif (strcmp(varargin{1},'double')) format = 'double'; elseif (strcmp(varargin{1},'native')) format = 'native'; else error(sprintf('unrecognized argument to wavread: %s',varargin{1})); end elseif (isnumeric(varargin{1})) p = int32(varargin{1}); if (isscalar(p)) range = [1,p]; elseif (numel(p) == 2) range = p; else error(sprintf('unrecognized argument to wavread')); end else error(sprintf('unrecognized argument to wavread')); end varargin(1) = []; nargin = nargin-1; end % Check the filename [p,n,e,v] = fileparts(filename); if (isempty(e)) filename = [filename,'.wav']; end % Here we go - open the file in little endian mode fpi = fopen(filename,'rb','le'); % Read the RIFF string id = get4bytestring(fpi); if (~strcmp(id,'RIFF')) fclose(fpi); error(sprintf('%s not a WAV file',filename)); end % Get the number of bytes in the file nbytes = fread(fpi, 1,'int32'); % Read the WAVE string subfmt = get4bytestring(fpi); if (~strcmp(subfmt,'WAVE')) fclose(fpi); error(sprintf('*** Cannot handle subformat %s',subfmt)); end % Read the fmt block fmt = get4bytestring(fpi); if (~strcmp(fmt,'fmt ')) fclose(fpi); error(sprintf('*** Expected format specifier, got %s',fmt)); end % Read the format chunk length cl = fread(fpi, 1,'int32'); % Read the data format type data_type = fread(fpi,1,'int16'); nchans = fread(fpi,1,'int16'); srate = fread(fpi,1,'int32'); tmpi = fread(fpi,1,'int32'); bps = fread(fpi,1,'int16'); nbits = fread(fpi,1,'int16'); % Dump any extra bytes p = fread(fpi,cl-16,'int8'); % Read the DATA string id = get4bytestring(fpi); while (~strcmp(id,'data')) cl = fread(fpi, 1, 'int32'); fread(fpi,cl,'int8'); id = get4bytestring(fpi); end if (~strcmp(id,'data')) fclose(fpi); error(sprintf('Did not find ''data'' ID where expected')); end nbytes = fread(fpi,1,'int32'); % OK - we now have enough info to calculate the size vector nbytes_per_sample = uint32(nbits/8); total_sample_count = uint32(nbytes/nbytes_per_sample); samples_per_channel = uint32(total_sample_count/nchans); size_vector = uint32([samples_per_channel,nchans]); % in size mode just return if (sizeflag) fclose(fpi); varargout = {size_vector}; return; end % Adjust the requested range to fit inside the actual size range = [max(range(1),1),min(range(2),samples_per_channel)]; % based on the the bits in the data... set the format to read in % the data if (nbits == 8) datafmt = 'uint8'; elseif (nbits == 16) datafmt = 'int16'; elseif (nbits == 24) datafmt = 'int24'; elseif (nbits == 32) if (data_type == 1) datafmt = 'int32'; elseif (data_type == 3) datafmt = 'float'; end else fclose(fpi); error('Unsupported WAV format!'); end % Seek to the right spot in the stream offset = range(1)-1; count = range(2)-range(1)+1; fseek(fpi,offset*nbytes_per_sample*nchans,'cof'); % Read the data out if (strcmp(datafmt,'int24')) snd = fread_24bit(fpi,[nchans,count]); else snd = fread(fpi,[nchans,count],datafmt)'; end if (strcmp(format,'double')) if (nbits == 8) snd = snd/255.0*2.0 - 1.0; elseif (nbits == 16) snd = snd/(2^15); elseif (nbits == 24) snd = snd/(2^23); elseif (nbits == 32) if (data_type == 1) snd = snd/(2^31); else snd = double(snd); end end end fclose(fpi); varargout = {snd,srate,nbits}; function str = get4bytestring(fp) str = char(fread(fp,[1,4],'int8')); function odat = fread_24bit(fp,size) dat = fread(fp,[size(1)*size(2)*3,1],'int8'); lo = int2bin(dat(1:3:end),8); med = int2bin(dat(2:3:end),8); hi = int2bin(dat(3:3:end),8); sg = repmat(hi(:,1),[1,8]); odat = int32(bin2int([sg,hi,med,lo])); odat = reshape(odat,size);