InstrumentSetup *_af_instsetup_new (int instrumentCount) { InstrumentSetup *instruments; if (instrumentCount == 0) return NULL; instruments = (InstrumentSetup *) _af_calloc(instrumentCount, sizeof (InstrumentSetup)); if (instruments == NULL) return NULL; for (int i=0; i<instrumentCount; i++) { instruments[i] = _af_default_instrumentsetup; instruments[i].id = AF_DEFAULT_INST + i; if (instruments[i].loopCount == 0) instruments[i].loops = NULL; else { instruments[i].loops = (LoopSetup *) _af_calloc(instruments[i].loopCount, sizeof (LoopSetup)); if (instruments[i].loops == NULL) return NULL; for (int j=0; j<instruments[i].loopCount; j++) instruments[i].loops[j].id = j+1; } } return instruments; }
TrackSetup *_af_tracksetup_new (int trackCount) { TrackSetup *tracks; if (trackCount == 0) return NULL; tracks = (TrackSetup *) _af_calloc(trackCount, sizeof (TrackSetup)); if (tracks == NULL) return NULL; for (int i=0; i<trackCount; i++) { tracks[i] = _af_default_tracksetup; tracks[i].id = AF_DEFAULT_TRACK + i; /* XXXmpruett deal with compression */ _af_set_sample_format(&tracks[i].f, tracks[i].f.sampleFormat, tracks[i].f.sampleWidth); if (tracks[i].markerCount == 0) tracks[i].markers = NULL; else { tracks[i].markers = (MarkerSetup *) _af_calloc(tracks[i].markerCount, sizeof (MarkerSetup)); if (tracks[i].markers == NULL) return NULL; for (int j=0; j<tracks[i].markerCount; j++) { tracks[i].markers[j].id = j+1; tracks[i].markers[j].name = _af_strdup(""); if (tracks[i].markers[j].name == NULL) return NULL; tracks[i].markers[j].comment = _af_strdup(""); if (tracks[i].markers[j].comment == NULL) return NULL; } } } return tracks; }
void afInitMarkIDs(AFfilesetup setup, int trackid, const int *markids, int nmarks) { if (!_af_filesetup_ok(setup)) return; TrackSetup *track = setup->getTrack(trackid); if (!track) return; if (track->markers != NULL) { for (int i=0; i<track->markerCount; i++) { if (track->markers[i].name != NULL) free(track->markers[i].name); if (track->markers[i].comment != NULL) free(track->markers[i].comment); } free(track->markers); } track->markers = (MarkerSetup *) _af_calloc(nmarks, sizeof (struct MarkerSetup)); track->markerCount = nmarks; for (int i=0; i<nmarks; i++) { track->markers[i].id = markids[i]; track->markers[i].name = _af_strdup(""); track->markers[i].comment = _af_strdup(""); } track->markersSet = true; }
AFfilesetup afNewFileSetup (void) { AFfilesetup setup; setup = (_AFfilesetup *) _af_malloc(sizeof (_AFfilesetup)); if (setup == NULL) return AF_NULL_FILESETUP; *setup = _af_default_file_setup; setup->tracks = _af_tracksetup_new(setup->trackCount); setup->instruments = _af_instsetup_new(setup->instrumentCount); if (setup->miscellaneousCount == 0) setup->miscellaneous = NULL; else { setup->miscellaneous = (MiscellaneousSetup *) _af_calloc(setup->miscellaneousCount, sizeof (MiscellaneousSetup)); for (int i=0; i<setup->miscellaneousCount; i++) { setup->miscellaneous[i].id = i+1; setup->miscellaneous[i].type = 0; setup->miscellaneous[i].size = 0; } } return setup; }
void afInitLoopIDs (AFfilesetup setup, int instid, int *loopids, int nloops) { int instno; if (!_af_filesetup_ok(setup)) return; if (!_af_unique_ids(loopids, nloops, "loop", AF_BAD_LOOPID)) return; if ((instno = _af_setup_instrument_index_from_id(setup, instid)) == -1) return; _af_setup_free_loops(setup, instno); setup->instruments[instno].loopCount = nloops; setup->instruments[instno].loopSet = true; if (nloops == 0) setup->instruments[instno].loops = NULL; else { int i; if ((setup->instruments[instno].loops = _af_calloc(nloops, sizeof (_LoopSetup))) == NULL) return; for (i=0; i < nloops; i++) setup->instruments[instno].loops[i].id = loopids[i]; } }
bool InstrumentSetup::allocateLoops(int count) { freeLoops(); loops = (LoopSetup *) _af_calloc(count, sizeof (LoopSetup)); if (loops) { loopCount = count; return true; } return false; }
status WAVEFile::writeCues() { int *markids, markCount; uint32_t numCues, cueChunkSize, listChunkSize; markCount = afGetMarkIDs(this, AF_DEFAULT_TRACK, NULL); if (markCount == 0) return AF_SUCCEED; if (markOffset == 0) markOffset = fh->tell(); else fh->seek(markOffset, File::SeekFromBeginning); fh->write("cue ", 4); /* The cue chunk consists of 4 bytes for the number of cue points followed by 24 bytes for each cue point record. */ cueChunkSize = 4 + markCount * 24; writeU32(&cueChunkSize); numCues = markCount; writeU32(&numCues); markids = (int *) _af_calloc(markCount, sizeof (int)); assert(markids != NULL); afGetMarkIDs(this, AF_DEFAULT_TRACK, markids); /* Write each marker to the file. */ for (int i=0; i < markCount; i++) { uint32_t identifier, position, chunkStart, blockStart; uint32_t sampleOffset; AFframecount markposition; identifier = markids[i]; writeU32(&identifier); position = i; writeU32(&position); /* For now the RIFF id is always the first data chunk. */ fh->write("data", 4); /* For an uncompressed WAVE file which contains only one data chunk, chunkStart and blockStart are zero. */ chunkStart = 0; fh->write(&chunkStart, sizeof (uint32_t)); blockStart = 0; fh->write(&blockStart, sizeof (uint32_t)); markposition = afGetMarkPosition(this, AF_DEFAULT_TRACK, markids[i]); /* Sample offsets are stored in the WAVE file as frames. */ sampleOffset = markposition; writeU32(&sampleOffset); } /* Now write the cue names which is in a master list chunk with a subchunk for each cue's name. */ listChunkSize = 4; for (int i=0; i<markCount; i++) { const char *name; name = afGetMarkName(this, AF_DEFAULT_TRACK, markids[i]); /* Each label chunk consists of 4 bytes for the "labl" chunk ID, 4 bytes for the chunk data size, 4 bytes for the cue point ID, and then the length of the label as a Pascal-style string. In all, this is 12 bytes plus the length of the string, its size byte, and a trailing pad byte if the length of the chunk is otherwise odd. */ listChunkSize += 12 + (strlen(name) + 1) + ((strlen(name) + 1) % 2); } fh->write("LIST", 4); writeU32(&listChunkSize); fh->write("adtl", 4); for (int i=0; i<markCount; i++) { const char *name; uint32_t labelSize, cuePointID; name = afGetMarkName(this, AF_DEFAULT_TRACK, markids[i]); /* Make labelSize even if it is not already. */ labelSize = 4+(strlen(name)+1) + ((strlen(name) + 1) % 2); cuePointID = markids[i]; fh->write("labl", 4); writeU32(&labelSize); writeU32(&cuePointID); fh->write(name, strlen(name) + 1); /* If the name plus the size byte comprises an odd length, add another byte to make the string an even length. */ if (((strlen(name) + 1) % 2) != 0) { uint8_t zero=0; writeU8(&zero); } } free(markids); return AF_SUCCEED; }
static status WriteCues (AFfilehandle file) { int i, *markids, markCount; uint32_t numCues, cueChunkSize, listChunkSize; _WAVEInfo *wave; assert(file); markCount = afGetMarkIDs(file, AF_DEFAULT_TRACK, NULL); if (markCount == 0) return AF_SUCCEED; wave = file->formatSpecific; if (wave->markOffset == 0) wave->markOffset = af_ftell(file->fh); else af_fseek(file->fh, wave->markOffset, SEEK_SET); af_fwrite("cue ", 4, 1, file->fh); /* The cue chunk consists of 4 bytes for the number of cue points followed by 24 bytes for each cue point record. */ cueChunkSize = 4 + markCount * 24; af_write_uint32_le(&cueChunkSize, file->fh); numCues = markCount; af_write_uint32_le(&numCues, file->fh); markids = _af_calloc(markCount, sizeof (int)); assert(markids != NULL); afGetMarkIDs(file, AF_DEFAULT_TRACK, markids); /* Write each marker to the file. */ for (i=0; i < markCount; i++) { uint32_t identifier, position, chunkStart, blockStart; uint32_t sampleOffset; AFframecount markposition; identifier = markids[i]; af_write_uint32_le(&identifier, file->fh); position = i; af_write_uint32_le(&position, file->fh); /* For now the RIFF id is always the first data chunk. */ af_fwrite("data", 4, 1, file->fh); /* For an uncompressed WAVE file which contains only one data chunk, chunkStart and blockStart are zero. */ chunkStart = 0; af_fwrite(&chunkStart, sizeof (uint32_t), 1, file->fh); blockStart = 0; af_fwrite(&blockStart, sizeof (uint32_t), 1, file->fh); markposition = afGetMarkPosition(file, AF_DEFAULT_TRACK, markids[i]); /* Sample offsets are stored in the WAVE file as frames. */ sampleOffset = markposition; af_write_uint32_le(&sampleOffset, file->fh); } /* Now write the cue names which is in a master list chunk with a subchunk for each cue's name. */ listChunkSize = 4; for (i=0; i<markCount; i++) { const char *name; name = afGetMarkName(file, AF_DEFAULT_TRACK, markids[i]); /* Each label chunk consists of 4 bytes for the "labl" chunk ID, 4 bytes for the chunk data size, 4 bytes for the cue point ID, and then the length of the label as a Pascal-style string. In all, this is 12 bytes plus the length of the string, its size byte, and a trailing pad byte if the length of the chunk is otherwise odd. */ listChunkSize += 12 + (strlen(name) + 1) + ((strlen(name) + 1) % 2); } af_fwrite("LIST", 4, 1, file->fh); af_write_uint32_le(&listChunkSize, file->fh); af_fwrite("adtl", 4, 1, file->fh); for (i=0; i<markCount; i++) { const char *name; uint32_t labelSize, cuePointID; name = afGetMarkName(file, AF_DEFAULT_TRACK, markids[i]); /* Make labelSize even if it is not already. */ labelSize = 4+(strlen(name)+1) + ((strlen(name) + 1) % 2); cuePointID = markids[i]; af_fwrite("labl", 4, 1, file->fh); af_write_uint32_le(&labelSize, file->fh); af_write_uint32_le(&cuePointID, file->fh); af_fwrite(name, strlen(name) + 1, 1, file->fh); /* If the name plus the size byte comprises an odd length, add another byte to make the string an even length. */ if (((strlen(name) + 1) % 2) != 0) { uint8_t zero=0; af_write_uint8(&zero, file->fh); } } free(markids); return AF_SUCCEED; }
/* ARGSUSED3 */ AUpvlist _afQueryFileFormat (int arg1, int arg2, int arg3, int arg4) { switch (arg1) { /* The following select only on arg1. */ case AF_QUERY_ID_COUNT: { int count = 0, idx; for (idx = 0; idx < _AF_NUM_UNITS; idx++) if (_af_units[idx].implemented) count++; return _af_pv_long(count); } /* NOTREACHED */ break; case AF_QUERY_IDS: { int count = 0, idx; int *buffer; buffer = (int *) _af_calloc(_AF_NUM_UNITS, sizeof (int)); if (buffer == NULL) return AU_NULL_PVLIST; for (idx = 0; idx < _AF_NUM_UNITS; idx++) if (_af_units[idx].implemented) buffer[count++] = idx; if (count == 0) { free(buffer); return AU_NULL_PVLIST; } return _af_pv_pointer(buffer); } /* NOTREACHED */ break; /* The following select on arg2. */ case AF_QUERY_LABEL: if (arg2 < 0 || arg2 >= _AF_NUM_UNITS) return AU_NULL_PVLIST; return _af_pv_pointer(const_cast<char *>(_af_units[arg2].label)); case AF_QUERY_NAME: if (arg2 < 0 || arg2 >= _AF_NUM_UNITS) return AU_NULL_PVLIST; return _af_pv_pointer(const_cast<char *>(_af_units[arg2].name)); case AF_QUERY_DESC: if (arg2 < 0 || arg2 >= _AF_NUM_UNITS) return AU_NULL_PVLIST; return _af_pv_pointer(const_cast<char *>(_af_units[arg2].description)); case AF_QUERY_IMPLEMENTED: if (arg2 < 0 || arg2 >= _AF_NUM_UNITS) return _af_pv_long(0); return _af_pv_long(_af_units[arg2].implemented); /* The following select on arg3. */ case AF_QUERY_SAMPLE_FORMATS: if (arg3 < 0 || arg3 >= _AF_NUM_UNITS) return AU_NULL_PVLIST; switch (arg2) { case AF_QUERY_DEFAULT: return _af_pv_long(_af_units[arg3].defaultSampleFormat); default: break; } /* NOTREACHED */ break; case AF_QUERY_SAMPLE_SIZES: if (arg3 < 0 || arg3 >= _AF_NUM_UNITS) return AU_NULL_PVLIST; switch (arg2) { case AF_QUERY_DEFAULT: return _af_pv_long(_af_units[arg3].defaultSampleWidth); default: break; } /* NOTREACHED */ break; case AF_QUERY_COMPRESSION_TYPES: { int idx, count; int *buffer; if (arg3 < 0 || arg3 >= _AF_NUM_UNITS) { _af_error(AF_BAD_QUERY, "unrecognized file format %d", arg3); return AU_NULL_PVLIST; } switch (arg2) { case AF_QUERY_VALUE_COUNT: count = _af_units[arg3].compressionTypeCount; return _af_pv_long(count); case AF_QUERY_VALUES: count = _af_units[arg3].compressionTypeCount; if (count == 0) return AU_NULL_PVLIST; buffer = (int *) _af_calloc(count, sizeof (int)); if (buffer == NULL) return AU_NULL_PVLIST; for (idx = 0; idx < count; idx++) { buffer[idx] = _af_units[arg3].compressionTypes[idx]; } return _af_pv_pointer(buffer); } } break; } _af_error(AF_BAD_QUERY, "bad query selector"); return AU_NULL_PVLIST; }
/* ARGSUSED0 */ AUpvlist _afQueryCompression (int arg1, int arg2, int arg3, int arg4) { const CompressionUnit *unit = NULL; switch (arg1) { case AF_QUERY_ID_COUNT: { int count = 0; for (int i = 0; i < _AF_NUM_COMPRESSION; i++) if (_af_compression[i].implemented) count++; return _af_pv_long(count); } case AF_QUERY_IDS: { int *buf = (int *) _af_calloc(_AF_NUM_COMPRESSION, sizeof (int)); if (!buf) return AU_NULL_PVLIST; int count = 0; for (int i = 0; i < _AF_NUM_COMPRESSION; i++) { if (_af_compression[i].implemented) buf[count++] = _af_compression[i].compressionID; } return _af_pv_pointer(buf); } case AF_QUERY_IMPLEMENTED: unit = _af_compression_unit_from_id(arg2); if (!unit) return _af_pv_long(0); return _af_pv_long(unit->implemented); case AF_QUERY_NATIVE_SAMPFMT: unit = _af_compression_unit_from_id(arg2); if (!unit) return AU_NULL_PVLIST; return _af_pv_long(unit->nativeSampleFormat); case AF_QUERY_NATIVE_SAMPWIDTH: unit = _af_compression_unit_from_id(arg2); if (!unit) return AU_NULL_PVLIST; return _af_pv_long(unit->nativeSampleWidth); case AF_QUERY_LABEL: unit = _af_compression_unit_from_id(arg2); if (!unit) return AU_NULL_PVLIST; return _af_pv_pointer(const_cast<char *>(unit->label)); case AF_QUERY_NAME: unit = _af_compression_unit_from_id(arg2); if (!unit) return AU_NULL_PVLIST; return _af_pv_pointer(const_cast<char *>(unit->shortname)); case AF_QUERY_DESC: unit = _af_compression_unit_from_id(arg2); if (!unit) return AU_NULL_PVLIST; return _af_pv_pointer(const_cast<char *>(unit->name)); } _af_error(AF_BAD_QUERY, "unrecognized query selector %d\n", arg1); return AU_NULL_PVLIST; }
/* ARGSUSED3 */ AUpvlist _afQueryInstrumentParameter (int arg1, int arg2, int arg3, int arg4) { switch (arg1) { /* For the following query types, arg2 is the file format. */ case AF_QUERY_SUPPORTED: if (arg2 < 0 || arg2 >= _AF_NUM_UNITS) return AU_NULL_PVLIST; return _af_pv_long(_af_units[arg2].instrumentParameterCount != 0); case AF_QUERY_ID_COUNT: if (arg2 < 0 || arg2 >= _AF_NUM_UNITS) return AU_NULL_PVLIST; return _af_pv_long(_af_units[arg2].instrumentParameterCount); case AF_QUERY_IDS: { int count; int *buffer; if (arg2 < 0 || arg2 >= _AF_NUM_UNITS) return AU_NULL_PVLIST; count = _af_units[arg2].instrumentParameterCount; if (count == 0) return AU_NULL_PVLIST; buffer = (int *) _af_calloc(count, sizeof (int)); if (buffer == NULL) return AU_NULL_PVLIST; for (int i=0; i<count; i++) buffer[i] = _af_units[arg2].instrumentParameters[i].id; return _af_pv_pointer(buffer); } /* NOTREACHED */ break; /* For the next few query types, arg2 is the file format and arg3 is the instrument parameter id. */ case AF_QUERY_TYPE: { int idx; if (arg2 < 0 || arg2 >= _AF_NUM_UNITS) return AU_NULL_PVLIST; idx = _af_instparam_index_from_id(arg2, arg3); if (idx<0) return AU_NULL_PVLIST; return _af_pv_long(_af_units[arg2].instrumentParameters[idx].type); } case AF_QUERY_NAME: { int idx; if (arg2 < 0 || arg2 >= _AF_NUM_UNITS) return AU_NULL_PVLIST; idx = _af_instparam_index_from_id(arg2, arg3); if (idx < 0) return AU_NULL_PVLIST; return _af_pv_pointer(const_cast<char *>(_af_units[arg2].instrumentParameters[idx].name)); } case AF_QUERY_DEFAULT: { int idx; if (arg2 < 0 || arg2 >= _AF_NUM_UNITS) return AU_NULL_PVLIST; idx = _af_instparam_index_from_id(arg2, arg3); if (idx >= 0) { AUpvlist ret = AUpvnew(1); AUpvsetparam(ret, 0, _af_units[arg2].instrumentParameters[idx].id); AUpvsetvaltype(ret, 0, _af_units[arg2].instrumentParameters[idx].type); AUpvsetval(ret, 0, const_cast<AFPVu *>(&_af_units[arg2].instrumentParameters[idx].defaultValue)); return ret; } return AU_NULL_PVLIST; } } _af_error(AF_BAD_QUERY, "bad query selector"); return AU_NULL_PVLIST; }
/* Parse instrument chunks, which contain information about using sound data as a sampled instrument. */ static status ParseINST (AFfilehandle file, AFvirtualfile *fh, u_int32_t type, size_t size) { _Instrument *instrument; u_int8_t baseNote; int8_t detune; u_int8_t lowNote, highNote, lowVelocity, highVelocity; int16_t gain; u_int16_t sustainLoopPlayMode, sustainLoopBegin, sustainLoopEnd; u_int16_t releaseLoopPlayMode, releaseLoopBegin, releaseLoopEnd; assert(!memcmp(&type, "INST", 4)); instrument = _af_calloc(1, sizeof (_Instrument)); instrument->id = AF_DEFAULT_INST; instrument->values = _af_calloc(_AF_AIFF_NUM_INSTPARAMS, sizeof (AFPVu)); instrument->loopCount = 2; instrument->loops = _af_calloc(2, sizeof (_Loop)); file->instrumentCount = 1; file->instruments = instrument; af_fread(&baseNote, 1, 1, fh); af_fread(&detune, 1, 1, fh); af_fread(&lowNote, 1, 1, fh); af_fread(&highNote, 1, 1, fh); af_fread(&lowVelocity, 1, 1, fh); af_fread(&highVelocity, 1, 1, fh); af_fread(&gain, 2, 1, fh); gain = BENDIAN_TO_HOST_INT16(gain); #ifdef DEBUG printf("baseNote/detune/lowNote/highNote/lowVelocity/highVelocity/gain:" " %d %d %d %d %d %d %d\n", baseNote, detune, lowNote, highNote, lowVelocity, highVelocity, gain); #endif instrument->values[0].l = baseNote; instrument->values[1].l = detune; instrument->values[2].l = lowVelocity; instrument->values[3].l = highVelocity; instrument->values[4].l = lowNote; instrument->values[5].l = highNote; instrument->values[6].l = gain; instrument->values[7].l = 1; /* sustain loop id */ instrument->values[8].l = 2; /* release loop id */ af_fread(&sustainLoopPlayMode, sizeof (u_int16_t), 1, fh); sustainLoopPlayMode = BENDIAN_TO_HOST_INT16(sustainLoopPlayMode); af_fread(&sustainLoopBegin, sizeof (u_int16_t), 1, fh); sustainLoopBegin = BENDIAN_TO_HOST_INT16(sustainLoopBegin); af_fread(&sustainLoopEnd, sizeof (u_int16_t), 1, fh); sustainLoopEnd = BENDIAN_TO_HOST_INT16(sustainLoopEnd); af_fread(&releaseLoopPlayMode, sizeof (u_int16_t), 1, fh); releaseLoopPlayMode = BENDIAN_TO_HOST_INT16(releaseLoopPlayMode); af_fread(&releaseLoopBegin, sizeof (u_int16_t), 1, fh); releaseLoopBegin = BENDIAN_TO_HOST_INT16(releaseLoopBegin); af_fread(&releaseLoopEnd, sizeof (u_int16_t), 1, fh); releaseLoopEnd = BENDIAN_TO_HOST_INT16(releaseLoopEnd); #ifdef DEBUG printf("sustain loop: mode %d, begin %d, end %d\n", sustainLoopPlayMode, sustainLoopBegin, sustainLoopEnd); printf("release loop: mode %d, begin %d, end %d\n", releaseLoopPlayMode, releaseLoopBegin, releaseLoopEnd); #endif instrument->loops[0].id = 1; instrument->loops[0].mode = sustainLoopPlayMode; instrument->loops[0].beginMarker = sustainLoopBegin; instrument->loops[0].endMarker = sustainLoopEnd; instrument->loops[1].id = 2; instrument->loops[1].mode = releaseLoopPlayMode; instrument->loops[1].beginMarker = releaseLoopBegin; instrument->loops[1].endMarker = releaseLoopEnd; return AF_SUCCEED; }