Daniel@0: function [data,Fs,nBits,formChunk] = aiffread(filePath,indexRange) Daniel@0: %AIFFREAD Read AIFF (Audio Interchange File Format) sound file. Daniel@0: % Y = AIFFREAD(FILE) reads an AIFF file specified by the string FILE, Daniel@0: % returning the sampled data in Y. The ".aif" extension is appended if no Daniel@0: % extension is given. Daniel@0: % Daniel@0: % [Y,FS,NBITS,CHUNKDATA] = AIFFREAD(FILE) returns the sample rate (FS) in Daniel@0: % Hertz, the number of bits per sample (NBITS) used to encode the data in Daniel@0: % the file, and a complete structure of the chunk data (CHUNKDATA) Daniel@0: % contained in the AIFF file (minus the actual audio data returned in Y). Daniel@0: % See below for a description of CHUNKDATA. Daniel@0: % Daniel@0: % [...] = AIFFREAD(FILE,N) returns only the first N samples from each Daniel@0: % channel in the file. Daniel@0: % Daniel@0: % [...] = AIFFREAD(FILE,[N1 N2]) returns only samples N1 through N2 from Daniel@0: % each channel in the file. Daniel@0: % Daniel@0: % [SIZ,...] = AIFFREAD(FILE,'size') returns the size of the audio data Daniel@0: % contained in the file in place of the actual audio data, where Daniel@0: % SIZ = [nSampleFrames nChannels]. Daniel@0: % Daniel@0: %-NOTES-------------------------------------------------------------------- Daniel@0: % Daniel@0: % A note on compressed files: Daniel@0: % Daniel@0: % Both AIFF and AIFC/AIFF-C (compressed) file types can be read by Daniel@0: % AIFFREAD, but the data returned for AIFC/AIFF-C files will be the Daniel@0: % raw, compressed data (i.e. AIFFREAD loads the data from the file Daniel@0: % without modification). Currently, since there are many compression Daniel@0: % formats, it is the responsibility of the user to uncompress the Daniel@0: % sound data using parameters defined in the COMM chunk (contained in Daniel@0: % the returned CHUNKDATA structure). When loading AIFC/AIFF-C files, Daniel@0: % any optional numerical subranges are ignored and the entire set of Daniel@0: % compressed data is returned as a column vector of signed bytes Daniel@0: % (INT8 type). Daniel@0: % Daniel@0: % A note on the CHUNKDATA structure: Daniel@0: % Daniel@0: % The CHUNKDATA structure has the following fields: Daniel@0: % Daniel@0: % -'chunkID': The 4-character ID for the chunk. This will always be Daniel@0: % the string 'FORM'. Daniel@0: % -'chunkSize': The size (in bytes) of the remaining data in the Daniel@0: % file. Daniel@0: % -'formType': A 4-character string for the file type that should Daniel@0: % be either 'AIFF' or 'AIFC'. Daniel@0: % -'chunkArray': An array of structures, one entry for every chunk Daniel@0: % that is in the file (not counting this parent FORM Daniel@0: % chunk). The fields of this structure are: Daniel@0: % -'chunkID': The 4-character ID for the chunk. Daniel@0: % -'chunkSize': The size (in bytes) of the Daniel@0: % remaining data in the chunk. Daniel@0: % -'chunkData': A structure of data for the Daniel@0: % chunk. The form of this data for Daniel@0: % a given chunkID can be found at Daniel@0: % the links given below for the Daniel@0: % file format standards. Daniel@0: % Daniel@0: % The data portion of certain chunks may not have a clearly defined Daniel@0: % format, or that format may be dependent on the implementation or Daniel@0: % application that will be using the data. In such cases, the data Daniel@0: % returned for that chunk in the CHUNKDATA structure will be in a raw Daniel@0: % format (vectors of signed or unsigned 8-bit integers) and it will be Daniel@0: % up to the user/application to parse and format this data correctly. Daniel@0: % The following is a list of such AIFF/AIFF-C chunks: Daniel@0: % Daniel@0: % -Audio Recording Chunk (chunkID = 'AESD'): The chunkData Daniel@0: % structure has one field 'aesChannelStatusData' that stores a Daniel@0: % column vector of 24 8-bit unsigned integers. Daniel@0: % -Application Specific Chunk (chunkID = 'APPL'): The chunkData Daniel@0: % structure has two fields. 'applicationSignature' stores a Daniel@0: % 4-character string identifying the application. 'data' stores a Daniel@0: % column vector of 8-bit signed integers. Daniel@0: % -MIDI Data Chunk (chunkID = 'MIDI'): The chunkData structure has Daniel@0: % one field 'midiData' that stores a column vector of 8-bit Daniel@0: % unsigned integers. Daniel@0: % -Sound Accelerator (SAXEL) Chunk (chunkID = 'SAXL'): There is no Daniel@0: % finalized format for Saxel chunks, so the chunkData structure Daniel@0: % follows the draft format given in Appendix D of the AIFF-C Daniel@0: % standard. Daniel@0: % Daniel@0: % Description for the AIFF standard can be found here: Daniel@0: % Daniel@0: % http://muratnkonar.com/aiff/index.html Daniel@0: % Daniel@0: % Descriptions for the AIFC/AIFF-C standard can be found here: Daniel@0: % Daniel@0: % http://www.cnpbagwell.com/aiff-c.txt Daniel@0: % http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/AIFF/Docs/... Daniel@0: % AIFF-C.9.26.91.pdf Daniel@0: Daniel@0: % Author: Ken Eaton Daniel@0: % Last modified: 3/17/09 Daniel@0: %-------------------------------------------------------------------------- Daniel@0: Daniel@0: % Initializations: Daniel@0: Daniel@0: aiffChunkPrecedence = {'COMM' 'SSND' 'MARK' 'INST' 'COMT' 'NAME' ... Daniel@0: 'AUTH' '[c] ' 'ANNO' 'AESD' 'MIDI' 'APPL'}; Daniel@0: aiffChunkLimits = [1 1 1 1 1 1 1 1 inf 1 inf inf]; Daniel@0: aifcChunkPrecedence = {'FVER' 'COMM' 'INST' 'SAXL' 'COMT' 'MARK' ... Daniel@0: 'SSND' 'NAME' 'AUTH' '[c] ' 'ANNO' 'AESD' ... Daniel@0: 'MIDI' 'APPL'}; Daniel@0: aifcChunkLimits = [1 1 1 inf 1 1 1 1 1 1 inf 1 inf inf]; Daniel@0: fid = -1; Daniel@0: Daniel@0: % Check the number of input arguments: Daniel@0: Daniel@0: switch nargin, Daniel@0: case 0, Daniel@0: error(error_message('notEnoughInputs')); Daniel@0: case 1, Daniel@0: indexRange = [1 inf]; Daniel@0: end Daniel@0: Daniel@0: % Check the file name input argument: Daniel@0: Daniel@0: if ~ischar(filePath), Daniel@0: error(error_message('badArgumentType','File name','char')); Daniel@0: end Daniel@0: [filePath,fileName,fileExtension] = fileparts(filePath); Daniel@0: if isempty(fileExtension), Daniel@0: fileExtension = '.aif'; Daniel@0: end Daniel@0: if ~any(strcmpi(fileExtension,{'.aif' '.afc' '.aiff' '.aifc'})), Daniel@0: error(error_message('unknownExtension',fileExtension)); Daniel@0: end Daniel@0: Daniel@0: % Check the optional input argument: Daniel@0: Daniel@0: if isnumeric(indexRange), % Numeric range specification Daniel@0: Daniel@0: indexRange = double(indexRange); Daniel@0: nRange = numel(indexRange); Daniel@0: if (nRange > 2) || any(indexRange < 1) || any(isnan(indexRange)), Daniel@0: error(error_message('badIndexValue')); Daniel@0: end Daniel@0: indexRange = [ones(nRange ~= 2) round(indexRange) inf(nRange == 0)]; Daniel@0: Daniel@0: elseif ischar(indexRange), % Specification for returning just the size Daniel@0: Daniel@0: if ~strncmpi(indexRange,'size',numel(indexRange)), Daniel@0: error(error_message('invalidString')); Daniel@0: end Daniel@0: indexRange = []; Daniel@0: Daniel@0: else % Invalid input Daniel@0: Daniel@0: error(error_message('badArgumentType','Optional argument',... Daniel@0: 'numeric or char')); Daniel@0: Daniel@0: end Daniel@0: Daniel@0: % Check that the file exists and can be opened: Daniel@0: Daniel@0: fid = fopen(fullfile(filePath,[fileName fileExtension]),'r','b'); Daniel@0: if fid == -1, Daniel@0: error(error_message('invalidFile',[fileName fileExtension])); Daniel@0: end Daniel@0: Daniel@0: % Initialize formChunk structure: Daniel@0: Daniel@0: formChunk = struct('chunkID',[],'chunkSize',[],'formType',[],... Daniel@0: 'chunkArray',[]); Daniel@0: Daniel@0: % Read FORM chunk data: Daniel@0: Daniel@0: formChunk.chunkID = read_text(fid,4); Daniel@0: if ~strcmp(formChunk.chunkID,'FORM'), Daniel@0: error(error_message('invalidFileFormat',fileExtension)); Daniel@0: end Daniel@0: formChunk.chunkSize = fread(fid,1,'int32'); Daniel@0: formType = read_text(fid,4); Daniel@0: if ~any(strcmp(formType,{'AIFF' 'AIFC'})), Daniel@0: error(error_message('invalidFileFormat',fileExtension)); Daniel@0: end Daniel@0: formChunk.formType = formType; Daniel@0: Daniel@0: % Since the order of chunks is not guaranteed, first skip through the Daniel@0: % file and read just the chunkIDs and chunkSizes: Daniel@0: Daniel@0: iChunk = 0; Daniel@0: chunkIDArray = {}; Daniel@0: chunkSizeArray = {}; Daniel@0: chunkDataIndex = []; Daniel@0: nextChunkID = read_text(fid,4); Daniel@0: while ~feof(fid), Daniel@0: iChunk = iChunk+1; Daniel@0: chunkIDArray{iChunk} = nextChunkID; Daniel@0: chunkSize = fread(fid,1,'int32'); Daniel@0: chunkSizeArray{iChunk} = chunkSize; Daniel@0: chunkDataIndex(iChunk) = ftell(fid); Daniel@0: fseek(fid,chunkSize+rem(chunkSize,2),'cof'); Daniel@0: nextChunkID = read_text(fid,4); Daniel@0: end Daniel@0: Daniel@0: % Check for the presence of required chunks: Daniel@0: Daniel@0: if ~ismember('COMM',chunkIDArray), Daniel@0: error(error_message('missingChunk','COMM',formType)); Daniel@0: end Daniel@0: if strcmp(formType,'AIFC') && ~ismember('FVER',chunkIDArray), Daniel@0: error(error_message('missingChunk','FVER',formType)); Daniel@0: end Daniel@0: Daniel@0: % Check for unknown chunks and order chunks based on chunk precedence: Daniel@0: Daniel@0: if strcmp(formType,'AIFF'), Daniel@0: [isChunk,orderIndex] = ismember(chunkIDArray,aiffChunkPrecedence); Daniel@0: else Daniel@0: [isChunk,orderIndex] = ismember(chunkIDArray,aifcChunkPrecedence); Daniel@0: end Daniel@0: if ~all(isChunk), Daniel@0: unknownChunks = [chunkIDArray(~isChunk); ... Daniel@0: repmat({', '},1,sum(~isChunk)-1) {'.'}]; Daniel@0: orderIndex = orderIndex(isChunk); Daniel@0: chunkIDArray = chunkIDArray(isChunk); Daniel@0: chunkSizeArray = chunkSizeArray(isChunk); Daniel@0: chunkDataIndex = chunkDataIndex(isChunk); Daniel@0: warning('aiffread:unknownChunk',... Daniel@0: ['The following chunk IDs are unknown for an ' formType ... Daniel@0: ' file and will be ignored: ' unknownChunks{:}]); Daniel@0: end Daniel@0: [index,orderIndex] = sort(orderIndex); Daniel@0: chunkIDArray = chunkIDArray(orderIndex); Daniel@0: chunkSizeArray = chunkSizeArray(orderIndex); Daniel@0: chunkDataIndex = chunkDataIndex(orderIndex); Daniel@0: Daniel@0: % Check for chunks that should not appear more than once: Daniel@0: Daniel@0: index = unique(index(diff(index) < 1)); Daniel@0: if strcmp(formType,'AIFF'), Daniel@0: repeatChunks = aiffChunkPrecedence(aiffChunkLimits(index) == 1); Daniel@0: else Daniel@0: repeatChunks = aifcChunkPrecedence(aifcChunkLimits(index) == 1); Daniel@0: end Daniel@0: if ~isempty(repeatChunks), Daniel@0: repeatChunks = [repeatChunks; ... Daniel@0: repmat({', '},1,numel(repeatChunks)-1) {'.'}]; Daniel@0: error(error_message('repeatChunk',formType,[repeatChunks{:}])); Daniel@0: end Daniel@0: Daniel@0: % Initialize chunkArray data: Daniel@0: Daniel@0: formChunk.chunkArray = struct('chunkID',chunkIDArray,... Daniel@0: 'chunkSize',chunkSizeArray,... Daniel@0: 'chunkData',[]); Daniel@0: Daniel@0: % Read the data for each chunk: Daniel@0: Daniel@0: for iChunk = 1:numel(chunkIDArray), Daniel@0: chunkData = []; Daniel@0: fseek(fid,chunkDataIndex(iChunk),'bof'); Daniel@0: switch chunkIDArray{iChunk}, Daniel@0: Daniel@0: case '[c] ', % Copyright Chunk Daniel@0: Daniel@0: chunkData.text = read_text(fid,chunkSizeArray{iChunk}); Daniel@0: Daniel@0: case 'AESD', % Audio Recording Chunk Daniel@0: Daniel@0: chunkData.aesChannelStatusData = ... Daniel@0: fread(fid,[chunkSizeArray{iChunk} 1],'*uint8'); Daniel@0: Daniel@0: case 'ANNO', % Annotation Chunk Daniel@0: Daniel@0: chunkData.text = read_text(fid,chunkSizeArray{iChunk}); Daniel@0: Daniel@0: case 'APPL', % Application Specific Chunk Daniel@0: Daniel@0: chunkData.applicationSignature = read_text(fid,4); Daniel@0: chunkData.data = fread(fid,[chunkSizeArray{iChunk}-4 1],'*int8'); Daniel@0: Daniel@0: case 'AUTH', % Author Chunk Daniel@0: Daniel@0: chunkData.text = read_text(fid,chunkSizeArray{iChunk}); Daniel@0: Daniel@0: case 'COMM', % Common Chunk Daniel@0: Daniel@0: nChannels = fread(fid,1,'int16'); Daniel@0: chunkData.nChannels = nChannels; Daniel@0: nSampleFrames = fread(fid,1,'uint32'); Daniel@0: if (nSampleFrames > 0) && ~ismember('SSND',chunkIDArray), Daniel@0: error(error_message('missingChunk','SSND',formType)); Daniel@0: end Daniel@0: chunkData.nSampleFrames = nSampleFrames; Daniel@0: nBits = fread(fid,1,'int16'); Daniel@0: chunkData.sampleSize = nBits; Daniel@0: exponent = fread(fid,1,'uint16'); Daniel@0: highMantissa = fread(fid,1,'uint32'); Daniel@0: lowMantissa = fread(fid,1,'uint32'); Daniel@0: Fs = extended2double(exponent,highMantissa,lowMantissa); Daniel@0: chunkData.sampleRate = Fs; Daniel@0: if strcmp(formType,'AIFF'), Daniel@0: compressionType = 'NONE'; Daniel@0: else Daniel@0: compressionType = read_text(fid,4); Daniel@0: chunkData.compressionType = compressionType; Daniel@0: chunkData.compressionName = read_pstring(fid); Daniel@0: end Daniel@0: Daniel@0: case 'COMT', % Comments Chunk Daniel@0: Daniel@0: nComments = fread(fid,1,'uint16'); Daniel@0: chunkData.nComments = nComments; Daniel@0: chunkData.commentArray = struct('timeStamp',cell(nComments,1),... Daniel@0: 'marker',[],'count',[],'text',[]); Daniel@0: for iComment = 1:nComments, Daniel@0: chunkData.commentArray(iComment) = read_comment(fid); Daniel@0: end Daniel@0: Daniel@0: case 'FVER', % Format Version Chunk (AIFC/AIFF-C only) Daniel@0: Daniel@0: timeStamp = fread(fid,1,'uint32'); Daniel@0: if timeStamp ~= 2726318400, Daniel@0: warning('aiffread:unknownVersion',... Daniel@0: ['File contains an unrecognized version of the ' ... Daniel@0: 'AIFC/AIFF-C standard.']); Daniel@0: end Daniel@0: chunkData.timeStamp = timeStamp; Daniel@0: Daniel@0: case 'INST', % Instrument Chunk Daniel@0: Daniel@0: chunkData.baseNote = fread(fid,1,'int8'); Daniel@0: chunkData.detune = fread(fid,1,'int8'); Daniel@0: chunkData.lowNote = fread(fid,1,'int8'); Daniel@0: chunkData.highNote = fread(fid,1,'int8'); Daniel@0: chunkData.lowVelocity = fread(fid,1,'int8'); Daniel@0: chunkData.highVelocity = fread(fid,1,'int8'); Daniel@0: chunkData.gain = fread(fid,1,'int16'); Daniel@0: chunkData.sustainLoop = read_loop(fid); Daniel@0: chunkData.releaseLoop = read_loop(fid); Daniel@0: Daniel@0: case 'MARK', % Marker Chunk Daniel@0: Daniel@0: nMarkers = fread(fid,1,'uint16'); Daniel@0: chunkData.nMarkers = nMarkers; Daniel@0: chunkData.markerArray = struct('id',cell(nMarkers,1),... Daniel@0: 'position',[],'markerName',[]); Daniel@0: for iMarker = 1:nMarkers, Daniel@0: chunkData.markerArray(iMarker) = read_marker(fid); Daniel@0: end Daniel@0: markerIDs = [chunkData.markerArray.id]; Daniel@0: if any(markerIDs < 1) || (numel(unique(markerIDs)) < nMarkers), Daniel@0: warning('aiffread:invalidMarkers',... Daniel@0: 'Invalid or repeated marker IDs were detected.'); Daniel@0: end Daniel@0: Daniel@0: case 'MIDI', % MIDI Data Chunk Daniel@0: Daniel@0: chunkData.midiData = fread(fid,[chunkSizeArray{iChunk} 1],... Daniel@0: '*uint8'); Daniel@0: Daniel@0: case 'NAME', % Name Chunk Daniel@0: Daniel@0: chunkData.text = read_text(fid,chunkSizeArray{iChunk}); Daniel@0: Daniel@0: case 'SAXL', % Sound Accelerator (SAXEL) Chunk (AIFC/AIFF-C only) Daniel@0: Daniel@0: nSaxels = fread(fid,1,'uint16'); Daniel@0: chunkData.nSaxels = nSaxels; Daniel@0: chunkData.saxelArray = struct('id',cell(nSaxels,1),'size',[],... Daniel@0: 'saxelData',[]); Daniel@0: for iSaxel = 1:nSaxels, Daniel@0: chunkData.saxelArray(iSaxel) = read_saxel(fid); Daniel@0: end Daniel@0: Daniel@0: case 'SSND', % Sound Data Chunk Daniel@0: Daniel@0: nBytes = ceil(nBits/8); Daniel@0: chunkData.offset = fread(fid,1,'uint32'); Daniel@0: chunkData.blockSize = fread(fid,1,'uint32'); Daniel@0: if isempty(indexRange), Daniel@0: data = [nSampleFrames nChannels]; Daniel@0: elseif strcmp(compressionType,'NONE'), Daniel@0: if (chunkSizeArray{iChunk}-8 ~= nChannels*nSampleFrames*nBytes), Daniel@0: error(error_message('sizeMismatch')); Daniel@0: end Daniel@0: fseek(fid,nBytes*nChannels*(indexRange(1)-1),'cof'); Daniel@0: nRead = min(indexRange(2),nSampleFrames)-indexRange(1)+1; Daniel@0: data = fread(fid,[nChannels nRead],['*bit' int2str(nBytes*8)]).'; Daniel@0: if nBits < nBytes*8, Daniel@0: data = data./(2^(nBytes*8-nBits)); Daniel@0: end Daniel@0: else Daniel@0: data = fread(fid,[chunkSizeArray{iChunk}-8 1],'*int8'); Daniel@0: end Daniel@0: Daniel@0: end Daniel@0: formChunk.chunkArray(iChunk).chunkData = chunkData; Daniel@0: end Daniel@0: Daniel@0: % Close the file: Daniel@0: Daniel@0: fclose(fid); Daniel@0: Daniel@0: %~~~Begin nested functions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Daniel@0: Daniel@0: %------------------------------------------------------------------------ Daniel@0: function errorStruct = error_message(errorCode,varargin) Daniel@0: % Daniel@0: % Initialize an error message (and close open files, if necessary). Daniel@0: % Daniel@0: %------------------------------------------------------------------------ Daniel@0: Daniel@0: % Close open files, if necessary: Daniel@0: Daniel@0: if ~isempty(fopen(fid)), Daniel@0: fclose(fid); Daniel@0: end Daniel@0: Daniel@0: % Initialize error message text: Daniel@0: Daniel@0: switch errorCode, Daniel@0: case 'badArgumentType', Daniel@0: errorText = [varargin{1} ' should be of type ' varargin{2} '.']; Daniel@0: case 'badIndexValue', Daniel@0: errorText = ['Index range must be specified as a scalar or ' ... Daniel@0: '2-element vector of positive, non-zero, non-NaN ' ... Daniel@0: 'values.']; Daniel@0: case 'invalidFile', Daniel@0: errorText = ['Could not open file ''' varargin{1} '''.']; Daniel@0: case 'invalidFileFormat', Daniel@0: errorText = ['Not a valid ' varargin{1} ' file.']; Daniel@0: case 'invalidString', Daniel@0: errorText = '''size'' is the only valid string argument.'; Daniel@0: case 'missingChunk', Daniel@0: errorText = ['''' varargin{1} ''' chunk is required for a ' ... Daniel@0: varargin{2} ' file.']; Daniel@0: case 'notEnoughInputs', Daniel@0: errorText = 'Not enough input arguments.'; Daniel@0: case 'repeatChunk', Daniel@0: errorText = ['The following chunk IDs should not appear more ' ... Daniel@0: 'than once in an ' varargin{1} ' file: ' varargin{2}]; Daniel@0: case 'sizeMismatch', Daniel@0: errorText = 'Data size mismatch between COMM and SSND chunks.'; Daniel@0: case 'unknownExtension', Daniel@0: errorText = ['Unknown file extension ''' varargin{1} '''.']; Daniel@0: end Daniel@0: Daniel@0: % Create error structure: Daniel@0: Daniel@0: errorStruct = struct('message',errorText,... Daniel@0: 'identifier',['aiffread:' errorCode]); Daniel@0: Daniel@0: end Daniel@0: Daniel@0: %~~~End nested functions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Daniel@0: Daniel@0: end Daniel@0: Daniel@0: %~~~Begin subfunctions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Daniel@0: Daniel@0: %-------------------------------------------------------------------------- Daniel@0: function value = extended2double(exponent,highMantissa,lowMantissa) Daniel@0: % Daniel@0: % Converts an 80-bit extended floating-point type to a double. Daniel@0: % Daniel@0: %-------------------------------------------------------------------------- Daniel@0: Daniel@0: signBit = bitand(exponent,32768); Daniel@0: exponent = bitand(exponent,32767); Daniel@0: highMantissa = bitand(highMantissa,4294967295); Daniel@0: lowMantissa = bitand(lowMantissa,4294967295); Daniel@0: if (exponent == 0) && (highMantissa == 0) && (lowMantissa == 0), Daniel@0: value = 0; Daniel@0: elseif exponent == 32767, Daniel@0: if (highMantissa > 0) || (lowMantissa > 0), Daniel@0: value = nan; Daniel@0: else Daniel@0: value = inf; Daniel@0: end Daniel@0: else Daniel@0: value = highMantissa*2^(exponent-16414)+lowMantissa*2^(exponent-16446); Daniel@0: end Daniel@0: if signBit, Daniel@0: value = -value; Daniel@0: end Daniel@0: Daniel@0: end Daniel@0: Daniel@0: %-------------------------------------------------------------------------- Daniel@0: function commentStruct = read_comment(fid) Daniel@0: % Daniel@0: % Reads a structure of comment data from a file. Daniel@0: % Daniel@0: %-------------------------------------------------------------------------- Daniel@0: Daniel@0: commentStruct = struct('timeStamp',fread(fid,1,'uint32'),... Daniel@0: 'marker',fread(fid,1,'int16'),... Daniel@0: 'count',[],'text',[]); Daniel@0: charCount = fread(fid,1,'uint16'); Daniel@0: commentStruct.count = charCount; Daniel@0: commentStruct.text = read_text(fid,charCount); Daniel@0: Daniel@0: end Daniel@0: Daniel@0: %-------------------------------------------------------------------------- Daniel@0: function loopStruct = read_loop(fid) Daniel@0: % Daniel@0: % Reads a structure of loop data from a file. Daniel@0: % Daniel@0: %-------------------------------------------------------------------------- Daniel@0: Daniel@0: loopStruct = struct('playMode',fread(fid,1,'int16'),... Daniel@0: 'beginLoop',fread(fid,1,'int16'),... Daniel@0: 'endLoop',fread(fid,1,'int16')); Daniel@0: Daniel@0: end Daniel@0: Daniel@0: %-------------------------------------------------------------------------- Daniel@0: function markerStruct = read_marker(fid) Daniel@0: % Daniel@0: % Reads a structure of marker data from a file. Daniel@0: % Daniel@0: %-------------------------------------------------------------------------- Daniel@0: Daniel@0: markerStruct = struct('id',fread(fid,1,'int16'),... Daniel@0: 'position',fread(fid,1,'uint32'),... Daniel@0: 'markerName',read_pstring(fid)); Daniel@0: Daniel@0: end Daniel@0: Daniel@0: %-------------------------------------------------------------------------- Daniel@0: function pascalString = read_pstring(fid) Daniel@0: % Daniel@0: % Reads a Pascal-style string from a file, and afterwards shifts the file Daniel@0: % pointer ahead by one byte if necessary to make the total number of bytes Daniel@0: % read an even number. Daniel@0: % Daniel@0: %-------------------------------------------------------------------------- Daniel@0: Daniel@0: charCount = fread(fid,1,'uint8'); Daniel@0: pascalString = fread(fid,[1 charCount],'int8=>char'); Daniel@0: if rem(charCount+1,2), Daniel@0: fseek(fid,1,'cof'); Daniel@0: end Daniel@0: Daniel@0: end Daniel@0: Daniel@0: %-------------------------------------------------------------------------- Daniel@0: function saxelStruct = read_saxel(fid) Daniel@0: % Daniel@0: % Reads a structure of saxel data from a file. Daniel@0: % Daniel@0: %-------------------------------------------------------------------------- Daniel@0: Daniel@0: saxelStruct = struct('id',fread(fid,1,'int16'),'size',[],'saxelData',[]); Daniel@0: saxelBytes = fread(fid,1,'uint16'); Daniel@0: saxelStruct.size = saxelBytes; Daniel@0: saxelStruct.saxelData = fread(fid,[saxelBytes 1],'*int8'); Daniel@0: if rem(saxelBytes,2), Daniel@0: fseek(fid,1,'cof'); Daniel@0: end Daniel@0: Daniel@0: end Daniel@0: Daniel@0: %-------------------------------------------------------------------------- Daniel@0: function textString = read_text(fid,charCount) Daniel@0: % Daniel@0: % Reads ASCII text from a file, and afterwards shifts the file pointer Daniel@0: % ahead by one byte if necessary to make the total number of bytes read an Daniel@0: % even number. Daniel@0: % Daniel@0: %-------------------------------------------------------------------------- Daniel@0: Daniel@0: textString = fread(fid,[1 charCount],'int8=>char'); Daniel@0: if rem(charCount,2), Daniel@0: fseek(fid,1,'cof'); Daniel@0: end Daniel@0: Daniel@0: end Daniel@0: Daniel@0: %~~~End subfunctions~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~