/* Parse marker chunks, which contain the positions and names of loop markers. */ static status ParseMARK (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, size_t size) { _Track *track; int i; u_int16_t numMarkers; assert(!memcmp(&type, "MARK", 4)); track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK); af_fread(&numMarkers, sizeof (u_int16_t), 1, fh); numMarkers = BENDIAN_TO_HOST_INT16(numMarkers); track->markerCount = numMarkers; if (numMarkers) track->markers = _af_marker_new(numMarkers); for (i=0; i<numMarkers; i++) { u_int16_t markerID = 0; u_int32_t markerPosition = 0; u_int8_t sizeByte = 0; char *markerName = NULL; af_fread(&markerID, sizeof (u_int16_t), 1, fh); markerID = BENDIAN_TO_HOST_INT16(markerID); af_fread(&markerPosition, sizeof (u_int32_t), 1, fh); markerPosition = BENDIAN_TO_HOST_INT32(markerPosition); af_fread(&sizeByte, sizeof (unsigned char), 1, fh); markerName = _af_malloc(sizeByte + 1); af_fread(markerName, sizeof (unsigned char), sizeByte, fh); markerName[sizeByte] = '\0'; #ifdef DEBUG printf("marker id: %d, position: %d, name: %s\n", markerID, markerPosition, markerName); printf("size byte: %d\n", sizeByte); #endif /* If sizeByte is even, then 1+sizeByte (the length of the string) is odd. Skip an extra byte to make it even. */ if ((sizeByte % 2) == 0) af_fseek(fh, 1, SEEK_CUR); track->markers[i].id = markerID; track->markers[i].position = markerPosition; track->markers[i].name = markerName; track->markers[i].comment = _af_strdup(""); } return AF_SUCCEED; }
status af_read_uint32_be (uint32_t *value, AFvirtualfile *vf) { uint32_t v; if (af_fread(&v, sizeof (v), 1, vf) != 1) return AF_FAIL; *value = BENDIAN_TO_HOST_INT32(v); return AF_SUCCEED; }
/* FVER chunks are only present in AIFF-C files. */ static status ParseFVER (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, size_t size) { u_int32_t timestamp; assert(!memcmp(&type, "FVER", 4)); af_fread(×tamp, sizeof (u_int32_t), 1, fh); timestamp = BENDIAN_TO_HOST_INT32(timestamp); /* timestamp holds the number of seconds since January 1, 1904. */ return AF_SUCCEED; }
/* Parse the stored sound chunk, which usually contains little more than the sound data. */ static status ParseSSND (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, size_t size) { _Track *track; u_int32_t offset, blockSize; assert(!memcmp(&type, "SSND", 4)); track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK); af_fread(&offset, sizeof (u_int32_t), 1, fh); offset = BENDIAN_TO_HOST_INT32(offset); af_fread(&blockSize, sizeof (u_int32_t), 1, fh); blockSize = BENDIAN_TO_HOST_INT32(blockSize); /* This seems like a reasonable way to calculate the number of bytes in an SSND chunk. */ track->data_size = size - 8 - offset; #ifdef DEBUG printf("offset: %d\n", offset); printf("block size: %d\n", blockSize); #endif track->fpos_first_frame = af_ftell(fh) + offset; #ifdef DEBUG printf("data start: %d\n", track->fpos_first_frame); #endif /* Sound data follows. */ return AF_SUCCEED; }
status _af_aiff_read_init (AFfilesetup setup, AFfilehandle file) { u_int32_t type, size, formtype; size_t index = 0; bool hasCOMM, hasFVER, hasSSND, hasMARK, hasINST; bool hasAESD, hasNAME, hasAUTH, hasCOPY; _Track *track; hasCOMM = AF_FALSE; hasFVER = AF_FALSE; hasSSND = AF_FALSE; hasMARK = AF_FALSE; hasINST = AF_FALSE; hasAESD = AF_FALSE; hasNAME = AF_FALSE; hasAUTH = AF_FALSE; hasCOPY = AF_FALSE; assert(file != NULL); assert(file->fh != NULL); af_fseek(file->fh, 0, SEEK_SET); af_fread(&type, 4, 1, file->fh); af_fread(&size, 4, 1, file->fh); size = BENDIAN_TO_HOST_INT32(size); af_fread(&formtype, 4, 1, file->fh); if (memcmp(&type, "FORM", 4) != 0 || (memcmp(&formtype, "AIFF", 4) && memcmp(&formtype, "AIFC", 4))) return AF_FAIL; #ifdef DEBUG printf("size: %d\n", size); #endif file->instrumentCount = 0; file->instruments = NULL; file->miscellaneousCount = 0; file->miscellaneous = NULL; /* AIFF files have only one track. */ track = _af_track_new(); file->trackCount = 1; file->tracks = track; /* Include the offset of the form type. */ index += 4; while (index < size) { u_int32_t chunkid = 0, chunksize = 0; status result = AF_SUCCEED; #ifdef DEBUG printf("index: %d\n", index); #endif af_fread(&chunkid, 4, 1, file->fh); af_fread(&chunksize, 4, 1, file->fh); chunksize = BENDIAN_TO_HOST_INT32(chunksize); #ifdef DEBUG _af_printid(chunkid); printf(" size: %d\n", chunksize); #endif if (!memcmp("COMM", &chunkid, 4)) { hasCOMM = AF_TRUE; result = ParseCOMM(file, file->fh, chunkid, chunksize); } else if (!memcmp("FVER", &chunkid, 4)) { hasFVER = AF_TRUE; ParseFVER(file, file->fh, chunkid, chunksize); } else if (!memcmp("INST", &chunkid, 4)) { hasINST = AF_TRUE; ParseINST(file, file->fh, chunkid, chunksize); } else if (!memcmp("MARK", &chunkid, 4)) { hasMARK = AF_TRUE; ParseMARK(file, file->fh, chunkid, chunksize); } else if (!memcmp("AESD", &chunkid, 4)) { hasAESD = AF_TRUE; ParseAESD(file, file->fh, chunkid, chunksize); } else if (!memcmp("NAME", &chunkid, 4) || !memcmp("AUTH", &chunkid, 4) || !memcmp("(c) ", &chunkid, 4) || !memcmp("ANNO", &chunkid, 4) || !memcmp("APPL", &chunkid, 4) || !memcmp("MIDI", &chunkid, 4)) { ParseMiscellaneous(file, file->fh, chunkid, chunksize); } /* The sound data chunk is required if there are more than zero sample frames. */ else if (!memcmp("SSND", &chunkid, 4)) { if (hasSSND) { _af_error(AF_BAD_AIFF_SSND, "AIFF file has more than one SSND chunk"); return AF_FAIL; } hasSSND = AF_TRUE; result = ParseSSND(file, file->fh, chunkid, chunksize); } if (result == AF_FAIL) return AF_FAIL; index += chunksize + 8; /* all chunks must be aligned on an even number of bytes */ if ((index % 2) != 0) index++; af_fseek(file->fh, index + 8, SEEK_SET); } if (!hasCOMM) { _af_error(AF_BAD_AIFF_COMM, "bad AIFF COMM chunk"); } /* The file has been successfully parsed. */ return AF_SUCCEED; }
/* Parse common data chunks, which contain information regarding the sampling rate, the number of sample frames, and the number of sound channels. */ static status ParseCOMM (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, size_t size) { _Track *track; u_int16_t numChannels; u_int32_t numSampleFrames; u_int16_t sampleSize; unsigned char sampleRate[10]; assert(!memcmp(&type, "COMM", 4)); track = _af_filehandle_get_track(file, AF_DEFAULT_TRACK); af_fread(&numChannels, sizeof (u_int16_t), 1, fh); track->f.channelCount = BENDIAN_TO_HOST_INT16(numChannels); af_fread(&numSampleFrames, sizeof (u_int32_t), 1, fh); track->totalfframes = BENDIAN_TO_HOST_INT32(numSampleFrames); af_fread(&sampleSize, sizeof (u_int16_t), 1, fh); track->f.sampleWidth = BENDIAN_TO_HOST_INT16(sampleSize); af_fread(sampleRate, 10, 1, fh); track->f.sampleRate = _af_convert_from_ieee_extended(sampleRate); track->f.compressionType = AF_COMPRESSION_NONE; track->f.sampleFormat = AF_SAMPFMT_TWOSCOMP; track->f.byteOrder = AF_BYTEORDER_BIGENDIAN; if (file->fileFormat == AF_FILE_AIFFC) { u_int8_t compressionID[4]; /* Pascal strings are at most 255 bytes long. */ unsigned char compressionName[256]; unsigned char compressionNameLength; af_fread(compressionID, 4, 1, fh); /* Read the Pascal-style string containing the name. */ af_fread(&compressionNameLength, 1, 1, fh); af_fread(compressionName, compressionNameLength, 1, fh); compressionName[compressionNameLength] = '\0'; if (!memcmp(compressionID, "NONE", 4)) track->f.compressionType = AF_COMPRESSION_NONE; else if (!memcmp(compressionID, "ACE2", 4) || !memcmp(compressionID, "ACE8", 4) || !memcmp(compressionID, "MAC3", 4) || !memcmp(compressionID, "MAC6", 4)) { _af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C format does not support Apple's proprietary %s compression format", compressionName); return AF_FAIL; } else if (!memcmp(compressionID, "ulaw", 4) || !memcmp(compressionID, "ULAW", 4)) { track->f.compressionType = AF_COMPRESSION_G711_ULAW; } else if (!memcmp(compressionID, "alaw", 4) || !memcmp(compressionID, "ALAW", 4)) { track->f.compressionType = AF_COMPRESSION_G711_ALAW; } else if (!memcmp(compressionID, "fl32", 4) || !memcmp(compressionID, "FL32", 4)) { track->f.sampleFormat = AF_SAMPFMT_FLOAT; track->f.sampleWidth = 32; track->f.compressionType = AF_COMPRESSION_NONE; } else if (!memcmp(compressionID, "fl64", 4) || !memcmp(compressionID, "FL64", 4)) { track->f.sampleFormat = AF_SAMPFMT_DOUBLE; track->f.sampleWidth = 64; track->f.compressionType = AF_COMPRESSION_NONE; } else if (!memcmp(compressionID, "sowt", 4)) { track->f.compressionType = AF_COMPRESSION_NONE; track->f.byteOrder = AF_BYTEORDER_LITTLEENDIAN; } else { _af_error(AF_BAD_NOT_IMPLEMENTED, "AIFF-C compression type '%c%c%c%c' not currently supported", compressionID[0], compressionID[1], compressionID[2], compressionID[3]); return AF_FAIL; } } _af_set_sample_format(&track->f, track->f.sampleFormat, track->f.sampleWidth); return AF_SUCCEED; }