1 | /* |
---|
2 | Audio File Library |
---|
3 | Copyright (C) 1998-2000, Michael Pruett <michael@68k.org> |
---|
4 | Copyright (C) 2000, Silicon Graphics, Inc. |
---|
5 | |
---|
6 | This library is free software; you can redistribute it and/or |
---|
7 | modify it under the terms of the GNU Library General Public |
---|
8 | License as published by the Free Software Foundation; either |
---|
9 | version 2 of the License, or (at your option) any later version. |
---|
10 | |
---|
11 | This library is distributed in the hope that it will be useful, |
---|
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
14 | Library General Public License for more details. |
---|
15 | |
---|
16 | You should have received a copy of the GNU Library General Public |
---|
17 | License along with this library; if not, write to the |
---|
18 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
19 | Boston, MA 02111-1307 USA. |
---|
20 | */ |
---|
21 | |
---|
22 | /* |
---|
23 | aiff.c |
---|
24 | |
---|
25 | This file contains routines for parsing AIFF and AIFF-C sound |
---|
26 | files. |
---|
27 | */ |
---|
28 | |
---|
29 | #ifdef HAVE_CONFIG_H |
---|
30 | #include <config.h> |
---|
31 | #endif |
---|
32 | |
---|
33 | #include <assert.h> |
---|
34 | #include <sys/types.h> |
---|
35 | #include <stdio.h> |
---|
36 | #include <string.h> |
---|
37 | |
---|
38 | #include "extended.h" |
---|
39 | #include "audiofile.h" |
---|
40 | #include "util.h" |
---|
41 | #include "afinternal.h" |
---|
42 | #include "byteorder.h" |
---|
43 | #include "aiff.h" |
---|
44 | #include "setup.h" |
---|
45 | #include "track.h" |
---|
46 | #include "marker.h" |
---|
47 | |
---|
48 | static status ParseFVER (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, |
---|
49 | size_t size); |
---|
50 | static status ParseAESD (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, |
---|
51 | size_t size); |
---|
52 | static status ParseMiscellaneous (AFfilehandle file, AFvirtualfile *fh, |
---|
53 | u_int32_t type, size_t size); |
---|
54 | static status ParseINST (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, |
---|
55 | size_t size); |
---|
56 | static status ParseMARK (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, |
---|
57 | size_t size); |
---|
58 | static status ParseCOMM (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, |
---|
59 | size_t size); |
---|
60 | static status ParseSSND (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, |
---|
61 | size_t size); |
---|
62 | |
---|
63 | _InstParamInfo _af_aiff_inst_params[_AF_AIFF_NUM_INSTPARAMS] = |
---|
64 | { |
---|
65 | { AF_INST_MIDI_BASENOTE, AU_PVTYPE_LONG, "MIDI base note", {60} }, |
---|
66 | { AF_INST_NUMCENTS_DETUNE, AU_PVTYPE_LONG, "Detune in cents", {0} }, |
---|
67 | { AF_INST_MIDI_LOVELOCITY, AU_PVTYPE_LONG, "Low velocity", {1} }, |
---|
68 | { AF_INST_MIDI_HIVELOCITY, AU_PVTYPE_LONG, "High velocity", {127} }, |
---|
69 | { AF_INST_MIDI_LONOTE, AU_PVTYPE_LONG, "Low note", {0} }, |
---|
70 | { AF_INST_MIDI_HINOTE, AU_PVTYPE_LONG, "High note", {127} }, |
---|
71 | { AF_INST_NUMDBS_GAIN, AU_PVTYPE_LONG, "Gain in dB", {0} }, |
---|
72 | { AF_INST_SUSLOOPID, AU_PVTYPE_LONG, "Sustain loop id", {0} }, |
---|
73 | { AF_INST_RELLOOPID, AU_PVTYPE_LONG, "Release loop id", {0} } |
---|
74 | }; |
---|
75 | |
---|
76 | int _af_aiffc_compression_types[_AF_AIFF_NUM_COMPTYPES] = |
---|
77 | { |
---|
78 | AF_COMPRESSION_G711_ULAW, |
---|
79 | AF_COMPRESSION_G711_ALAW |
---|
80 | }; |
---|
81 | |
---|
82 | _AFfilesetup _af_aiff_default_filesetup = |
---|
83 | { |
---|
84 | _AF_VALID_FILESETUP, /* valid */ |
---|
85 | AF_FILE_AIFF, /* fileFormat */ |
---|
86 | AF_TRUE, /* trackSet */ |
---|
87 | AF_TRUE, /* instrumentSet */ |
---|
88 | AF_TRUE, /* miscellaneousSet */ |
---|
89 | 1, /* trackCount */ |
---|
90 | NULL, /* tracks */ |
---|
91 | 1, /* instrumentCount */ |
---|
92 | NULL, /* instruments */ |
---|
93 | 0, /* miscellaneousCount */ |
---|
94 | NULL /* miscellaneous */ |
---|
95 | }; |
---|
96 | |
---|
97 | /* |
---|
98 | FVER chunks are only present in AIFF-C files. |
---|
99 | */ |
---|
100 | static status ParseFVER (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, size_t size) |
---|
101 | { |
---|
102 | u_int32_t timestamp; |
---|
103 | |
---|
104 | assert(!memcmp(&type, "FVER", 4)); |
---|
105 | |
---|
106 | af_fread(×tamp, sizeof (u_int32_t), 1, fh); |
---|
107 | timestamp = BENDIAN_TO_HOST_INT32(timestamp); |
---|
108 | /* timestamp holds the number of seconds since January 1, 1904. */ |
---|
109 | |
---|
110 | return AF_SUCCEED; |
---|
111 | } |
---|
112 | |
---|
113 | /* |
---|
114 | Parse AES recording data. |
---|
115 | */ |
---|
116 | static status ParseAESD (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, size_t size) |
---|
117 | { |
---|
118 | _Track *track; |
---|
119 | unsigned char aesChannelStatusData[24]; |
---|
120 | |
---|
121 | assert(!memcmp(&type, "AESD", 4)); |
---|
122 | assert(size == 24); |
---|
123 | |
---|
124 | track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK); |
---|
125 | |
---|
126 | track->hasAESData = AF_TRUE; |
---|
127 | |
---|
128 | /* |
---|
129 | Try to read 24 bytes of AES nonaudio data from the file. |
---|
130 | Fail if the file disappoints. |
---|
131 | */ |
---|
132 | if (af_fread(aesChannelStatusData, 1, 24, fh) != 24) |
---|
133 | return AF_FAIL; |
---|
134 | |
---|
135 | memcpy(track->aesData, aesChannelStatusData, 24); |
---|
136 | |
---|
137 | return AF_SUCCEED; |
---|
138 | } |
---|
139 | |
---|
140 | /* |
---|
141 | Parse miscellaneous data chunks such as name, author, copyright, |
---|
142 | and annotation chunks. |
---|
143 | */ |
---|
144 | static status ParseMiscellaneous (AFfilehandle file, AFvirtualfile *fh, |
---|
145 | u_int32_t type, size_t size) |
---|
146 | { |
---|
147 | int misctype = AF_MISC_UNRECOGNIZED; |
---|
148 | |
---|
149 | assert(!memcmp(&type, "NAME", 4) || !memcmp(&type, "AUTH", 4) || |
---|
150 | !memcmp(&type, "(c) ", 4) || !memcmp(&type, "ANNO", 4) || |
---|
151 | !memcmp(&type, "APPL", 4) || !memcmp(&type, "MIDI", 4)); |
---|
152 | assert(size >= 0); |
---|
153 | |
---|
154 | file->miscellaneousCount++; |
---|
155 | file->miscellaneous = _af_realloc(file->miscellaneous, |
---|
156 | file->miscellaneousCount * sizeof (_Miscellaneous)); |
---|
157 | |
---|
158 | if (!memcmp(&type, "NAME", 4)) |
---|
159 | misctype = AF_MISC_NAME; |
---|
160 | else if (!memcmp(&type, "AUTH", 4)) |
---|
161 | misctype = AF_MISC_AUTH; |
---|
162 | else if (!memcmp(&type, "(c) ", 4)) |
---|
163 | misctype = AF_MISC_COPY; |
---|
164 | else if (!memcmp(&type, "ANNO", 4)) |
---|
165 | misctype = AF_MISC_ANNO; |
---|
166 | else if (!memcmp(&type, "APPL", 4)) |
---|
167 | misctype = AF_MISC_APPL; |
---|
168 | else if (!memcmp(&type, "MIDI", 4)) |
---|
169 | misctype = AF_MISC_MIDI; |
---|
170 | |
---|
171 | file->miscellaneous[file->miscellaneousCount - 1].id = file->miscellaneousCount; |
---|
172 | file->miscellaneous[file->miscellaneousCount - 1].type = misctype; |
---|
173 | file->miscellaneous[file->miscellaneousCount - 1].size = size; |
---|
174 | file->miscellaneous[file->miscellaneousCount - 1].position = 0; |
---|
175 | file->miscellaneous[file->miscellaneousCount - 1].buffer = _af_malloc(size); |
---|
176 | af_fread(file->miscellaneous[file->miscellaneousCount - 1].buffer, |
---|
177 | size, 1, file->fh); |
---|
178 | |
---|
179 | return AF_SUCCEED; |
---|
180 | } |
---|
181 | |
---|
182 | /* |
---|
183 | Parse instrument chunks, which contain information about using |
---|
184 | sound data as a sampled instrument. |
---|
185 | */ |
---|
186 | static status ParseINST (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, |
---|
187 | size_t size) |
---|
188 | { |
---|
189 | _Instrument *instrument; |
---|
190 | u_int8_t baseNote; |
---|
191 | int8_t detune; |
---|
192 | u_int8_t lowNote, highNote, lowVelocity, highVelocity; |
---|
193 | int16_t gain; |
---|
194 | |
---|
195 | u_int16_t sustainLoopPlayMode, sustainLoopBegin, sustainLoopEnd; |
---|
196 | u_int16_t releaseLoopPlayMode, releaseLoopBegin, releaseLoopEnd; |
---|
197 | |
---|
198 | assert(!memcmp(&type, "INST", 4)); |
---|
199 | |
---|
200 | instrument = _af_calloc(1, sizeof (_Instrument)); |
---|
201 | instrument->id = AF_DEFAULT_INST; |
---|
202 | instrument->values = _af_calloc(_AF_AIFF_NUM_INSTPARAMS, sizeof (AFPVu)); |
---|
203 | instrument->loopCount = 2; |
---|
204 | instrument->loops = _af_calloc(2, sizeof (_Loop)); |
---|
205 | |
---|
206 | file->instrumentCount = 1; |
---|
207 | file->instruments = instrument; |
---|
208 | |
---|
209 | af_fread(&baseNote, 1, 1, fh); |
---|
210 | af_fread(&detune, 1, 1, fh); |
---|
211 | af_fread(&lowNote, 1, 1, fh); |
---|
212 | af_fread(&highNote, 1, 1, fh); |
---|
213 | af_fread(&lowVelocity, 1, 1, fh); |
---|
214 | af_fread(&highVelocity, 1, 1, fh); |
---|
215 | af_fread(&gain, 2, 1, fh); |
---|
216 | gain = BENDIAN_TO_HOST_INT16(gain); |
---|
217 | |
---|
218 | #ifdef DEBUG |
---|
219 | printf("baseNote/detune/lowNote/highNote/lowVelocity/highVelocity/gain:" |
---|
220 | " %d %d %d %d %d %d %d\n", |
---|
221 | baseNote, detune, lowNote, highNote, lowVelocity, highVelocity, |
---|
222 | gain); |
---|
223 | #endif |
---|
224 | |
---|
225 | instrument->values[0].l = baseNote; |
---|
226 | instrument->values[1].l = detune; |
---|
227 | instrument->values[2].l = lowVelocity; |
---|
228 | instrument->values[3].l = highVelocity; |
---|
229 | instrument->values[4].l = lowNote; |
---|
230 | instrument->values[5].l = highNote; |
---|
231 | instrument->values[6].l = gain; |
---|
232 | |
---|
233 | instrument->values[7].l = 1; /* sustain loop id */ |
---|
234 | instrument->values[8].l = 2; /* release loop id */ |
---|
235 | |
---|
236 | af_fread(&sustainLoopPlayMode, sizeof (u_int16_t), 1, fh); |
---|
237 | sustainLoopPlayMode = BENDIAN_TO_HOST_INT16(sustainLoopPlayMode); |
---|
238 | af_fread(&sustainLoopBegin, sizeof (u_int16_t), 1, fh); |
---|
239 | sustainLoopBegin = BENDIAN_TO_HOST_INT16(sustainLoopBegin); |
---|
240 | af_fread(&sustainLoopEnd, sizeof (u_int16_t), 1, fh); |
---|
241 | sustainLoopEnd = BENDIAN_TO_HOST_INT16(sustainLoopEnd); |
---|
242 | |
---|
243 | af_fread(&releaseLoopPlayMode, sizeof (u_int16_t), 1, fh); |
---|
244 | releaseLoopPlayMode = BENDIAN_TO_HOST_INT16(releaseLoopPlayMode); |
---|
245 | af_fread(&releaseLoopBegin, sizeof (u_int16_t), 1, fh); |
---|
246 | releaseLoopBegin = BENDIAN_TO_HOST_INT16(releaseLoopBegin); |
---|
247 | af_fread(&releaseLoopEnd, sizeof (u_int16_t), 1, fh); |
---|
248 | releaseLoopEnd = BENDIAN_TO_HOST_INT16(releaseLoopEnd); |
---|
249 | |
---|
250 | #ifdef DEBUG |
---|
251 | printf("sustain loop: mode %d, begin %d, end %d\n", |
---|
252 | sustainLoopPlayMode, sustainLoopBegin, sustainLoopEnd); |
---|
253 | |
---|
254 | printf("release loop: mode %d, begin %d, end %d\n", |
---|
255 | releaseLoopPlayMode, releaseLoopBegin, releaseLoopEnd); |
---|
256 | #endif |
---|
257 | |
---|
258 | instrument->loops[0].id = 1; |
---|
259 | instrument->loops[0].mode = sustainLoopPlayMode; |
---|
260 | instrument->loops[0].beginMarker = sustainLoopBegin; |
---|
261 | instrument->loops[0].endMarker = sustainLoopEnd; |
---|
262 | |
---|
263 | instrument->loops[1].id = 2; |
---|
264 | instrument->loops[1].mode = releaseLoopPlayMode; |
---|
265 | instrument->loops[1].beginMarker = releaseLoopBegin; |
---|
266 | instrument->loops[1].endMarker = releaseLoopEnd; |
---|
267 | |
---|
268 | return AF_SUCCEED; |
---|
269 | } |
---|
270 | |
---|
271 | /* |
---|
272 | Parse marker chunks, which contain the positions and names of loop markers. |
---|
273 | */ |
---|
274 | static status ParseMARK (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, |
---|
275 | size_t size) |
---|
276 | { |
---|
277 | _Track *track; |
---|
278 | int i; |
---|
279 | u_int16_t numMarkers; |
---|
280 | |
---|
281 | assert(!memcmp(&type, "MARK", 4)); |
---|
282 | |
---|
283 | track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK); |
---|
284 | |
---|
285 | af_fread(&numMarkers, sizeof (u_int16_t), 1, fh); |
---|
286 | numMarkers = BENDIAN_TO_HOST_INT16(numMarkers); |
---|
287 | |
---|
288 | track->markerCount = numMarkers; |
---|
289 | if (numMarkers) |
---|
290 | track->markers = _af_marker_new(numMarkers); |
---|
291 | |
---|
292 | for (i=0; i<numMarkers; i++) |
---|
293 | { |
---|
294 | u_int16_t markerID = 0; |
---|
295 | u_int32_t markerPosition = 0; |
---|
296 | u_int8_t sizeByte = 0; |
---|
297 | char *markerName = NULL; |
---|
298 | |
---|
299 | af_fread(&markerID, sizeof (u_int16_t), 1, fh); |
---|
300 | markerID = BENDIAN_TO_HOST_INT16(markerID); |
---|
301 | af_fread(&markerPosition, sizeof (u_int32_t), 1, fh); |
---|
302 | markerPosition = BENDIAN_TO_HOST_INT32(markerPosition); |
---|
303 | af_fread(&sizeByte, sizeof (unsigned char), 1, fh); |
---|
304 | markerName = _af_malloc(sizeByte + 1); |
---|
305 | af_fread(markerName, sizeof (unsigned char), sizeByte, fh); |
---|
306 | |
---|
307 | markerName[sizeByte] = '\0'; |
---|
308 | |
---|
309 | #ifdef DEBUG |
---|
310 | printf("marker id: %d, position: %d, name: %s\n", |
---|
311 | markerID, markerPosition, markerName); |
---|
312 | |
---|
313 | printf("size byte: %d\n", sizeByte); |
---|
314 | #endif |
---|
315 | |
---|
316 | /* |
---|
317 | If sizeByte is even, then 1+sizeByte (the length |
---|
318 | of the string) is odd. Skip an extra byte to |
---|
319 | make it even. |
---|
320 | */ |
---|
321 | |
---|
322 | if ((sizeByte % 2) == 0) |
---|
323 | af_fseek(fh, 1, SEEK_CUR); |
---|
324 | |
---|
325 | track->markers[i].id = markerID; |
---|
326 | track->markers[i].position = markerPosition; |
---|
327 | track->markers[i].name = markerName; |
---|
328 | track->markers[i].comment = _af_strdup(""); |
---|
329 | } |
---|
330 | |
---|
331 | return AF_SUCCEED; |
---|
332 | } |
---|
333 | |
---|
334 | /* |
---|
335 | Parse common data chunks, which contain information regarding the |
---|
336 | sampling rate, the number of sample frames, and the number of |
---|
337 | sound channels. |
---|
338 | */ |
---|
339 | static status ParseCOMM (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, |
---|
340 | size_t size) |
---|
341 | { |
---|
342 | _Track *track; |
---|
343 | u_int16_t numChannels; |
---|
344 | u_int32_t numSampleFrames; |
---|
345 | u_int16_t sampleSize; |
---|
346 | unsigned char sampleRate[10]; |
---|
347 | |
---|
348 | assert(!memcmp(&type, "COMM", 4)); |
---|
349 | |
---|
350 | track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK); |
---|
351 | |
---|
352 | af_fread(&numChannels, sizeof (u_int16_t), 1, fh); |
---|
353 | track->f.channelCount = BENDIAN_TO_HOST_INT16(numChannels); |
---|
354 | |
---|
355 | af_fread(&numSampleFrames, sizeof (u_int32_t), 1, fh); |
---|
356 | track->totalfframes = BENDIAN_TO_HOST_INT32(numSampleFrames); |
---|
357 | |
---|
358 | af_fread(&sampleSize, sizeof (u_int16_t), 1, fh); |
---|
359 | track->f.sampleWidth = BENDIAN_TO_HOST_INT16(sampleSize); |
---|
360 | |
---|
361 | af_fread(sampleRate, 10, 1, fh); |
---|
362 | track->f.sampleRate = ConvertFromIeeeExtended(sampleRate); |
---|
363 | |
---|
364 | track->f.compressionType = AF_COMPRESSION_NONE; |
---|
365 | track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP; |
---|
366 | track->f.byteOrder = AF_BYTEORDER_BIGENDIAN; |
---|
367 | |
---|
368 | if (file->fileFormat == AF_FILE_AIFFC) |
---|
369 | { |
---|
370 | u_int8_t compressionID[4]; |
---|
371 | /* Pascal strings are at most 255 bytes long. */ |
---|
372 | unsigned char compressionName[256]; |
---|
373 | unsigned char compressionNameLength; |
---|
374 | |
---|
375 | af_fread(compressionID, 4, 1, fh); |
---|
376 | |
---|
377 | /* Read the Pascal-style string containing the name. */ |
---|
378 | af_fread(&compressionNameLength, 1, 1, fh); |
---|
379 | af_fread(compressionName, compressionNameLength, 1, fh); |
---|
380 | compressionName[compressionNameLength] = '\0'; |
---|
381 | |
---|
382 | if (!memcmp(compressionID, "NONE", 4)) |
---|
383 | track->f.compressionType = AF_COMPRESSION_NONE; |
---|
384 | else if (!memcmp(compressionID, "ACE2", 4) || |
---|
385 | !memcmp(compressionID, "ACE8", 4) || |
---|
386 | !memcmp(compressionID, "MAC3", 4) || |
---|
387 | !memcmp(compressionID, "MAC6", 4)) |
---|
388 | { |
---|
389 | _af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C format does not support Apple's proprietary %s compression format", compressionName); |
---|
390 | return AF_FAIL; |
---|
391 | } |
---|
392 | else if (!memcmp(compressionID, "ulaw", 4) || |
---|
393 | !memcmp(compressionID, "ULAW", 4)) |
---|
394 | { |
---|
395 | track->f.compressionType = AF_COMPRESSION_G711_ULAW; |
---|
396 | } |
---|
397 | else if (!memcmp(compressionID, "alaw", 4) || |
---|
398 | !memcmp(compressionID, "ALAW", 4)) |
---|
399 | { |
---|
400 | track->f.compressionType = AF_COMPRESSION_G711_ALAW; |
---|
401 | } |
---|
402 | else if (!memcmp(compressionID, "fl32", 4) || |
---|
403 | !memcmp(compressionID, "FL32", 4)) |
---|
404 | { |
---|
405 | track->f.sampleFormat = AF_SAMPFMT_FLOAT; |
---|
406 | track->f.sampleWidth = 32; |
---|
407 | track->f.compressionType = AF_COMPRESSION_NONE; |
---|
408 | } |
---|
409 | else if (!memcmp(compressionID, "fl64", 4) || |
---|
410 | !memcmp(compressionID, "FL64", 4)) |
---|
411 | { |
---|
412 | track->f.sampleFormat = AF_SAMPFMT_DOUBLE; |
---|
413 | track->f.sampleWidth = 64; |
---|
414 | track->f.compressionType = AF_COMPRESSION_NONE; |
---|
415 | } |
---|
416 | } |
---|
417 | |
---|
418 | _af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth); |
---|
419 | |
---|
420 | return AF_SUCCEED; |
---|
421 | } |
---|
422 | |
---|
423 | /* |
---|
424 | Parse the stored sound chunk, which usually contains little more |
---|
425 | than the sound data. |
---|
426 | */ |
---|
427 | static status ParseSSND (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, |
---|
428 | size_t size) |
---|
429 | { |
---|
430 | _Track *track; |
---|
431 | u_int32_t offset, blockSize; |
---|
432 | |
---|
433 | assert(!memcmp(&type, "SSND", 4)); |
---|
434 | |
---|
435 | track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK); |
---|
436 | |
---|
437 | af_fread(&offset, sizeof (u_int32_t), 1, fh); |
---|
438 | offset = BENDIAN_TO_HOST_INT32(offset); |
---|
439 | af_fread(&blockSize, sizeof (u_int32_t), 1, fh); |
---|
440 | blockSize = BENDIAN_TO_HOST_INT32(blockSize); |
---|
441 | |
---|
442 | /* |
---|
443 | This seems like a reasonable way to calculate the number of |
---|
444 | bytes in an SSND chunk. |
---|
445 | */ |
---|
446 | track->data_size = size - 8 - offset; |
---|
447 | |
---|
448 | #ifdef DEBUG |
---|
449 | printf("offset: %d\n", offset); |
---|
450 | printf("block size: %d\n", blockSize); |
---|
451 | #endif |
---|
452 | |
---|
453 | track->fpos_first_frame = af_ftell(fh) + offset; |
---|
454 | |
---|
455 | #ifdef DEBUG |
---|
456 | printf("data start: %d\n", track->fpos_first_frame); |
---|
457 | #endif |
---|
458 | |
---|
459 | /* Sound data follows. */ |
---|
460 | |
---|
461 | return AF_SUCCEED; |
---|
462 | } |
---|
463 | |
---|
464 | status _af_aiff_read_init (AFfilesetup setup, AFfilehandle file) |
---|
465 | { |
---|
466 | u_int32_t type, size, formtype; |
---|
467 | size_t index = 0; |
---|
468 | bool hasCOMM, hasFVER, hasSSND, hasMARK, hasINST; |
---|
469 | bool hasAESD, hasNAME, hasAUTH, hasCOPY; |
---|
470 | _Track *track; |
---|
471 | |
---|
472 | hasCOMM = AF_FALSE; |
---|
473 | hasFVER = AF_FALSE; |
---|
474 | hasSSND = AF_FALSE; |
---|
475 | hasMARK = AF_FALSE; |
---|
476 | hasINST = AF_FALSE; |
---|
477 | hasAESD = AF_FALSE; |
---|
478 | hasNAME = AF_FALSE; |
---|
479 | hasAUTH = AF_FALSE; |
---|
480 | hasCOPY = AF_FALSE; |
---|
481 | |
---|
482 | assert(file != NULL); |
---|
483 | assert(file->fh != NULL); |
---|
484 | |
---|
485 | af_fseek(file->fh, 0, SEEK_SET); |
---|
486 | |
---|
487 | af_fread(&type, 4, 1, file->fh); |
---|
488 | af_fread(&size, 4, 1, file->fh); |
---|
489 | size = BENDIAN_TO_HOST_INT32(size); |
---|
490 | af_fread(&formtype, 4, 1, file->fh); |
---|
491 | |
---|
492 | if (memcmp(&type, "FORM", 4) != 0 || |
---|
493 | (memcmp(&formtype, "AIFF", 4) && memcmp(&formtype, "AIFC", 4))) |
---|
494 | return AF_FAIL; |
---|
495 | |
---|
496 | #ifdef DEBUG |
---|
497 | printf("size: %d\n", size); |
---|
498 | #endif |
---|
499 | |
---|
500 | file->instrumentCount = 0; |
---|
501 | file->instruments = NULL; |
---|
502 | file->miscellaneousCount = 0; |
---|
503 | file->miscellaneous = NULL; |
---|
504 | |
---|
505 | /* AIFF files have only one track. */ |
---|
506 | track = _af_track_new(); |
---|
507 | file->trackCount = 1; |
---|
508 | file->tracks = track; |
---|
509 | |
---|
510 | /* Include the offset of the form type. */ |
---|
511 | index += 4; |
---|
512 | |
---|
513 | while (index < size) |
---|
514 | { |
---|
515 | u_int32_t chunkid = 0, chunksize = 0; |
---|
516 | |
---|
517 | #ifdef DEBUG |
---|
518 | printf("index: %d\n", index); |
---|
519 | #endif |
---|
520 | af_fread(&chunkid, 4, 1, file->fh); |
---|
521 | af_fread(&chunksize, 4, 1, file->fh); |
---|
522 | chunksize = BENDIAN_TO_HOST_INT32(chunksize); |
---|
523 | |
---|
524 | #ifdef DEBUG |
---|
525 | _af_printid(chunkid); |
---|
526 | printf(" size: %d\n", chunksize); |
---|
527 | #endif |
---|
528 | |
---|
529 | if (!memcmp("COMM", &chunkid, 4)) |
---|
530 | { |
---|
531 | hasCOMM = AF_TRUE; |
---|
532 | ParseCOMM(file, file->fh, chunkid, chunksize); |
---|
533 | } |
---|
534 | else if (!memcmp("FVER", &chunkid, 4)) |
---|
535 | { |
---|
536 | hasFVER = AF_TRUE; |
---|
537 | ParseFVER(file, file->fh, chunkid, chunksize); |
---|
538 | } |
---|
539 | else if (!memcmp("INST", &chunkid, 4)) |
---|
540 | { |
---|
541 | hasINST = AF_TRUE; |
---|
542 | ParseINST(file, file->fh, chunkid, chunksize); |
---|
543 | } |
---|
544 | else if (!memcmp("MARK", &chunkid, 4)) |
---|
545 | { |
---|
546 | hasMARK = AF_TRUE; |
---|
547 | ParseMARK(file, file->fh, chunkid, chunksize); |
---|
548 | } |
---|
549 | else if (!memcmp("AESD", &chunkid, 4)) |
---|
550 | { |
---|
551 | hasAESD = AF_TRUE; |
---|
552 | ParseAESD(file, file->fh, chunkid, chunksize); |
---|
553 | } |
---|
554 | else if (!memcmp("NAME", &chunkid, 4) || |
---|
555 | !memcmp("AUTH", &chunkid, 4) || |
---|
556 | !memcmp("(c) ", &chunkid, 4) || |
---|
557 | !memcmp("ANNO", &chunkid, 4) || |
---|
558 | !memcmp("APPL", &chunkid, 4) || |
---|
559 | !memcmp("MIDI", &chunkid, 4)) |
---|
560 | { |
---|
561 | ParseMiscellaneous(file, file->fh, chunkid, chunksize); |
---|
562 | } |
---|
563 | /* |
---|
564 | The sound data chunk is required if there are more than |
---|
565 | zero sample frames. |
---|
566 | */ |
---|
567 | else if (!memcmp("SSND", &chunkid, 4)) |
---|
568 | { |
---|
569 | if (hasSSND) |
---|
570 | { |
---|
571 | _af_error(AF_BAD_AIFF_SSND, "AIFF file has more than one SSND chunk"); |
---|
572 | return AF_FAIL; |
---|
573 | } |
---|
574 | hasSSND = AF_TRUE; |
---|
575 | ParseSSND(file, file->fh, chunkid, chunksize); |
---|
576 | } |
---|
577 | |
---|
578 | index += chunksize + 8; |
---|
579 | |
---|
580 | /* all chunks must be aligned on an even number of bytes */ |
---|
581 | if ((index % 2) != 0) |
---|
582 | index++; |
---|
583 | |
---|
584 | af_fseek(file->fh, index + 8, SEEK_SET); |
---|
585 | } |
---|
586 | |
---|
587 | if (!hasCOMM) |
---|
588 | { |
---|
589 | _af_error(AF_BAD_AIFF_COMM, "bad AIFF COMM chunk"); |
---|
590 | } |
---|
591 | |
---|
592 | /* The file has been successfully parsed. */ |
---|
593 | return AF_SUCCEED; |
---|
594 | } |
---|
595 | |
---|
596 | bool _af_aiff_recognize (AFvirtualfile *fh) |
---|
597 | { |
---|
598 | u_int8_t buffer[8]; |
---|
599 | |
---|
600 | af_fseek(fh, 0, SEEK_SET); |
---|
601 | |
---|
602 | if (af_fread(buffer, 1, 8, fh) != 8 || memcmp(buffer, "FORM", 4) != 0) |
---|
603 | return AF_FALSE; |
---|
604 | if (af_fread(buffer, 1, 4, fh) != 4 || memcmp(buffer, "AIFF", 4) != 0) |
---|
605 | return AF_FALSE; |
---|
606 | |
---|
607 | return AF_TRUE; |
---|
608 | } |
---|
609 | |
---|
610 | bool _af_aifc_recognize (AFvirtualfile *fh) |
---|
611 | { |
---|
612 | u_int8_t buffer[8]; |
---|
613 | |
---|
614 | af_fseek(fh, 0, SEEK_SET); |
---|
615 | |
---|
616 | if (af_fread(buffer, 1, 8, fh) != 8 || memcmp(buffer, "FORM", 4) != 0) |
---|
617 | return AF_FALSE; |
---|
618 | if (af_fread(buffer, 1, 4, fh) != 4 || memcmp(buffer, "AIFC", 4) != 0) |
---|
619 | return AF_FALSE; |
---|
620 | |
---|
621 | return AF_TRUE; |
---|
622 | } |
---|
623 | |
---|
624 | AFfilesetup _af_aiff_complete_setup (AFfilesetup setup) |
---|
625 | { |
---|
626 | _TrackSetup *track; |
---|
627 | |
---|
628 | bool isAIFF = setup->fileFormat == AF_FILE_AIFF; |
---|
629 | |
---|
630 | if (setup->trackSet && setup->trackCount != 1) |
---|
631 | { |
---|
632 | _af_error(AF_BAD_NUMTRACKS, "AIFF/AIFF-C file must have 1 track"); |
---|
633 | return AF_NULL_FILESETUP; |
---|
634 | } |
---|
635 | |
---|
636 | track = &setup->tracks[0]; |
---|
637 | |
---|
638 | if (track->sampleFormatSet) |
---|
639 | { |
---|
640 | if (track->f.sampleFormat == AF_SAMPFMT_UNSIGNED) |
---|
641 | { |
---|
642 | _af_error(AF_BAD_FILEFMT, "AIFF/AIFF-C format does not support unsigned data"); |
---|
643 | return AF_NULL_FILESETUP; |
---|
644 | } |
---|
645 | else if (isAIFF && track->f.sampleFormat != AF_SAMPFMT_TWOSCOMP) |
---|
646 | { |
---|
647 | _af_error(AF_BAD_FILEFMT, "AIFF format supports only two's complement integer data"); |
---|
648 | return AF_NULL_FILESETUP; |
---|
649 | } |
---|
650 | } |
---|
651 | else |
---|
652 | _af_set_sample_format(&track->f, AF_SAMPFMT_TWOSCOMP, |
---|
653 | track->f.sampleWidth); |
---|
654 | |
---|
655 | /* Check sample width if writing two's complement. Otherwise ignore. */ |
---|
656 | if (track->f.sampleFormat == AF_SAMPFMT_TWOSCOMP && |
---|
657 | (track->f.sampleWidth < 1 || track->f.sampleWidth > 32)) |
---|
658 | { |
---|
659 | _af_error(AF_BAD_WIDTH, |
---|
660 | "invalid sample width %d for AIFF/AIFF-C file " |
---|
661 | "(must be 1-32)", track->f.sampleWidth); |
---|
662 | return AF_NULL_FILESETUP; |
---|
663 | } |
---|
664 | |
---|
665 | if (isAIFF && track->f.compressionType != AF_COMPRESSION_NONE) |
---|
666 | { |
---|
667 | _af_error(AF_BAD_FILESETUP, |
---|
668 | "AIFF does not support compression; use AIFF-C"); |
---|
669 | return AF_NULL_FILESETUP; |
---|
670 | } |
---|
671 | |
---|
672 | /* XXXmpruett handle compression here */ |
---|
673 | |
---|
674 | if (track->byteOrderSet && |
---|
675 | track->f.byteOrder != AF_BYTEORDER_BIGENDIAN && |
---|
676 | track->f.sampleWidth > 8) |
---|
677 | { |
---|
678 | _af_error(AF_BAD_BYTEORDER, |
---|
679 | "AIFF/AIFF-C format supports only big-endian data"); |
---|
680 | } |
---|
681 | track->f.byteOrder = AF_BYTEORDER_BIGENDIAN; |
---|
682 | |
---|
683 | if (setup->instrumentSet) |
---|
684 | { |
---|
685 | if (setup->instrumentCount != 0 && setup->instrumentCount != 1) |
---|
686 | { |
---|
687 | _af_error(AF_BAD_NUMINSTS, "AIFF/AIFF-C file must have 0 or 1 instrument chunk"); |
---|
688 | return AF_NULL_FILESETUP; |
---|
689 | } |
---|
690 | if (setup->instruments != 0 && |
---|
691 | setup->instruments[0].loopCount != 2) |
---|
692 | { |
---|
693 | _af_error(AF_BAD_NUMLOOPS, "AIFF/AIFF-C file with instrument must also have 2 loops"); |
---|
694 | return AF_NULL_FILESETUP; |
---|
695 | } |
---|
696 | } |
---|
697 | |
---|
698 | if (setup->miscellaneousSet) |
---|
699 | { |
---|
700 | int i; |
---|
701 | for (i=0; i<setup->miscellaneousCount; i++) |
---|
702 | { |
---|
703 | switch (setup->miscellaneous[i].type) |
---|
704 | { |
---|
705 | case AF_MISC_COPY: |
---|
706 | case AF_MISC_AUTH: |
---|
707 | case AF_MISC_NAME: |
---|
708 | case AF_MISC_ANNO: |
---|
709 | case AF_MISC_APPL: |
---|
710 | case AF_MISC_MIDI: |
---|
711 | break; |
---|
712 | |
---|
713 | default: |
---|
714 | _af_error(AF_BAD_MISCTYPE, "invalid miscellaneous type %d for AIFF/AIFF-C file", setup->miscellaneous[i].type); |
---|
715 | return AF_NULL_FILESETUP; |
---|
716 | } |
---|
717 | } |
---|
718 | } |
---|
719 | |
---|
720 | return _af_filesetup_copy(setup, &_af_aiff_default_filesetup, AF_TRUE); |
---|
721 | } |
---|
722 | |
---|
723 | bool _af_aiff_instparam_valid (AFfilehandle filehandle, AUpvlist list, int i) |
---|
724 | { |
---|
725 | int param, type, lval; |
---|
726 | |
---|
727 | AUpvgetparam(list, i, ¶m); |
---|
728 | AUpvgetvaltype(list, i, &type); |
---|
729 | if (type != AU_PVTYPE_LONG) |
---|
730 | return AF_FALSE; |
---|
731 | |
---|
732 | AUpvgetval(list, i, &lval); |
---|
733 | |
---|
734 | switch (param) |
---|
735 | { |
---|
736 | case AF_INST_MIDI_BASENOTE: |
---|
737 | return ((lval >= 0) && (lval <= 127)); |
---|
738 | |
---|
739 | case AF_INST_NUMCENTS_DETUNE: |
---|
740 | return ((lval >= -50) && (lval <= 50)); |
---|
741 | |
---|
742 | case AF_INST_MIDI_LOVELOCITY: |
---|
743 | return ((lval >= 1) && (lval <= 127)); |
---|
744 | |
---|
745 | case AF_INST_MIDI_HIVELOCITY: |
---|
746 | return ((lval >= 1) && (lval <= 127)); |
---|
747 | |
---|
748 | case AF_INST_MIDI_LONOTE: |
---|
749 | return ((lval >= 0) && (lval <= 127)); |
---|
750 | |
---|
751 | case AF_INST_MIDI_HINOTE: |
---|
752 | return ((lval >= 0) && (lval <= 127)); |
---|
753 | |
---|
754 | case AF_INST_NUMDBS_GAIN: |
---|
755 | case AF_INST_SUSLOOPID: |
---|
756 | case AF_INST_RELLOOPID: |
---|
757 | return AF_TRUE; |
---|
758 | |
---|
759 | default: |
---|
760 | return AF_FALSE; |
---|
761 | break; |
---|
762 | } |
---|
763 | |
---|
764 | return AF_TRUE; |
---|
765 | } |
---|
766 | |
---|
767 | int _af_aifc_get_version (AFfilehandle file) |
---|
768 | { |
---|
769 | return AIFC_VERSION_1; |
---|
770 | } |
---|