source: trunk/third/audiofile/libaudiofile/aiff.c @ 17099

Revision 17099, 20.4 KB checked in by ghudson, 23 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17098, which included commits to RCS files with non-trunk default branches.
Line 
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
48static status ParseFVER (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
49        size_t size);
50static status ParseAESD (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
51        size_t size);
52static status ParseMiscellaneous (AFfilehandle file, AFvirtualfile *fh,
53        u_int32_t type, size_t size);
54static status ParseINST (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
55        size_t size);
56static status ParseMARK (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
57        size_t size);
58static status ParseCOMM (AFfilehandle file, AFvirtualfile *fh, u_int32_t type,
59        size_t size);
60static 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
76int _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*/
100static 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(&timestamp, 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*/
116static 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*/
144static 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*/
186static 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*/
274static 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*/
339static 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*/
427static 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
464status _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
596bool _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
610bool _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
624AFfilesetup _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
723bool _af_aiff_instparam_valid (AFfilehandle filehandle, AUpvlist list, int i)
724{
725        int     param, type, lval;
726
727        AUpvgetparam(list, i, &param);
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
767int _af_aifc_get_version (AFfilehandle file)
768{
769        return AIFC_VERSION_1;
770}
Note: See TracBrowser for help on using the repository browser.