V_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 "v_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: v_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.
0001 function [y,fs,wmode,fidx]=v_readwav(filename,mode,nmax,nskip) 0002 %V_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 "v_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: v_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: v_readwav.m 10865 2018-09-21 17:22:45Z 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) || isstring(filename) 0110 if any(mode=='d') 0111 filename=fullfile(v_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' 'Mu-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=v_pcma2lin(y,213,1); 0292 pk=4032+mno*64; 0293 elseif info(8)==7 0294 y=v_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 v_spgrambw(y(:,i),fs,spm); 0395 end 0396 else 0397 v_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