/* ** Return the number of INST's and an array of resource IDs */ short int XGetInstrumentArray(XShortResourceID *instArray, short maxArraySize) { short int icount, totalCount; long size; XPTR theRes; /* Collect INST resources */ totalCount = 0; if (instArray) { for (icount = 0; icount < maxArraySize; icount++) { theRes = XGetAndDetachResource(ID_INST, icount, &size); if (theRes) { XDisposePtr(theRes); instArray[totalCount++] = (XShortResourceID)icount; if (totalCount > maxArraySize) { totalCount = maxArraySize; break; } } } XBubbleSortArray((short *)instArray, (short)totalCount); } return totalCount; }
XBOOL XIsSampleUsedInAllInstruments(XShortResourceID soundSampleID, XShortResourceID *pWhichInstrument) { InstrumentResource *theX; short int count, totalInstruments; XBOOL used; long size; XShortResourceID instArray[MAX_INSTRUMENTS * MAX_BANKS]; used = FALSE; totalInstruments = XGetInstrumentArray(instArray, MAX_INSTRUMENTS * MAX_BANKS); if (totalInstruments && pWhichInstrument) { for (count = 0; count < totalInstruments; count++) { theX = (InstrumentResource *)XGetAndDetachResource(ID_INST, instArray[count], &size); if (theX) { used = XIsSoundUsedInInstrument(theX, soundSampleID); XDisposePtr((XPTR)theX); if (used) { *pWhichInstrument = instArray[count]; break; } } } } return used; }
XShortResourceID XCheckValidInstrument(XShortResourceID theID) { InstrumentResource *theX; short int totalSnds; XShortResourceID sndArray[MAX_SAMPLES]; short int count; XShortResourceID badLoad; XPTR theSnd; long size; badLoad = 0; theX = (InstrumentResource *)XGetAndDetachResource(ID_INST, theID, &size); if (theX) { totalSnds = XCollectSoundsFromInstrument(theX, sndArray, MAX_SAMPLES); XDisposePtr((XPTR)theX); for (count = 0; count < totalSnds; count++) { theSnd = XGetAndDetachResource(ID_CSND, sndArray[count], &size); // look for compressed version first if (theSnd == NULL) { theSnd = XGetAndDetachResource(ID_SND, sndArray[count], &size); } if (theSnd == NULL) { theSnd = XGetAndDetachResource(ID_ESND, sndArray[count], &size); } if (theSnd == NULL) { badLoad = sndArray[count]; } XDisposePtr(theSnd); if (badLoad) { break; } } } return badLoad; }
short int XCollectSoundsFromInstrumentID(XShortResourceID theID, XShortResourceID *sndArray, short maxArraySize) { InstrumentResource *theX; short int totalSnds; long size; totalSnds = 0; theX = (InstrumentResource *)XGetAndDetachResource(ID_INST, theID, &size); if (theX) { totalSnds = XCollectSoundsFromInstrument(theX, sndArray, maxArraySize); XDisposePtr((XPTR)theX); } return totalSnds; }
// This will return a MIDI/CMID/EMID/ECMI object from an open resource file // // INPUT: // theXSong is the SongResource structure // // OUTPUT: // pMusicName is a pascal string // pMusicType is the resource type // pMusicID is the resource ID // pReturnedSize is the resource size XPTR XGetMusicObjectFromSong(SongResource *theXSong, char *pMusicName, XResourceType *pMusicType, XLongResourceID *pMusicID, long *pReturnedSize) { long musicID; SongType songType; XPTR data; XResourceType midiTypes[] = {ID_MIDI, ID_MIDI_OLD, ID_CMID, ID_EMID, ID_ECMI}; short int count; data = NULL; if (pReturnedSize) { *pReturnedSize = 0; } if (pMusicName) { pMusicName[0] = 0; } if (theXSong) { *pMusicType = 0; *pMusicID = 0; musicID = XGetSongResourceObjectID(theXSong); songType = XGetSongResourceObjectType(theXSong); for (count = 0; count < (sizeof(midiTypes) / sizeof(long)); count++) { data = XGetAndDetachResource(midiTypes[count], musicID, pReturnedSize); if (data) { if (pMusicName) { XGetResourceName(midiTypes[count], musicID, pMusicName); XCtoPstr(pMusicName); } *pMusicType = midiTypes[count]; *pMusicID = musicID; break; } } } return data; }
// Given an array of instruments, this will return an array of SND resources that are required to load // these instruments short int XGetTotalKeysplits(XShortResourceID *instArray, short int totalInstruments, XShortResourceID *sndArray, short int totalSnds) { register short int count, count2, count3, count4, keyCount; KeySplit theSplit; InstrumentResource *theInstrument; char *pLoaded; long size; keyCount = 0; if (instArray && totalInstruments && sndArray && totalSnds) { pLoaded = (char *)XNewPtr((long)sizeof(char) * totalSnds); if (pLoaded) { for (count = 0; count < totalInstruments; count++) { theInstrument = (InstrumentResource *)XGetAndDetachResource(ID_INST, instArray[count], &size); if (theInstrument) { count3 = (short)XGetShort(&theInstrument->keySplitCount); for (count2 = 0; count2 < count3; count2++) { XGetKeySplitFromPtr(theInstrument, count2, &theSplit); count4 = PV_ConvertResourceID2Index(sndArray, totalSnds, theSplit.sndResourceID); if (count4) { if (pLoaded[count4] == 0) { pLoaded[count4] = 1; keyCount++; } } } } } XDisposePtr((XPTR)pLoaded); } } return keyCount; }
// Instruments 0 to MAX_INSTRUMENTS*MAX_BANKS are the standard MIDI instrument placements. // This will create an internal instrument from and external instrument. If theX is non-null then it // will use that data to create the GM_Instrument GM_Instrument * PV_GetInstrument(XLongResourceID theID, void *theExternalX, INT32 patchSize) { GM_Instrument *theI, *theS; InstrumentResource *theX; INT32 size; short int count; UBYTE *theSound; KeySplit theXSplit; CacheSampleInfo sndInfo; LOOPCOUNT i; INT32 theSampleID; theI = NULL; theX = (InstrumentResource *)theExternalX; if (theExternalX == NULL) { theX = (InstrumentResource *)XGetAndDetachResource(ID_INST, theID, &patchSize); } if (theX) { if (XGetShort(&theX->keySplitCount) < 2) // if its 1, then it has no splits { // get the sample ID from a short, values can be negative // then allow conversion to take place. // NOTE: I know this is awfull, but if you change it things will break. The // internal ID values are all 32 bit signed, and some of the external // file structures are 16 bit signed. theSampleID = (INT32)((short)XGetShort(&theX->sndResourceID)); theSound = (UBYTE *)PV_GetSampleFromID((INT32)theSampleID, &sndInfo); if (theSound) { theI = (GM_Instrument *)XNewPtr((INT32)sizeof(GM_Instrument)); if (theI) { theI->u.w.theWaveform = (SBYTE *)theSound; theI->disableSndLooping = TEST_FLAG_VALUE(theX->flags1, ZBF_disableSndLooping); theI->playAtSampledFreq = TEST_FLAG_VALUE(theX->flags2, ZBF_playAtSampledFreq); theI->doKeymapSplit = FALSE; theI->notPolyphonic = TEST_FLAG_VALUE(theX->flags2, ZBF_notPolyphonic); theI->avoidReverb = TEST_FLAG_VALUE(theX->flags1, ZBF_avoidReverb); theI->useSampleRate = TEST_FLAG_VALUE(theX->flags1, ZBF_useSampleRate); theI->sampleAndHold = TEST_FLAG_VALUE(theX->flags1, ZBF_sampleAndHold); theI->useSoundModifierAsRootKey = TEST_FLAG_VALUE(theX->flags2, ZBF_useSoundModifierAsRootKey); PV_GetEnvelopeData(theX, theI, patchSize); // get envelope theI->u.w.bitSize = sndInfo.bitSize; theI->u.w.channels = sndInfo.channels; theI->u.w.waveformID = XGetShort(&theX->sndResourceID); theI->u.w.waveSize = sndInfo.waveSize; theI->u.w.waveFrames = sndInfo.waveFrames; theI->u.w.startLoop = sndInfo.loopStart; theI->u.w.endLoop = sndInfo.loopEnd; theI->masterRootKey = XGetShort(&theX->midiRootKey); theI->panPlacement = theX->panPlacement; theI->u.w.baseMidiPitch = (unsigned char)sndInfo.baseKey; theI->u.w.sampledRate = sndInfo.rate; // NOTE!! If ZBF_useSoundModifierAsRootKey is TRUE, then we are using // the Sound Modifier data blocks as a root key replacement for samples in // the particular split theI->miscParameter1 = XGetShort(&theX->miscParameter1); theI->miscParameter2 = XGetShort(&theX->miscParameter2); if (theI->useSoundModifierAsRootKey) { theI->enableSoundModifier = FALSE; if (theI->miscParameter2 == 0) // Forces a default value of 0 to 100 { theI->miscParameter2 = 100; } } else { theI->enableSoundModifier = TEST_FLAG_VALUE(theX->flags2, ZBF_enableSoundModifier); theI->smodResourceID = theX->smodResourceID; // Process sample in place if ( (theI->enableSoundModifier) && (theI->u.w.bitSize == 8) && (theI->u.w.channels == 1) ) { #if DISPLAY_INSTRUMENTS DPrint(drawDebug, "---->Processing instrument %ld with SMOD %ld\r", (INT32)theID, (INT32)theI->smodResourceID); #endif PV_ProcessSampleWithSMOD(theI->u.w.theWaveform, theI->u.w.waveSize, theI->u.w.waveformID, theI->smodResourceID, theI->miscParameter1, theI->miscParameter2); } } } } } else { // Keysplits #if DISPLAY_INSTRUMENTS DPrint(drawDebug, "----->Processing %ld keysplits\r", (INT32)XGetShort(&theX->keySplitCount)); #endif size = XGetShort(&theX->keySplitCount) * (INT32)sizeof(GM_KeymapSplit); size += (INT32)sizeof(GM_KeymapSplitInfo); theI = (GM_Instrument *)XNewPtr(size + (INT32)sizeof(GM_Instrument)); if (theI) { theI->disableSndLooping = TEST_FLAG_VALUE(theX->flags1, ZBF_disableSndLooping); theI->doKeymapSplit = TRUE; theI->notPolyphonic = TEST_FLAG_VALUE(theX->flags2, ZBF_notPolyphonic); theI->avoidReverb = TEST_FLAG_VALUE(theX->flags1, ZBF_avoidReverb); theI->useSampleRate = TEST_FLAG_VALUE(theX->flags1, ZBF_useSampleRate); theI->sampleAndHold = TEST_FLAG_VALUE(theX->flags1, ZBF_sampleAndHold); theI->playAtSampledFreq = TEST_FLAG_VALUE(theX->flags2, ZBF_playAtSampledFreq); theI->useSoundModifierAsRootKey = TEST_FLAG_VALUE(theX->flags2, ZBF_useSoundModifierAsRootKey); PV_GetEnvelopeData(theX, theI, patchSize); // get envelope theI->u.k.KeymapSplitCount = XGetShort(&theX->keySplitCount); theI->u.k.defaultInstrumentID = (XShortResourceID)XGetShort(&theX->sndResourceID); theI->masterRootKey = XGetShort(&theX->midiRootKey); theI->panPlacement = theX->panPlacement; // NOTE!! If ZBF_useSoundModifierAsRootKey is TRUE, then we are using // the Sound Modifier data blocks as a root key replacement for samples in // the particular split theI->miscParameter1 = XGetShort(&theX->miscParameter1); theI->miscParameter2 = XGetShort(&theX->miscParameter2); if (theI->useSoundModifierAsRootKey) { theI->enableSoundModifier = FALSE; if (theI->miscParameter2 == 0) // Forces a default value of 0 to 100 { theI->miscParameter2 = 100; } } else { theI->enableSoundModifier = TEST_FLAG_VALUE(theX->flags2, ZBF_enableSoundModifier); theI->smodResourceID = theX->smodResourceID; } for (count = 0; count < theI->u.k.KeymapSplitCount; count++) { XGetKeySplitFromPtr(theX, count, &theXSplit); theI->u.k.keySplits[count].lowMidi = theXSplit.lowMidi; theI->u.k.keySplits[count].highMidi = theXSplit.highMidi; theI->u.k.keySplits[count].miscParameter1 = theXSplit.miscParameter1; if (theI->useSoundModifierAsRootKey && (theXSplit.miscParameter2 == 0)) // Forces a default value of 0 to 100 { theXSplit.miscParameter2 = 100; } theI->u.k.keySplits[count].miscParameter2 = theXSplit.miscParameter2; // if (GM_IsInstrumentRangeUsed(theID, (INT16)theXSplit.lowMidi, (INT16)theXSplit.highMidi)) { #if DISPLAY_INSTRUMENTS DPrint(drawDebug, "------->Keysplit %ld low %ld high %ld\r", (INT32)count, (INT32)theXSplit.lowMidi, (INT32)theXSplit.highMidi); #endif theS = PV_CreateInstrumentFromResource(theI, (XLongResourceID)theXSplit.sndResourceID); theI->u.k.keySplits[count].pSplitInstrument = theS; if (theS) { theS->useSoundModifierAsRootKey = theI->useSoundModifierAsRootKey; theS->miscParameter1 = theXSplit.miscParameter1; if (theS->useSoundModifierAsRootKey && (theXSplit.miscParameter2 == 0)) // Forces a default value of 0 to 100 { theXSplit.miscParameter2 = 100; } theS->miscParameter2 = theXSplit.miscParameter2; theS->masterRootKey = theI->masterRootKey; theS->avoidReverb = theI->avoidReverb; theS->volumeADSRRecord = theI->volumeADSRRecord; for (i = 0; i < theI->LFORecordCount; i++) { theS->LFORecords[i] = theI->LFORecords[i]; } theS->LFORecordCount = theI->LFORecordCount; for (i = 0; i < theI->curveRecordCount; i++) { theS->curve[i] = theI->curve[i]; } theS->curveRecordCount = theI->curveRecordCount; theS->LPF_frequency = theI->LPF_frequency; theS->LPF_resonance = theI->LPF_resonance; theS->LPF_lowpassAmount = theI->LPF_lowpassAmount; if (theS->useSoundModifierAsRootKey == FALSE) { // Process sample in place if ( (theS->enableSoundModifier) && (theS->u.w.bitSize == 8) && (theS->u.w.channels == 1) ) { #if DISPLAY_INSTRUMENTS DPrint(drawDebug, "----->Processing instrument %ld with SMOD %ld\r", (INT32)theID, (INT32)theI->smodResourceID); #endif PV_ProcessSampleWithSMOD( theS->u.w.theWaveform, theS->u.w.waveSize, theXSplit.sndResourceID, theS->smodResourceID, theS->miscParameter1, theS->miscParameter2); } } } } } } } if (theExternalX == NULL) { XDisposePtr((XPTR)theX); } } #if DISPLAY_INSTRUMENTS if (theI) { DPrint(drawDebug, "-------->INST info: masterRootKey %ld\r", (INT32)theI->masterRootKey); } #endif return theI; }
XERR XCopySndResources(XShortResourceID *pSndCopy, short int sndCount, XFILE readFileRef, XFILE writeFileRef, XBOOL protect, XBOOL copyNames) { short int count, resCount; XPTR pData; short int theID; char theName[256]; long size; long soundTypes[] = {ID_SND, ID_ESND, ID_CSND}; if (sndCount && pSndCopy) { XFileUseThisResourceFile(readFileRef); /* from resource file */ for (count = 0; count < sndCount; count++) { theID = pSndCopy[count]; // determine if the resource is already in the written file XFileUseThisResourceFile(writeFileRef); pData = XGetAndDetachResource(ID_SND, theID, &size); if (pData == NULL) { pData = XGetAndDetachResource(ID_ESND, theID, &size); } if (pData == NULL) { pData = XGetAndDetachResource(ID_CSND, theID, &size); } XDisposePtr(pData); if (pData == NULL) // check to see that its not there already!! { for (resCount = 0; resCount < 3; resCount++) { XFileUseThisResourceFile(readFileRef); /* from resource file */ pData = XGetFileResource(readFileRef, soundTypes[resCount], theID, theName, &size); if (pData) { if (copyNames == FALSE) { theName[0] = 0; } XFileUseThisResourceFile(writeFileRef); if (protect && (soundTypes[resCount] == ID_SND)) { XEncryptData(pData, size); XAddResource(ID_ESND, theID, theName, pData, size); } else { XAddResource(soundTypes[resCount], theID, theName, pData, size); } XDisposePtr(pData); } } } else { XDisposePtr(pData); } } } return 0; }
// Given a song ID and two arrays, this will return the INST resources ID and the 'snd ' resource ID // that are needed to load the song terminated with a -1. // Will return 0 for success or 1 for failure OPErr XGetSongInstrumentList(XShortResourceID theSongID, XShortResourceID *pInstArray, short int maxInstArraySize, XShortResourceID *pSndArray, short int maxSndArraySize) { long count, instCount, sndCount, newCount, completeSndCount; XShortResourceID soundID; SongResource *theSong; XShortResourceID completeSndArray[MAX_SAMPLES]; XShortResourceID completeInstArray[MAX_INSTRUMENTS * MAX_BANKS]; XBOOL goodSound; OPErr theErr; long size; theErr = NO_ERR; if ( (pInstArray) && (pSndArray) ) { for (count = 0; count < maxInstArraySize; count++) { pInstArray[count] = (XShortResourceID)-1; completeInstArray[count] = (XShortResourceID)-1; } for (count = 0; count < maxSndArraySize; count++) { pSndArray[count] = (XShortResourceID)-1; completeSndArray[count] = (XShortResourceID)-1; } theSong = (SongResource *)XGetAndDetachResource(ID_SONG, theSongID, &size); if (theSong) { instCount = GM_GetUsedPatchlist(theSong, NULL, 0L, completeInstArray, &theErr); if (instCount && (theErr == 0) ) { // remove duplicates in inst sndCount = 0; for (newCount = 0; newCount < instCount; newCount++) { goodSound = TRUE; soundID = completeInstArray[newCount]; for (count = 0; count < sndCount; count++) { if (soundID == pInstArray[count]) { goodSound = FALSE; break; } } if (goodSound) { pInstArray[sndCount++] = (XShortResourceID)soundID; } } instCount = sndCount; XBubbleSortArray((short *)pInstArray, (short)instCount); completeSndCount = 0; for (count = 0; count < instCount; count++) { newCount = XCollectSoundsFromInstrumentID(pInstArray[count], &completeSndArray[completeSndCount], 128); completeSndCount += newCount; } // remove duplicates in snds sndCount = 0; for (newCount = 0; newCount < completeSndCount; newCount++) { goodSound = TRUE; soundID = completeSndArray[newCount]; for (count = 0; count < sndCount; count++) { if (soundID == pSndArray[count]) { goodSound = FALSE; break; } } if (goodSound) { pSndArray[sndCount++] = (XShortResourceID)soundID; } } XBubbleSortArray((short *)pSndArray, (short)sndCount); } else { theErr = BAD_MIDI_DATA; } } XDisposePtr((XPTR)theSong); } return theErr; }
// Given a list of instruments, this will return the sample ID's that are required to load // all of these instruments short int XGetSamplesFromInstruments(XShortResourceID *pInstArray, short int maxInstArraySize, XShortResourceID *pSndArray, short int maxSndArraySize) { register long count, instCount, sndCount, newCount, completeSndCount; XShortResourceID soundID; XShortResourceID *completeSndArray; XBOOL goodSound; InstrumentResource *theX; long size; sndCount = 0; completeSndArray = (XShortResourceID *)XNewPtr(sizeof(XShortResourceID) * MAX_INSTRUMENTS * 128L); if (completeSndArray) { if ( (pInstArray) && (pSndArray) ) { instCount = 0; for (count = 0; count < maxInstArraySize; count++) { if (pInstArray[count] != (XShortResourceID)-1) { instCount++; } else { break; } } for (count = 0; count < maxSndArraySize; count++) { pSndArray[count] = (XShortResourceID)-1; completeSndArray[count] = (XShortResourceID)-1; } completeSndCount = 0; for (count = 0; count < instCount; count++) { theX = (InstrumentResource *)XGetAndDetachResource(ID_INST, pInstArray[count], &size); if (theX) { newCount = XCollectSoundsFromInstrument(theX, &completeSndArray[completeSndCount], 128); XDisposePtr((XPTR)theX); completeSndCount += newCount; } } // remove duplicates in snds for (newCount = 0; newCount < completeSndCount; newCount++) { goodSound = TRUE; soundID = completeSndArray[newCount]; for (count = 0; count < sndCount; count++) { if (soundID == pSndArray[count]) { goodSound = FALSE; break; } } if (goodSound) { pSndArray[sndCount++] = (XShortResourceID)soundID; } } XBubbleSortArray((short *)pSndArray, (short)sndCount); } XDisposePtr(completeSndArray); } return (short)sndCount; }
/* ** This will walk through all Instrument resources and collect all snd resources ** that are used. */ short int XGatherAllSoundsFromAllInstruments(XShortResourceID *pSndArray, short int maxArraySize) { short int count, icount, sndCount, jcount; XShortResourceID soundID; XBOOL goodSound; XShortResourceID instArray[MAX_INSTRUMENTS * MAX_BANKS]; short int totalInstruments; XShortResourceID sndArray[MAX_SAMPLES]; short int totalSnds; XShortResourceID *completeSndArray; short int completeSndCount; InstrumentResource *theX; long size; completeSndCount = 0; sndCount = 0; completeSndArray = (XShortResourceID *)XNewPtr(MAX_INSTRUMENTS * MAX_BANKS * 128L * sizeof(XShortResourceID)); if (completeSndArray) { sndCount = 0; totalInstruments = XGetInstrumentArray(instArray, MAX_INSTRUMENTS * MAX_BANKS); if (totalInstruments) { for (count = 0; count < totalInstruments; count++) { theX = (InstrumentResource *)XGetAndDetachResource(ID_INST, instArray[count], &size); if (theX) { totalSnds = XCollectSoundsFromInstrument(theX, sndArray, MAX_SAMPLES); XDisposePtr((XPTR)theX); for (icount = 0; icount < totalSnds; icount++) { completeSndArray[completeSndCount++] = sndArray[icount]; } } } XBubbleSortArray((short *)completeSndArray, (short)completeSndCount); // Remove duplicates for (jcount = 0; jcount < completeSndCount; jcount++) { goodSound = TRUE; soundID = completeSndArray[jcount]; for (count = 0; count < sndCount; count++) { if (soundID == pSndArray[count]) { goodSound = FALSE; break; } } if (goodSound) { if (sndCount < maxArraySize) { pSndArray[sndCount++] = soundID; } } } } XDisposePtr((XPTR)completeSndArray); } return sndCount; }