annotate toolboxes/MIRtoolbox1.3.2/MIRToolbox/aiffread.m @ 0:e9a9cd732c1e tip

first hg version after svn
author wolffd
date Tue, 10 Feb 2015 15:05:51 +0000
parents
children
rev   line source
wolffd@0 1 function [data,Fs,nBits,formChunk] = aiffread(filePath,indexRange)
wolffd@0 2 %AIFFREAD Read AIFF (Audio Interchange File Format) sound file.
wolffd@0 3 % Y = AIFFREAD(FILE) reads an AIFF file specified by the string FILE,
wolffd@0 4 % returning the sampled data in Y. The ".aif" extension is appended if no
wolffd@0 5 % extension is given.
wolffd@0 6 %
wolffd@0 7 % [Y,FS,NBITS,CHUNKDATA] = AIFFREAD(FILE) returns the sample rate (FS) in
wolffd@0 8 % Hertz, the number of bits per sample (NBITS) used to encode the data in
wolffd@0 9 % the file, and a complete structure of the chunk data (CHUNKDATA)
wolffd@0 10 % contained in the AIFF file (minus the actual audio data returned in Y).
wolffd@0 11 % See below for a description of CHUNKDATA.
wolffd@0 12 %
wolffd@0 13 % [...] = AIFFREAD(FILE,N) returns only the first N samples from each
wolffd@0 14 % channel in the file.
wolffd@0 15 %
wolffd@0 16 % [...] = AIFFREAD(FILE,[N1 N2]) returns only samples N1 through N2 from
wolffd@0 17 % each channel in the file.
wolffd@0 18 %
wolffd@0 19 % [SIZ,...] = AIFFREAD(FILE,'size') returns the size of the audio data
wolffd@0 20 % contained in the file in place of the actual audio data, where
wolffd@0 21 % SIZ = [nSampleFrames nChannels].
wolffd@0 22 %
wolffd@0 23 %-NOTES--------------------------------------------------------------------
wolffd@0 24 %
wolffd@0 25 % A note on compressed files:
wolffd@0 26 %
wolffd@0 27 % Both AIFF and AIFC/AIFF-C (compressed) file types can be read by
wolffd@0 28 % AIFFREAD, but the data returned for AIFC/AIFF-C files will be the
wolffd@0 29 % raw, compressed data (i.e. AIFFREAD loads the data from the file
wolffd@0 30 % without modification). Currently, since there are many compression
wolffd@0 31 % formats, it is the responsibility of the user to uncompress the
wolffd@0 32 % sound data using parameters defined in the COMM chunk (contained in
wolffd@0 33 % the returned CHUNKDATA structure). When loading AIFC/AIFF-C files,
wolffd@0 34 % any optional numerical subranges are ignored and the entire set of
wolffd@0 35 % compressed data is returned as a column vector of signed bytes
wolffd@0 36 % (INT8 type).
wolffd@0 37 %
wolffd@0 38 % A note on the CHUNKDATA structure:
wolffd@0 39 %
wolffd@0 40 % The CHUNKDATA structure has the following fields:
wolffd@0 41 %
wolffd@0 42 % -'chunkID': The 4-character ID for the chunk. This will always be
wolffd@0 43 % the string 'FORM'.
wolffd@0 44 % -'chunkSize': The size (in bytes) of the remaining data in the
wolffd@0 45 % file.
wolffd@0 46 % -'formType': A 4-character string for the file type that should
wolffd@0 47 % be either 'AIFF' or 'AIFC'.
wolffd@0 48 % -'chunkArray': An array of structures, one entry for every chunk
wolffd@0 49 % that is in the file (not counting this parent FORM
wolffd@0 50 % chunk). The fields of this structure are:
wolffd@0 51 % -'chunkID': The 4-character ID for the chunk.
wolffd@0 52 % -'chunkSize': The size (in bytes) of the
wolffd@0 53 % remaining data in the chunk.
wolffd@0 54 % -'chunkData': A structure of data for the
wolffd@0 55 % chunk. The form of this data for
wolffd@0 56 % a given chunkID can be found at
wolffd@0 57 % the links given below for the
wolffd@0 58 % file format standards.
wolffd@0 59 %
wolffd@0 60 % The data portion of certain chunks may not have a clearly defined
wolffd@0 61 % format, or that format may be dependent on the implementation or
wolffd@0 62 % application that will be using the data. In such cases, the data
wolffd@0 63 % returned for that chunk in the CHUNKDATA structure will be in a raw
wolffd@0 64 % format (vectors of signed or unsigned 8-bit integers) and it will be
wolffd@0 65 % up to the user/application to parse and format this data correctly.
wolffd@0 66 % The following is a list of such AIFF/AIFF-C chunks:
wolffd@0 67 %
wolffd@0 68 % -Audio Recording Chunk (chunkID = 'AESD'): The chunkData
wolffd@0 69 % structure has one field 'aesChannelStatusData' that stores a
wolffd@0 70 % column vector of 24 8-bit unsigned integers.
wolffd@0 71 % -Application Specific Chunk (chunkID = 'APPL'): The chunkData
wolffd@0 72 % structure has two fields. 'applicationSignature' stores a
wolffd@0 73 % 4-character string identifying the application. 'data' stores a
wolffd@0 74 % column vector of 8-bit signed integers.
wolffd@0 75 % -MIDI Data Chunk (chunkID = 'MIDI'): The chunkData structure has
wolffd@0 76 % one field 'midiData' that stores a column vector of 8-bit
wolffd@0 77 % unsigned integers.
wolffd@0 78 % -Sound Accelerator (SAXEL) Chunk (chunkID = 'SAXL'): There is no
wolffd@0 79 % finalized format for Saxel chunks, so the chunkData structure
wolffd@0 80 % follows the draft format given in Appendix D of the AIFF-C
wolffd@0 81 % standard.
wolffd@0 82 %
wolffd@0 83 % Description for the AIFF standard can be found here:
wolffd@0 84 %
wolffd@0 85 % http://muratnkonar.com/aiff/index.html
wolffd@0 86 %
wolffd@0 87 % Descriptions for the AIFC/AIFF-C standard can be found here:
wolffd@0 88 %
wolffd@0 89 % http://www.cnpbagwell.com/aiff-c.txt
wolffd@0 90 % http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/AIFF/Docs/...
wolffd@0 91 % AIFF-C.9.26.91.pdf
wolffd@0 92
wolffd@0 93 % Author: Ken Eaton
wolffd@0 94 % Last modified: 3/17/09
wolffd@0 95 %--------------------------------------------------------------------------
wolffd@0 96
wolffd@0 97 % Initializations:
wolffd@0 98
wolffd@0 99 aiffChunkPrecedence = {'COMM' 'SSND' 'MARK' 'INST' 'COMT' 'NAME' ...
wolffd@0 100 'AUTH' '[c] ' 'ANNO' 'AESD' 'MIDI' 'APPL'};
wolffd@0 101 aiffChunkLimits = [1 1 1 1 1 1 1 1 inf 1 inf inf];
wolffd@0 102 aifcChunkPrecedence = {'FVER' 'COMM' 'INST' 'SAXL' 'COMT' 'MARK' ...
wolffd@0 103 'SSND' 'NAME' 'AUTH' '[c] ' 'ANNO' 'AESD' ...
wolffd@0 104 'MIDI' 'APPL'};
wolffd@0 105 aifcChunkLimits = [1 1 1 inf 1 1 1 1 1 1 inf 1 inf inf];
wolffd@0 106 fid = -1;
wolffd@0 107
wolffd@0 108 % Check the number of input arguments:
wolffd@0 109
wolffd@0 110 switch nargin,
wolffd@0 111 case 0,
wolffd@0 112 error(error_message('notEnoughInputs'));
wolffd@0 113 case 1,
wolffd@0 114 indexRange = [1 inf];
wolffd@0 115 end
wolffd@0 116
wolffd@0 117 % Check the file name input argument:
wolffd@0 118
wolffd@0 119 if ~ischar(filePath),
wolffd@0 120 error(error_message('badArgumentType','File name','char'));
wolffd@0 121 end
wolffd@0 122 [filePath,fileName,fileExtension] = fileparts(filePath);
wolffd@0 123 if isempty(fileExtension),
wolffd@0 124 fileExtension = '.aif';
wolffd@0 125 end
wolffd@0 126 if ~any(strcmpi(fileExtension,{'.aif' '.afc' '.aiff' '.aifc'})),
wolffd@0 127 error(error_message('unknownExtension',fileExtension));
wolffd@0 128 end
wolffd@0 129
wolffd@0 130 % Check the optional input argument:
wolffd@0 131
wolffd@0 132 if isnumeric(indexRange), % Numeric range specification
wolffd@0 133
wolffd@0 134 indexRange = double(indexRange);
wolffd@0 135 nRange = numel(indexRange);
wolffd@0 136 if (nRange > 2) || any(indexRange < 1) || any(isnan(indexRange)),
wolffd@0 137 error(error_message('badIndexValue'));
wolffd@0 138 end
wolffd@0 139 indexRange = [ones(nRange ~= 2) round(indexRange) inf(nRange == 0)];
wolffd@0 140
wolffd@0 141 elseif ischar(indexRange), % Specification for returning just the size
wolffd@0 142
wolffd@0 143 if ~strncmpi(indexRange,'size',numel(indexRange)),
wolffd@0 144 error(error_message('invalidString'));
wolffd@0 145 end
wolffd@0 146 indexRange = [];
wolffd@0 147
wolffd@0 148 else % Invalid input
wolffd@0 149
wolffd@0 150 error(error_message('badArgumentType','Optional argument',...
wolffd@0 151 'numeric or char'));
wolffd@0 152
wolffd@0 153 end
wolffd@0 154
wolffd@0 155 % Check that the file exists and can be opened:
wolffd@0 156
wolffd@0 157 fid = fopen(fullfile(filePath,[fileName fileExtension]),'r','b');
wolffd@0 158 if fid == -1,
wolffd@0 159 error(error_message('invalidFile',[fileName fileExtension]));
wolffd@0 160 end
wolffd@0 161
wolffd@0 162 % Initialize formChunk structure:
wolffd@0 163
wolffd@0 164 formChunk = struct('chunkID',[],'chunkSize',[],'formType',[],...
wolffd@0 165 'chunkArray',[]);
wolffd@0 166
wolffd@0 167 % Read FORM chunk data:
wolffd@0 168
wolffd@0 169 formChunk.chunkID = read_text(fid,4);
wolffd@0 170 if ~strcmp(formChunk.chunkID,'FORM'),
wolffd@0 171 error(error_message('invalidFileFormat',fileExtension));
wolffd@0 172 end
wolffd@0 173 formChunk.chunkSize = fread(fid,1,'int32');
wolffd@0 174 formType = read_text(fid,4);
wolffd@0 175 if ~any(strcmp(formType,{'AIFF' 'AIFC'})),
wolffd@0 176 error(error_message('invalidFileFormat',fileExtension));
wolffd@0 177 end
wolffd@0 178 formChunk.formType = formType;
wolffd@0 179
wolffd@0 180 % Since the order of chunks is not guaranteed, first skip through the
wolffd@0 181 % file and read just the chunkIDs and chunkSizes:
wolffd@0 182
wolffd@0 183 iChunk = 0;
wolffd@0 184 chunkIDArray = {};
wolffd@0 185 chunkSizeArray = {};
wolffd@0 186 chunkDataIndex = [];
wolffd@0 187 nextChunkID = read_text(fid,4);
wolffd@0 188 while ~feof(fid),
wolffd@0 189 iChunk = iChunk+1;
wolffd@0 190 chunkIDArray{iChunk} = nextChunkID;
wolffd@0 191 chunkSize = fread(fid,1,'int32');
wolffd@0 192 chunkSizeArray{iChunk} = chunkSize;
wolffd@0 193 chunkDataIndex(iChunk) = ftell(fid);
wolffd@0 194 fseek(fid,chunkSize+rem(chunkSize,2),'cof');
wolffd@0 195 nextChunkID = read_text(fid,4);
wolffd@0 196 end
wolffd@0 197
wolffd@0 198 % Check for the presence of required chunks:
wolffd@0 199
wolffd@0 200 if ~ismember('COMM',chunkIDArray),
wolffd@0 201 error(error_message('missingChunk','COMM',formType));
wolffd@0 202 end
wolffd@0 203 if strcmp(formType,'AIFC') && ~ismember('FVER',chunkIDArray),
wolffd@0 204 error(error_message('missingChunk','FVER',formType));
wolffd@0 205 end
wolffd@0 206
wolffd@0 207 % Check for unknown chunks and order chunks based on chunk precedence:
wolffd@0 208
wolffd@0 209 if strcmp(formType,'AIFF'),
wolffd@0 210 [isChunk,orderIndex] = ismember(chunkIDArray,aiffChunkPrecedence);
wolffd@0 211 else
wolffd@0 212 [isChunk,orderIndex] = ismember(chunkIDArray,aifcChunkPrecedence);
wolffd@0 213 end
wolffd@0 214 if ~all(isChunk),
wolffd@0 215 unknownChunks = [chunkIDArray(~isChunk); ...
wolffd@0 216 repmat({', '},1,sum(~isChunk)-1) {'.'}];
wolffd@0 217 orderIndex = orderIndex(isChunk);
wolffd@0 218 chunkIDArray = chunkIDArray(isChunk);
wolffd@0 219 chunkSizeArray = chunkSizeArray(isChunk);
wolffd@0 220 chunkDataIndex = chunkDataIndex(isChunk);
wolffd@0 221 warning('aiffread:unknownChunk',...
wolffd@0 222 ['The following chunk IDs are unknown for an ' formType ...
wolffd@0 223 ' file and will be ignored: ' unknownChunks{:}]);
wolffd@0 224 end
wolffd@0 225 [index,orderIndex] = sort(orderIndex);
wolffd@0 226 chunkIDArray = chunkIDArray(orderIndex);
wolffd@0 227 chunkSizeArray = chunkSizeArray(orderIndex);
wolffd@0 228 chunkDataIndex = chunkDataIndex(orderIndex);
wolffd@0 229
wolffd@0 230 % Check for chunks that should not appear more than once:
wolffd@0 231
wolffd@0 232 index = unique(index(diff(index) < 1));
wolffd@0 233 if strcmp(formType,'AIFF'),
wolffd@0 234 repeatChunks = aiffChunkPrecedence(aiffChunkLimits(index) == 1);
wolffd@0 235 else
wolffd@0 236 repeatChunks = aifcChunkPrecedence(aifcChunkLimits(index) == 1);
wolffd@0 237 end
wolffd@0 238 if ~isempty(repeatChunks),
wolffd@0 239 repeatChunks = [repeatChunks; ...
wolffd@0 240 repmat({', '},1,numel(repeatChunks)-1) {'.'}];
wolffd@0 241 error(error_message('repeatChunk',formType,[repeatChunks{:}]));
wolffd@0 242 end
wolffd@0 243
wolffd@0 244 % Initialize chunkArray data:
wolffd@0 245
wolffd@0 246 formChunk.chunkArray = struct('chunkID',chunkIDArray,...
wolffd@0 247 'chunkSize',chunkSizeArray,...
wolffd@0 248 'chunkData',[]);
wolffd@0 249
wolffd@0 250 % Read the data for each chunk:
wolffd@0 251
wolffd@0 252 for iChunk = 1:numel(chunkIDArray),
wolffd@0 253 chunkData = [];
wolffd@0 254 fseek(fid,chunkDataIndex(iChunk),'bof');
wolffd@0 255 switch chunkIDArray{iChunk},
wolffd@0 256
wolffd@0 257 case '[c] ', % Copyright Chunk
wolffd@0 258
wolffd@0 259 chunkData.text = read_text(fid,chunkSizeArray{iChunk});
wolffd@0 260
wolffd@0 261 case 'AESD', % Audio Recording Chunk
wolffd@0 262
wolffd@0 263 chunkData.aesChannelStatusData = ...
wolffd@0 264 fread(fid,[chunkSizeArray{iChunk} 1],'*uint8');
wolffd@0 265
wolffd@0 266 case 'ANNO', % Annotation Chunk
wolffd@0 267
wolffd@0 268 chunkData.text = read_text(fid,chunkSizeArray{iChunk});
wolffd@0 269
wolffd@0 270 case 'APPL', % Application Specific Chunk
wolffd@0 271
wolffd@0 272 chunkData.applicationSignature = read_text(fid,4);
wolffd@0 273 chunkData.data = fread(fid,[chunkSizeArray{iChunk}-4 1],'*int8');
wolffd@0 274
wolffd@0 275 case 'AUTH', % Author Chunk
wolffd@0 276
wolffd@0 277 chunkData.text = read_text(fid,chunkSizeArray{iChunk});
wolffd@0 278
wolffd@0 279 case 'COMM', % Common Chunk
wolffd@0 280
wolffd@0 281 nChannels = fread(fid,1,'int16');
wolffd@0 282 chunkData.nChannels = nChannels;
wolffd@0 283 nSampleFrames = fread(fid,1,'uint32');
wolffd@0 284 if (nSampleFrames > 0) && ~ismember('SSND',chunkIDArray),
wolffd@0 285 error(error_message('missingChunk','SSND',formType));
wolffd@0 286 end
wolffd@0 287 chunkData.nSampleFrames = nSampleFrames;
wolffd@0 288 nBits = fread(fid,1,'int16');
wolffd@0 289 chunkData.sampleSize = nBits;
wolffd@0 290 exponent = fread(fid,1,'uint16');
wolffd@0 291 highMantissa = fread(fid,1,'uint32');
wolffd@0 292 lowMantissa = fread(fid,1,'uint32');
wolffd@0 293 Fs = extended2double(exponent,highMantissa,lowMantissa);
wolffd@0 294 chunkData.sampleRate = Fs;
wolffd@0 295 if strcmp(formType,'AIFF'),
wolffd@0 296 compressionType = 'NONE';
wolffd@0 297 else
wolffd@0 298 compressionType = read_text(fid,4);
wolffd@0 299 chunkData.compressionType = compressionType;
wolffd@0 300 chunkData.compressionName = read_pstring(fid);
wolffd@0 301 end
wolffd@0 302
wolffd@0 303 case 'COMT', % Comments Chunk
wolffd@0 304
wolffd@0 305 nComments = fread(fid,1,'uint16');
wolffd@0 306 chunkData.nComments = nComments;
wolffd@0 307 chunkData.commentArray = struct('timeStamp',cell(nComments,1),...
wolffd@0 308 'marker',[],'count',[],'text',[]);
wolffd@0 309 for iComment = 1:nComments,
wolffd@0 310 chunkData.commentArray(iComment) = read_comment(fid);
wolffd@0 311 end
wolffd@0 312
wolffd@0 313 case 'FVER', % Format Version Chunk (AIFC/AIFF-C only)
wolffd@0 314
wolffd@0 315 timeStamp = fread(fid,1,'uint32');
wolffd@0 316 if timeStamp ~= 2726318400,
wolffd@0 317 warning('aiffread:unknownVersion',...
wolffd@0 318 ['File contains an unrecognized version of the ' ...
wolffd@0 319 'AIFC/AIFF-C standard.']);
wolffd@0 320 end
wolffd@0 321 chunkData.timeStamp = timeStamp;
wolffd@0 322
wolffd@0 323 case 'INST', % Instrument Chunk
wolffd@0 324
wolffd@0 325 chunkData.baseNote = fread(fid,1,'int8');
wolffd@0 326 chunkData.detune = fread(fid,1,'int8');
wolffd@0 327 chunkData.lowNote = fread(fid,1,'int8');
wolffd@0 328 chunkData.highNote = fread(fid,1,'int8');
wolffd@0 329 chunkData.lowVelocity = fread(fid,1,'int8');
wolffd@0 330 chunkData.highVelocity = fread(fid,1,'int8');
wolffd@0 331 chunkData.gain = fread(fid,1,'int16');
wolffd@0 332 chunkData.sustainLoop = read_loop(fid);
wolffd@0 333 chunkData.releaseLoop = read_loop(fid);
wolffd@0 334
wolffd@0 335 case 'MARK', % Marker Chunk
wolffd@0 336
wolffd@0 337 nMarkers = fread(fid,1,'uint16');
wolffd@0 338 chunkData.nMarkers = nMarkers;
wolffd@0 339 chunkData.markerArray = struct('id',cell(nMarkers,1),...
wolffd@0 340 'position',[],'markerName',[]);
wolffd@0 341 for iMarker = 1:nMarkers,
wolffd@0 342 chunkData.markerArray(iMarker) = read_marker(fid);
wolffd@0 343 end
wolffd@0 344 markerIDs = [chunkData.markerArray.id];
wolffd@0 345 if any(markerIDs < 1) || (numel(unique(markerIDs)) < nMarkers),
wolffd@0 346 warning('aiffread:invalidMarkers',...
wolffd@0 347 'Invalid or repeated marker IDs were detected.');
wolffd@0 348 end
wolffd@0 349
wolffd@0 350 case 'MIDI', % MIDI Data Chunk
wolffd@0 351
wolffd@0 352 chunkData.midiData = fread(fid,[chunkSizeArray{iChunk} 1],...
wolffd@0 353 '*uint8');
wolffd@0 354
wolffd@0 355 case 'NAME', % Name Chunk
wolffd@0 356
wolffd@0 357 chunkData.text = read_text(fid,chunkSizeArray{iChunk});
wolffd@0 358
wolffd@0 359 case 'SAXL', % Sound Accelerator (SAXEL) Chunk (AIFC/AIFF-C only)
wolffd@0 360
wolffd@0 361 nSaxels = fread(fid,1,'uint16');
wolffd@0 362 chunkData.nSaxels = nSaxels;
wolffd@0 363 chunkData.saxelArray = struct('id',cell(nSaxels,1),'size',[],...
wolffd@0 364 'saxelData',[]);
wolffd@0 365 for iSaxel = 1:nSaxels,
wolffd@0 366 chunkData.saxelArray(iSaxel) = read_saxel(fid);
wolffd@0 367 end
wolffd@0 368
wolffd@0 369 case 'SSND', % Sound Data Chunk
wolffd@0 370
wolffd@0 371 nBytes = ceil(nBits/8);
wolffd@0 372 chunkData.offset = fread(fid,1,'uint32');
wolffd@0 373 chunkData.blockSize = fread(fid,1,'uint32');
wolffd@0 374 if isempty(indexRange),
wolffd@0 375 data = [nSampleFrames nChannels];
wolffd@0 376 elseif strcmp(compressionType,'NONE'),
wolffd@0 377 if (chunkSizeArray{iChunk}-8 ~= nChannels*nSampleFrames*nBytes),
wolffd@0 378 error(error_message('sizeMismatch'));
wolffd@0 379 end
wolffd@0 380 fseek(fid,nBytes*nChannels*(indexRange(1)-1),'cof');
wolffd@0 381 nRead = min(indexRange(2),nSampleFrames)-indexRange(1)+1;
wolffd@0 382 data = fread(fid,[nChannels nRead],['*bit' int2str(nBytes*8)]).';
wolffd@0 383 if nBits < nBytes*8,
wolffd@0 384 data = data./(2^(nBytes*8-nBits));
wolffd@0 385 end
wolffd@0 386 else
wolffd@0 387 data = fread(fid,[chunkSizeArray{iChunk}-8 1],'*int8');
wolffd@0 388 end
wolffd@0 389
wolffd@0 390 end
wolffd@0 391 formChunk.chunkArray(iChunk).chunkData = chunkData;
wolffd@0 392 end
wolffd@0 393
wolffd@0 394 % Close the file:
wolffd@0 395
wolffd@0 396 fclose(fid);
wolffd@0 397
wolffd@0 398 %~~~Begin nested functions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wolffd@0 399
wolffd@0 400 %------------------------------------------------------------------------
wolffd@0 401 function errorStruct = error_message(errorCode,varargin)
wolffd@0 402 %
wolffd@0 403 % Initialize an error message (and close open files, if necessary).
wolffd@0 404 %
wolffd@0 405 %------------------------------------------------------------------------
wolffd@0 406
wolffd@0 407 % Close open files, if necessary:
wolffd@0 408
wolffd@0 409 if ~isempty(fopen(fid)),
wolffd@0 410 fclose(fid);
wolffd@0 411 end
wolffd@0 412
wolffd@0 413 % Initialize error message text:
wolffd@0 414
wolffd@0 415 switch errorCode,
wolffd@0 416 case 'badArgumentType',
wolffd@0 417 errorText = [varargin{1} ' should be of type ' varargin{2} '.'];
wolffd@0 418 case 'badIndexValue',
wolffd@0 419 errorText = ['Index range must be specified as a scalar or ' ...
wolffd@0 420 '2-element vector of positive, non-zero, non-NaN ' ...
wolffd@0 421 'values.'];
wolffd@0 422 case 'invalidFile',
wolffd@0 423 errorText = ['Could not open file ''' varargin{1} '''.'];
wolffd@0 424 case 'invalidFileFormat',
wolffd@0 425 errorText = ['Not a valid ' varargin{1} ' file.'];
wolffd@0 426 case 'invalidString',
wolffd@0 427 errorText = '''size'' is the only valid string argument.';
wolffd@0 428 case 'missingChunk',
wolffd@0 429 errorText = ['''' varargin{1} ''' chunk is required for a ' ...
wolffd@0 430 varargin{2} ' file.'];
wolffd@0 431 case 'notEnoughInputs',
wolffd@0 432 errorText = 'Not enough input arguments.';
wolffd@0 433 case 'repeatChunk',
wolffd@0 434 errorText = ['The following chunk IDs should not appear more ' ...
wolffd@0 435 'than once in an ' varargin{1} ' file: ' varargin{2}];
wolffd@0 436 case 'sizeMismatch',
wolffd@0 437 errorText = 'Data size mismatch between COMM and SSND chunks.';
wolffd@0 438 case 'unknownExtension',
wolffd@0 439 errorText = ['Unknown file extension ''' varargin{1} '''.'];
wolffd@0 440 end
wolffd@0 441
wolffd@0 442 % Create error structure:
wolffd@0 443
wolffd@0 444 errorStruct = struct('message',errorText,...
wolffd@0 445 'identifier',['aiffread:' errorCode]);
wolffd@0 446
wolffd@0 447 end
wolffd@0 448
wolffd@0 449 %~~~End nested functions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wolffd@0 450
wolffd@0 451 end
wolffd@0 452
wolffd@0 453 %~~~Begin subfunctions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wolffd@0 454
wolffd@0 455 %--------------------------------------------------------------------------
wolffd@0 456 function value = extended2double(exponent,highMantissa,lowMantissa)
wolffd@0 457 %
wolffd@0 458 % Converts an 80-bit extended floating-point type to a double.
wolffd@0 459 %
wolffd@0 460 %--------------------------------------------------------------------------
wolffd@0 461
wolffd@0 462 signBit = bitand(exponent,32768);
wolffd@0 463 exponent = bitand(exponent,32767);
wolffd@0 464 highMantissa = bitand(highMantissa,4294967295);
wolffd@0 465 lowMantissa = bitand(lowMantissa,4294967295);
wolffd@0 466 if (exponent == 0) && (highMantissa == 0) && (lowMantissa == 0),
wolffd@0 467 value = 0;
wolffd@0 468 elseif exponent == 32767,
wolffd@0 469 if (highMantissa > 0) || (lowMantissa > 0),
wolffd@0 470 value = nan;
wolffd@0 471 else
wolffd@0 472 value = inf;
wolffd@0 473 end
wolffd@0 474 else
wolffd@0 475 value = highMantissa*2^(exponent-16414)+lowMantissa*2^(exponent-16446);
wolffd@0 476 end
wolffd@0 477 if signBit,
wolffd@0 478 value = -value;
wolffd@0 479 end
wolffd@0 480
wolffd@0 481 end
wolffd@0 482
wolffd@0 483 %--------------------------------------------------------------------------
wolffd@0 484 function commentStruct = read_comment(fid)
wolffd@0 485 %
wolffd@0 486 % Reads a structure of comment data from a file.
wolffd@0 487 %
wolffd@0 488 %--------------------------------------------------------------------------
wolffd@0 489
wolffd@0 490 commentStruct = struct('timeStamp',fread(fid,1,'uint32'),...
wolffd@0 491 'marker',fread(fid,1,'int16'),...
wolffd@0 492 'count',[],'text',[]);
wolffd@0 493 charCount = fread(fid,1,'uint16');
wolffd@0 494 commentStruct.count = charCount;
wolffd@0 495 commentStruct.text = read_text(fid,charCount);
wolffd@0 496
wolffd@0 497 end
wolffd@0 498
wolffd@0 499 %--------------------------------------------------------------------------
wolffd@0 500 function loopStruct = read_loop(fid)
wolffd@0 501 %
wolffd@0 502 % Reads a structure of loop data from a file.
wolffd@0 503 %
wolffd@0 504 %--------------------------------------------------------------------------
wolffd@0 505
wolffd@0 506 loopStruct = struct('playMode',fread(fid,1,'int16'),...
wolffd@0 507 'beginLoop',fread(fid,1,'int16'),...
wolffd@0 508 'endLoop',fread(fid,1,'int16'));
wolffd@0 509
wolffd@0 510 end
wolffd@0 511
wolffd@0 512 %--------------------------------------------------------------------------
wolffd@0 513 function markerStruct = read_marker(fid)
wolffd@0 514 %
wolffd@0 515 % Reads a structure of marker data from a file.
wolffd@0 516 %
wolffd@0 517 %--------------------------------------------------------------------------
wolffd@0 518
wolffd@0 519 markerStruct = struct('id',fread(fid,1,'int16'),...
wolffd@0 520 'position',fread(fid,1,'uint32'),...
wolffd@0 521 'markerName',read_pstring(fid));
wolffd@0 522
wolffd@0 523 end
wolffd@0 524
wolffd@0 525 %--------------------------------------------------------------------------
wolffd@0 526 function pascalString = read_pstring(fid)
wolffd@0 527 %
wolffd@0 528 % Reads a Pascal-style string from a file, and afterwards shifts the file
wolffd@0 529 % pointer ahead by one byte if necessary to make the total number of bytes
wolffd@0 530 % read an even number.
wolffd@0 531 %
wolffd@0 532 %--------------------------------------------------------------------------
wolffd@0 533
wolffd@0 534 charCount = fread(fid,1,'uint8');
wolffd@0 535 pascalString = fread(fid,[1 charCount],'int8=>char');
wolffd@0 536 if rem(charCount+1,2),
wolffd@0 537 fseek(fid,1,'cof');
wolffd@0 538 end
wolffd@0 539
wolffd@0 540 end
wolffd@0 541
wolffd@0 542 %--------------------------------------------------------------------------
wolffd@0 543 function saxelStruct = read_saxel(fid)
wolffd@0 544 %
wolffd@0 545 % Reads a structure of saxel data from a file.
wolffd@0 546 %
wolffd@0 547 %--------------------------------------------------------------------------
wolffd@0 548
wolffd@0 549 saxelStruct = struct('id',fread(fid,1,'int16'),'size',[],'saxelData',[]);
wolffd@0 550 saxelBytes = fread(fid,1,'uint16');
wolffd@0 551 saxelStruct.size = saxelBytes;
wolffd@0 552 saxelStruct.saxelData = fread(fid,[saxelBytes 1],'*int8');
wolffd@0 553 if rem(saxelBytes,2),
wolffd@0 554 fseek(fid,1,'cof');
wolffd@0 555 end
wolffd@0 556
wolffd@0 557 end
wolffd@0 558
wolffd@0 559 %--------------------------------------------------------------------------
wolffd@0 560 function textString = read_text(fid,charCount)
wolffd@0 561 %
wolffd@0 562 % Reads ASCII text from a file, and afterwards shifts the file pointer
wolffd@0 563 % ahead by one byte if necessary to make the total number of bytes read an
wolffd@0 564 % even number.
wolffd@0 565 %
wolffd@0 566 %--------------------------------------------------------------------------
wolffd@0 567
wolffd@0 568 textString = fread(fid,[1 charCount],'int8=>char');
wolffd@0 569 if rem(charCount,2),
wolffd@0 570 fseek(fid,1,'cof');
wolffd@0 571 end
wolffd@0 572
wolffd@0 573 end
wolffd@0 574
wolffd@0 575 %~~~End subfunctions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~