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

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