# v_readaif

## PURPOSE

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

## SYNOPSIS

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

## DESCRIPTION

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

     Input Parameters:

        FILENAME gives the name of the file (with optional .AIF extension) or alternatively
                     can be the FIDX output from a previous call to READAIF
        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)
       File I/O: 'f'    Do not close file on exit
                 'd'    Look in data directory: v_voicebox('dir_data')

        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 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, 6=A-law, 7=Mu-law (always 1 for AIFF)
               (9)  fs    sample frequency
               (10) offset
               (11) block size

       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

## CROSS-REFERENCE INFORMATION

This function calls:

- v_voicebox V_VOICEBOX set global parameters for Voicebox functions Y=(FIELD,VAL)

This function is called by:

## SOURCE CODE

    0001 function [y,fs,wmode,fidx]=v_readaif(filename,mode,nmax,nskip)
    0002 %V_READAIF  Read a .AIF 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 .AIF extension) or alternatively
    0007 %                 can be the FIDX output from a previous call to READAIF
    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 %   File I/O: 'f'    Do not close file on exit
    0019 %             'd'    Look in data directory: v_voicebox('dir_data')
    0020 %
    0021 %    NMAX     maximum number of samples to read (or -1 for unlimited [default])
    0022 %    NSKIP    number of samples to skip from start of file
    0023 %               (or -1 to continue from previous read when FIDX is given instead of FILENAME [default])
    0024 %
    0025 % Output Parameters:
    0026 %
    0027 %    Y        data matrix of dimension (samples,channels)
    0028 %    FS       sample frequency in Hz
    0029 %    WMODE    mode string needed to recreate the data file
    0030 %    FIDX     Information row vector containing the element listed below.
    0031 %
    0032 %           (1)  file id
    0033 %                (2)  current position in file
    0034 %           (3)  dataoff    byte offset in file to start of data
    0035 %           (4)  nsamp    number of samples
    0036 %           (5)  nchan    number of channels
    0037 %           (6)  nbyte    bytes per data value
    0038 %           (7)  bits    number of bits of precision
    0039 %           (8)  code    Data format: 1=PCM, 2=ADPCM, 6=A-law, 7=Mu-law (always 1 for AIFF)
    0040 %           (9)  fs    sample frequency
    0041 %           (10) offset
    0042 %           (11) block size
    0043 %
    0044 %   If no output parameters are specified, header information will be printed.
    0045 %
    0046 %   For stereo data, y(:,1) is the left channel and y(:,2) the right
    0047
    0048 %  future enhancements: (1) handle LIST and CAT files as well
    0049 %                       (2) deal with offset and blocksize properly
    0050 %                       (3) handle other chunk types sensibly
    0051
    0052 %       Copyright (C) Mike Brookes 1998
    0053 %      Version: $Id: v_readaif.m 10865 2018-09-21 17:22:45Z dmb $
    0054 %
    0055 %   VOICEBOX is a MATLAB toolbox for speech processing.
    0056 %   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
    0057 %
    0058 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    0059 %   This program is free software; you can redistribute it and/or modify
    0060 %   it under the terms of the GNU Lesser General Public License as published by
    0061 %   the Free Software Foundation; either version 3 of the License, or
    0062 %   (at your option) any later version.
    0063 %
    0064 %   This program is distributed in the hope that it will be useful,
    0065 %   but WITHOUT ANY WARRANTY; without even the implied warranty of
    0066 %   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    0067 %   GNU Lesser General Public License for more details.
    0068 %
    0069 %   You can obtain a copy of the GNU Lesser General Public License from
    0070 %   https://www.gnu.org/licenses/ .
    0071 %
    0072 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    0073
    0074 if nargin<1 error('Usage: [y,fs,wmode,fidx]=READAIFF(filename,mode,nmax,nskip)'); end
    0075
    0076 if nargin<2 mode='p';
    0077 else mode = [mode(:).' 'p'];
    0078 end
    0079 k=find((mode>='p') & (mode<='s'));
    0080 mno=all(mode~='o');                      % scale to input limits not output limits
    0081 sc=mode(k(1));
    0082
    0083
    0084 info=zeros(1,11);
    0085 if ischar(filename)
    0086     if any(mode=='d')
    0087         filename=fullfile(v_voicebox('dir_data'),filename);
    0088     end
    0089     fid=fopen(filename,'rb','b');
    0090     if fid == -1
    0091         fn=[filename,'.aif'];
    0092         fid=fopen(fn,'rb','b');
    0093         if fid ~= -1 filename=fn; end
    0094     end
    0095     if fid == -1 error(sprintf('Can''t open %s for input',filename)); end
    0096     info(1)=fid;
    0097 else
    0098     info=filename;
    0099     fid=info(1);
    0100 end
    0101
    0102 if ~info(3)
    0103     fseek(fid,0,-1);                        % read file header
    0104     header=fread(fid,4,'uchar');
    0105     if header' ~= 'FORM' fclose(fid); error(sprintf('File %s does not begin with a FORM group ID',filename)); end
    0106     filen=fread(fid,1,'ulong')-4;
    0107     header=fread(fid,4,'uchar');
    0108     if header' ~= 'AIFF' fclose(fid); error(sprintf('File %s does not begin with a AIFF type ID',filename)); end
    0109
    0110
    0111     fmt=0;
    0112     data=0;
    0113     while filen>=8                        % loop to read all chunks
    0114         header=fread(fid,4,'char');
    0115         len=fread(fid,1,'ulong');
    0116         lenx=len+rem(len,2);    % round up to an even number
    0117         filen=filen-lenx-8;
    0118         %fprintf(1,'%s chunk, %d bytes, %d bytes remaining\n',char(header'),len,filen);
    0119         if header' == 'COMM'                    % ******* found COMM chunk *********
    0120             fmt=1;
    0121             info(5)=fread(fid,1,'ushort');            %number of channels
    0122             info(4)=fread(fid,1,'ulong');            %number of samples
    0123             info(7)=fread(fid,1,'ushort');                % bits per sample
    0124             info(6)=ceil(info(7)/8);            % bytes per sample
    0125             info(8)=1;
    0126             ieeex=fread(fid,5,'ushort');               % read a 10-byte extended ieee format number
    0127             fsign=ieeex(1)>32767;
    0128             ieeex(1)=ieeex(1)-32768*fsign;
    0129             if ~ieeex info(9)=0;
    0130             elseif ieeex(1)==32767 info(9)=nan;
    0131             else
    0132                 info(9)=(1-2*fsign)*sum(pow2(ieeex(2:5)',ieeex(1)-(16398:16:16446)));
    0133             end
    0134             fseek(fid,lenx-18,0);                % skip to end of header
    0135         elseif header' == 'SSND'                % ******* found DATA chunk *********
    0136             info(10)=fread(fid,1,'ulong');            %number of channels
    0137             info(11)=fread(fid,1,'ulong');            %number of channels
    0138             info(3)=ftell(fid);
    0139             data=1;
    0140             fseek(fid,lenx-8,0);                % skip to end of chunk
    0141         else                            % ******* found unwanted chunk *********
    0142             fseek(fid,lenx,0);
    0143         end
    0144     end
    0145     if filen~=0
    0146         fprintf(2,'READAIF warning: Inconsistent file length - %d extra bytes\n',filen);
    0147     end
    0148 end
    0149 fs=info(9);
    0150 if ~fmt | ~data fclose(fid); error(sprintf('File %s does not contain COMM and SSND chunks',filename)); end
    0151
    0152
    0153 if nargin<4 nskip=info(2);
    0154 elseif nskip<0 nskip=info(2);
    0155 end
    0156
    0157 ksamples=info(4)-nskip;
    0158 if nargin>2
    0159     if nmax>=0
    0160         ksamples=min(nmax,ksamples);
    0161     end
    0162 elseif ~nargout
    0163     ksamples=min(5,ksamples);
    0164 end
    0165 if ksamples>0
    0166     info(2)=nskip+ksamples;
    0167     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
    0168     fseek(fid,info(3)+info(6)*info(5)*nskip,-1);
    0169     nsamples=info(5)*ksamples;
    0170     if info(6)<3
    0171         if info(6)<2
    0172             y=fread(fid,nsamples,'schar');
    0173         else
    0174             y=fread(fid,nsamples,'short');
    0175         end
    0176     else
    0177         if info(6)<4
    0178             y=fread(fid,3*nsamples,'uchar');
    0179             y=reshape(y,3,nsamples);
    0180             y=[1 256 65536]*y-pow2(fix(pow2(y(3,:),-7)),24);
    0181         else
    0182             y=fread(fid,nsamples,'long');
    0183         end
    0184     end
    0185     if sc ~= 'r'
    0186         if sc=='s' sf=1/max(max(abs(y)),1);
    0187         elseif sc=='p' sf=1/pk;
    0188         else   sf=2.03033976/pk;
    0189         end
    0190         y=sf*y;
    0191     else
    0192         y=y*pow2(1,info(7)-8*info(6)); % shift to get the data into the LSB end
    0193     end
    0194
    0195     if info(5)>1 y = reshape(y,info(5),ksamples).'; end
    0196 else
    0197     y=[];
    0198 end
    0199
    0200 if all(mode~='f') fclose(fid); end
    0201
    0202 if nargout>2
    0203     if ~mno wmode=[wmode 'o']; end
    0204     if any(mode=='n') wmode=[wmode 'n']; end
    0205     wmode=[sc num2str(info(7))];
    0206     fidx=info;
    0207 elseif ~nargout
    0208     fprintf(1,'\n%d Hz sample rate\n%d channel x %d samples x %d bit = %.3g seconds\n',info([9 5 4]), info(7),info(4)/info(9));
    0209 end
    0210
    0211
    0212