Home > voicebox > readwav.m

readwav

PURPOSE ^

READWAV Read a .WAV format sound file [Y,FS,WMODE,FIDX]=(FILENAME,MODE,NMAX,NSKIP)

SYNOPSIS ^

function [y,fs,wmode,fidx]=readwav(filename,mode,nmax,nskip)

DESCRIPTION ^

READWAV  Read a .WAV format sound file [Y,FS,WMODE,FIDX]=(FILENAME,MODE,NMAX,NSKIP)

 Input Parameters:

    FILENAME gives the name of the file (with optional .WAV extension) or alternatively
                 can be the FIDX output from a previous call to READWAV
    MODE        specifies the following (*=default):

    Scaling: 's'    Auto scale to make data peak = +-1
             'r'    Raw unscaled data (integer values)
             'q'    Scaled to make 0dBm0 be unity mean square
             'p' *     Scaled to make +-1 equal full scale
             'o'    Scale to bin centre rather than bin edge (e.g. 127 rather than 127.5 for 8 bit values)
                     (can be combined with n+p,r,s modes)
             'n'    Scale to negative peak rather than positive peak (e.g. 128.5 rather than 127.5 for 8 bit values)
                     (can be combined with o+p,r,s modes)
             'g'    Scale by the gain written by the "g" option in "writewav" to restore original level
     Offset: 'y' *     Correct for offset in <=8 bit PCM data
             'z'    No offset correction
   File I/O: 'f'    Do not close file on exit
             'd'    Look in data directory: voicebox('dir_data')
   Display;  'h'    Print header information
             'w'    Plot waveform
             'W'    Plot spectrogram
             'a'    play audio (max 10 seconds)
             'A'    play all audio even if very long

    NMAX     maximum number of samples to read (or -1 for unlimited [default])
    NSKIP    number of samples to skip from start of file
               (or -1 to continue from previous read when FIDX is given instead of FILENAME [default])

 Output Parameters:

    Y        data matrix of dimension (samples,channels)
    FS       sample frequency in Hz
    WMODE    mode string needed for WRITEWAV to recreate the data file
    FIDX     Information row vector containing the element listed below.

           (1)  file id
            (2)  current position in file
           (3)  dataoff    byte offset in file to start of data
           (4)  nsamp    number of samples
           (5)  nchan    number of channels
           (6)  nbyte    bytes per data value
           (7)  bits    number of bits of precision
           (8)  code    Data format: 1=PCM, 2=ADPCM, 3=floating point, 6=A-law, 7=Mu-law
           (9)  fs        sample frequency
           (10) mask   channel mask
           (11) gain   gain factor in dB
           (12) riffmt 'e' original wav format, 'x' WAVEFORMATEX format, 'X' WAVEFORMATEXTENSIBLE format
           (13) factlen length of FACT chunk

   If no output parameters are specified, header information will be printed.

   For stereo data, y(:,1) is the left channel and y(:,2) the right
   The mask, if specified, is a bit field giving the channels present in the following order:
   0=FL, 1=FR, 2=FC, 3=W, 4=BL, 5=BR, 6=FLC, 7=FRC, 8=BC, 9=SL, 10=SR, 11=TC, 12=TFL, 13=TFC, 14=TFR, 15=TBL, 16=TBC, 17=TBR
   where F=front, L=left, C=centre, W=woofer (low frequency), B=back, LC=left of centre, RC=right of centre, S=side, T=top

   See also WRITEWAV.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function [y,fs,wmode,fidx]=readwav(filename,mode,nmax,nskip)
0002 %READWAV  Read a .WAV format sound file [Y,FS,WMODE,FIDX]=(FILENAME,MODE,NMAX,NSKIP)
0003 %
0004 % Input Parameters:
0005 %
0006 %    FILENAME gives the name of the file (with optional .WAV extension) or alternatively
0007 %                 can be the FIDX output from a previous call to READWAV
0008 %    MODE        specifies the following (*=default):
0009 %
0010 %    Scaling: 's'    Auto scale to make data peak = +-1
0011 %             'r'    Raw unscaled data (integer values)
0012 %             'q'    Scaled to make 0dBm0 be unity mean square
0013 %             'p' *     Scaled to make +-1 equal full scale
0014 %             'o'    Scale to bin centre rather than bin edge (e.g. 127 rather than 127.5 for 8 bit values)
0015 %                     (can be combined with n+p,r,s modes)
0016 %             'n'    Scale to negative peak rather than positive peak (e.g. 128.5 rather than 127.5 for 8 bit values)
0017 %                     (can be combined with o+p,r,s modes)
0018 %             'g'    Scale by the gain written by the "g" option in "writewav" to restore original level
0019 %     Offset: 'y' *     Correct for offset in <=8 bit PCM data
0020 %             'z'    No offset correction
0021 %   File I/O: 'f'    Do not close file on exit
0022 %             'd'    Look in data directory: voicebox('dir_data')
0023 %   Display;  'h'    Print header information
0024 %             'w'    Plot waveform
0025 %             'W'    Plot spectrogram
0026 %             'a'    play audio (max 10 seconds)
0027 %             'A'    play all audio even if very long
0028 %
0029 %    NMAX     maximum number of samples to read (or -1 for unlimited [default])
0030 %    NSKIP    number of samples to skip from start of file
0031 %               (or -1 to continue from previous read when FIDX is given instead of FILENAME [default])
0032 %
0033 % Output Parameters:
0034 %
0035 %    Y        data matrix of dimension (samples,channels)
0036 %    FS       sample frequency in Hz
0037 %    WMODE    mode string needed for WRITEWAV to recreate the data file
0038 %    FIDX     Information row vector containing the element listed below.
0039 %
0040 %           (1)  file id
0041 %            (2)  current position in file
0042 %           (3)  dataoff    byte offset in file to start of data
0043 %           (4)  nsamp    number of samples
0044 %           (5)  nchan    number of channels
0045 %           (6)  nbyte    bytes per data value
0046 %           (7)  bits    number of bits of precision
0047 %           (8)  code    Data format: 1=PCM, 2=ADPCM, 3=floating point, 6=A-law, 7=Mu-law
0048 %           (9)  fs        sample frequency
0049 %           (10) mask   channel mask
0050 %           (11) gain   gain factor in dB
0051 %           (12) riffmt 'e' original wav format, 'x' WAVEFORMATEX format, 'X' WAVEFORMATEXTENSIBLE format
0052 %           (13) factlen length of FACT chunk
0053 %
0054 %   If no output parameters are specified, header information will be printed.
0055 %
0056 %   For stereo data, y(:,1) is the left channel and y(:,2) the right
0057 %   The mask, if specified, is a bit field giving the channels present in the following order:
0058 %   0=FL, 1=FR, 2=FC, 3=W, 4=BL, 5=BR, 6=FLC, 7=FRC, 8=BC, 9=SL, 10=SR, 11=TC, 12=TFL, 13=TFC, 14=TFR, 15=TBL, 16=TBC, 17=TBR
0059 %   where F=front, L=left, C=centre, W=woofer (low frequency), B=back, LC=left of centre, RC=right of centre, S=side, T=top
0060 %
0061 %   See also WRITEWAV.
0062 
0063 %   *** Note on scaling ***
0064 %   If we want to scale signal values in the range +-1 to an integer in the
0065 %   range [-128,127] then we have four plausible choices corresponding to
0066 %   scale factors of (a) 127, (b) 127.5, (c) 128 or (d) 128.5 but each choice
0067 %   has disadvantages.
0068 %   For forward scaling: (c) and (d) cause clipping on inputs of +1.
0069 %   For reverse scaling: (a) and (b) can generate output values < -1.
0070 %   Any of these scalings can be selected via the mode input: (a) 'o', (b) default, (c) 'on', (d) 'n'
0071 
0072 %       Copyright (C) Mike Brookes 1998-2011
0073 %      Version: $Id: readwav.m 10351 2018-01-25 09:26:14Z dmb $
0074 %
0075 %   VOICEBOX is a MATLAB toolbox for speech processing.
0076 %   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
0077 %
0078 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0079 %   This program is free software; you can redistribute it and/or modify
0080 %   it under the terms of the GNU General Public License as published by
0081 %   the Free Software Foundation; either version 2 of the License, or
0082 %   (at your option) any later version.
0083 %
0084 %   This program is distributed in the hope that it will be useful,
0085 %   but WITHOUT ANY WARRANTY; without even the implied warranty of
0086 %   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0087 %   GNU General Public License for more details.
0088 %
0089 %   You can obtain a copy of the GNU General Public License from
0090 %   http://www.gnu.org/copyleft/gpl.html or by writing to
0091 %   Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA.
0092 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0093 
0094 % Bugs/suggestions:
0095 
0096 
0097 if nargin<1
0098     error('Usage: [y,fs,wmode,fidx]=READWAV(filename,mode,nmax,nskip)'); end
0099 if nargin<2
0100     mode='p';
0101 else
0102     mode = [mode(:).' 'p'];
0103 end
0104 k=find((mode>='p') & (mode<='s'));
0105 mno=all(mode~='o');                      % scale to input limits not output limits
0106 sc=mode(k(1));
0107 z=128*all(mode~='z'); % data offset value
0108 info=zeros(1,13);
0109 if ischar(filename)
0110     if any(mode=='d')
0111         filename=fullfile(voicebox('dir_data'),filename);
0112     end
0113     fid=fopen(filename,'rb','l');
0114     if fid == -1
0115         fn=[filename,'.wav'];
0116         fid=fopen(fn,'rb','l');
0117         if fid ~= -1
0118             filename=fn;
0119         end
0120     end
0121     if fid == -1
0122         error('Can''t open %s for input',filename);
0123     end
0124     info(1)=fid;
0125 else                                % first argument is FIDX from previous call
0126     info=filename;
0127     fid=info(1);
0128 end
0129 getdat= nargout>0 || any(lower(mode)=='w') || any(lower(mode)=='a');
0130 mh=any(mode=='h') || ~getdat;
0131 if ~info(3)
0132     fseek(fid,8,-1);                        % read riff chunk
0133     header=fread(fid,4,'*char')';
0134     if ~strcmp(header,'WAVE')
0135         fclose(fid);
0136         error('File does not begin with a WAVE chunck');
0137     end
0138     if mh
0139         fprintf('\nWAVE file: %s\n',filename);
0140     end
0141     fmtlen=-1;
0142     datalen=-1;
0143     instlen=-1;
0144     info(13)=-1;
0145     info(12)='e';  % default is original wave file format
0146     while datalen<0                        % loop until FMT and DATA chuncks both found
0147         header=fread(fid,4,'*char');
0148         len=fread(fid,1,'ulong');
0149         if mh
0150             fprintf('  %s chunk: %d bytes\n',header,len);
0151         end
0152         if strcmp(header','fmt ')                    % ******* found FMT chunk *********
0153             fmtlen=len;                             % remember the length
0154             if len>16
0155                 info(12)='x';  % might be WAVEFORMATEX format
0156             end
0157             wavfmt=fread(fid,1,'short');            % format: 1=PCM, 6=A-law, 7-Mu-law
0158             info(8)=wavfmt;
0159             info(5)=fread(fid,1,'ushort');            % number of channels
0160             fs=fread(fid,1,'ulong');                % sample rate in Hz
0161             info(9)=fs;                             % sample rate in Hz
0162             rate=fread(fid,1,'ulong');                % average bytes per second (ignore)
0163             align=fread(fid,1,'ushort');            % block alignment in bytes (container size * #channels)
0164             bps=fread(fid,1,'ushort');            % bits per sample
0165             info(7)=bps;
0166             %             info(6)=ceil(info(7)/8);                % round up to a byte count
0167             info(6)=floor(align/info(5));                       % assume block size/channels = container size
0168             if info(8)==-2   % wave format extensible
0169                 cb=fread(fid,1,'ushort');            % extra bytes must be >=22
0170                 info(12)='X';                         % WAVEFORMATEXTENSIBLE format
0171                 wfxsamp=fread(fid,1,'ushort');            % samples union
0172                 if wfxsamp>0
0173                     info(7)=wfxsamp;     % valid bits per sample
0174                 end
0175                 info(10)=fread(fid,1,'ulong');                % channel mask
0176                 wfxguida=fread(fid,1,'ulong');                % GUID
0177                 wfxguidb=fread(fid,2,'ushort');                % GUID
0178                 wfxguidc=fread(fid,8,'uchar');                % GUID
0179                 if wfxguida<65536
0180                     info(8)=wfxguida; % turn it into normal wav format
0181                 end
0182                 fseek(fid,len-40,0);                    % skip to end of header
0183             else
0184                 if align>0 && align<(info(6)+4)*info(5)
0185                     info(6)=ceil(align/info(5));
0186                 end
0187                 fseek(fid,len-16,0);                    % skip to end of header
0188             end
0189             if mh
0190                 fmttypes={'?' 'PCM' 'ADPCM' 'IEEE-float' '?' '?' 'A-law' '-law' '?'};
0191                 fprintf('        Format: %d = %s',info(8),fmttypes{1+max(min(info(8),8),0)});
0192                 if wavfmt==-2
0193                     fprintf(' (%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x)\n',wfxguida,wfxguidb,wfxguidc);
0194                 else
0195                     fprintf('\n');
0196                 end
0197                 fprintf('        %d channels at %g kHz sample rate (%d kbytes/s)\n',info(5),fs/1000,rate/1000);
0198                 fprintf('        Mask=%x:',info(10));
0199                 spkpos={'FL' 'FR' 'FC' 'W' 'BL' 'BR' 'FLC' 'FRC' 'BC' 'SL' 'SR' 'TC' 'TFL' 'TFC' 'TFR' 'TBL' 'TBC' 'TBR'};
0200                 for i=1:18
0201                     if mod(floor(info(10)*pow2(1-i)),2)
0202                         fprintf([' ' spkpos{i}]);
0203                     end
0204                 end
0205                 fprintf('\n        %d valid bits of %d per sample (%d byte block size)\n',info(7),bps,align);
0206             end
0207         elseif strcmp(header','fact')                % ******* found FACT chunk *********
0208             info(13)=len;
0209             if len<4
0210                 error('FACT chunk too short');
0211             end
0212             nsamp=fread(fid,1,'ulong');                % number of samples
0213             fseek(fid,len-4,0);                     % skip to end of header
0214             if mh
0215                 fprintf('        %d samples = %.3g seconds\n',nsamp,nsamp/fs);
0216             end
0217         elseif strcmp(header','inst')                % ******* found INST chunk *********
0218             instlen=len;
0219             if len<7
0220                 error('INST chunk too short');
0221             end
0222             inst=fread(fid,3,'schar');
0223             info(11)=double(inst(3));                          % gain in dB
0224             if mh
0225                 fprintf('        Gain = %d dB\n',info(11));
0226             end
0227             fseek(fid,len-3,0);                     % skip to end of header
0228         elseif strcmp(header','data')                % ******* found DATA chunk *********
0229             if fmtlen<0
0230                 fclose(fid);
0231                 error('File %s does not contain a FMT chunck',filename);
0232             end
0233             if info(13)>3 && nsamp >0
0234                 info(4)=nsamp;   % take data length from FACT chunk
0235             else
0236                 info(4) = fix(len/(info(6)*info(5)));  % number of samples
0237             end
0238             info(3)=ftell(fid);                    % start of data
0239             datalen=len;
0240             if mh
0241                 fprintf('        %d samples x %d channels x %d bytes/samp',info(4:6));
0242                 if prod(info(4:6))~=len
0243                     fprintf(' + %d padding bytes',len-prod(info(4:6)));
0244                 end
0245                 fprintf(' = %g sec\n',info(4)/fs);
0246             end
0247         else                            % ******* found unwanted chunk *********
0248             fseek(fid,len,0);
0249         end
0250     end
0251 else
0252     fs=info(9);
0253 end
0254 if nargin<4 || nskip<0
0255     nskip=info(2);  % resume at current file position
0256 end
0257 
0258 ksamples=info(4)-nskip; % number of samples remaining
0259 if nargin>2
0260     if nmax>=0
0261         ksamples=min(nmax,ksamples); % number of samples to read
0262     end
0263 elseif ~getdat 
0264     ksamples=min(5,ksamples); % just read 5 samples so we can print the first few data values
0265 end
0266 if ksamples>0
0267     info(2)=nskip+ksamples;
0268     fseek(fid,info(3)+info(6)*info(5)*nskip,-1);
0269     nsamples=info(5)*ksamples;
0270     if any(info(8)==3)  % floating point format
0271         pk=1;  % peak is 1
0272         switch info(6)
0273             case 4
0274                 y=fread(fid,nsamples,'float32');
0275             case 8
0276                 y=fread(fid,nsamples,'float64');
0277             otherwise
0278                 error('cannot read %d-byte floating point numbers',info(6));
0279         end
0280     else
0281         if ~any(info(8)==[1 6 7])
0282             sc='r';  % read strange formats in raw integer mode
0283         end
0284         pk=pow2(0.5,8*info(6))*(1+(mno/2-all(mode~='n'))/pow2(0.5,info(7)));  % use modes o and n to determine effective peak
0285         switch info(6)
0286             case 1
0287                 y=fread(fid,nsamples,'uchar');
0288                 if info(8)==1
0289                     y=y-z;
0290                 elseif info(8)==6
0291                     y=pcma2lin(y,213,1);
0292                     pk=4032+mno*64;
0293                 elseif info(8)==7
0294                     y=pcmu2lin(y,1);
0295                     pk=8031+mno*128;
0296                 end
0297             case 2
0298                 y=fread(fid,nsamples,'short');
0299             case 3
0300                 y=fread(fid,3*nsamples,'uchar');
0301                 y=reshape(y,3,nsamples);
0302                 y=([1 256 65536]*y-pow2(fix(pow2(y(3,:),-7)),24)).';
0303             case 4
0304                 y=fread(fid,nsamples,'long');
0305             otherwise
0306                 error('cannot read %d-byte integers',info(6));
0307         end
0308     end
0309     if sc ~= 'r'
0310         if sc=='s'
0311             sf=1/max(abs(y(:)));
0312         elseif sc=='p'
0313             sf=1/pk;
0314         else
0315             if info(8)==7
0316                 sf=2.03761563/pk;
0317             else
0318                 sf=2.03033976/pk;
0319             end
0320         end
0321         y=sf*y;
0322     else                             % mode = 'r' - output raw values
0323         if info(8)==1
0324             y=y*pow2(1,info(7)-8*info(6));  % shift to get the bits correct
0325         end
0326     end
0327     if any(mode=='g') && info(11)~=0
0328         y=y*10^(info(11)/20);   % scale by the gain
0329     end
0330     if info(5)>1
0331         y = reshape(y,info(5),ksamples).';
0332     end
0333 else
0334     y=[];
0335 end
0336 if all(mode~='f')
0337     fclose(fid);
0338 end
0339 if nargout>2  % sort out the mode input for writing this format
0340     wmode=char([info(12) sc 'z'-z/128]);
0341     if info(13)>0
0342         wmode=[wmode 'E'];
0343     end
0344     if info(6)>1 && info(6)<5
0345         cszc=' cCL';
0346         wmode=[wmode cszc(info(6))];
0347     end
0348     switch info(8)
0349         case 1                                    % PCM modes
0350             if ~mno
0351                 wmode=[wmode 'o'];
0352             end
0353             if any(mode=='n')
0354                 wmode=[wmode 'n'];
0355             end
0356             wmode=[wmode num2str(info(7))];
0357         case 3
0358             if info(7)<=32
0359                 wmode = [wmode 'v'];
0360             else
0361                 wmode = [wmode 'V'];
0362             end
0363         case 6
0364             wmode = [wmode 'a'];
0365         case 7
0366             wmode = [wmode 'u'];
0367     end
0368     fidx=info;
0369 end
0370 [ns,nchan]=size(y);
0371 if mh && ns>0
0372     nsh=min(ns,5);  % print first few samples
0373     for i=1:nsh
0374         fprintf('        %d:',i);
0375         fprintf(' %.3g',y(i,:));
0376         fprintf('\n');
0377     end
0378 end
0379 
0380 if ns>0.01*fs
0381     if any(lower(mode)=='a')
0382         nsh=min(ns,10*fs+ns*any(mode=='A'));
0383         soundsc(y(1:nsh,1:min(nchan,2)),fs);
0384     end
0385     if any(mode=='W')
0386         spm='pJcbf ';
0387         if any(mode=='w')
0388             spm(end)='w';
0389         end
0390         clf;
0391         if nchan>1
0392             for i=nchan:-1:1
0393                 subplot(nchan,1,i)
0394                 spgrambw(y(:,i),fs,spm);
0395             end
0396         else
0397             spgrambw(y,fs,spm);
0398         end
0399     elseif any(mode=='w')
0400         clf;
0401         if nchan>1
0402             for i=nchan:-1:1
0403                 subplot(nchan,1,i)
0404                 plot((1:ns)/fs,y(:,i));
0405                 ylabel(['Chan ' num2str(i)]);
0406                 if i==nchan
0407                     xlabel('Time (s)');
0408                 end
0409             end
0410         else
0411             plot((1:ns)/fs,y);
0412             xlabel('Time (s)');
0413         end
0414 
0415     end
0416 end
0417 
0418 
0419 
0420

Generated on Mon 06-Aug-2018 14:48:32 by m2html © 2003