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