diff options
Diffstat (limited to 'backends/midi/mt32/part.cpp')
-rw-r--r-- | backends/midi/mt32/part.cpp | 505 |
1 files changed, 254 insertions, 251 deletions
diff --git a/backends/midi/mt32/part.cpp b/backends/midi/mt32/part.cpp index 6fe783e1b6..c240874143 100644 --- a/backends/midi/mt32/part.cpp +++ b/backends/midi/mt32/part.cpp @@ -34,16 +34,19 @@ static const Bit8u PartialMixStruct[13] = { 0, 1, 0, 1, 1, 0, 1, 3, 3, 2, 2, 2, 2 }; -// This caches the timbres/settings in use by the rhythm part -static PatchCache drumCache[94][4]; -static StereoVolume drumPan[64]; +static const float floatKeyfollow[17] = { + -1.0f, -1.0f/2.0f, -1.0f/4.0f, 0.0f, + 1.0f/8.0f, 1.0f/4.0f, 3.0f/8.0f, 1.0f/2.0f, 5.0f/8.0f, 3.0f/4.0f, 7.0f/8.0f, 1.0f, + 5.0f/4.0f, 3.0f/2.0f, 2.0f, + 1.0009765625f, 1.0048828125f +}; //FIXME:KG: Put this dpoly stuff somewhere better -bool dpoly::isActive() { +bool dpoly::isActive() const { return partials[0] != NULL || partials[1] != NULL || partials[2] != NULL || partials[3] != NULL; } -Bit64s dpoly::getAge() { +Bit64s dpoly::getAge() const { for (int i = 0; i < 4; i++) { if (partials[i] != NULL) { return partials[i]->age; @@ -52,36 +55,34 @@ Bit64s dpoly::getAge() { return 0; } -Part::Part(Synth *useSynth, int usePartNum) { +RhythmPart::RhythmPart(Synth *useSynth, unsigned int usePartNum): Part(useSynth, usePartNum) { + strcpy(name, "Rhythm"); + rhythmTemp = &synth->mt32ram.rhythmSettings[0]; + refresh(); +} + +Part::Part(Synth *useSynth, unsigned int usePartNum) { this->synth = useSynth; this->partNum = usePartNum; - isRhythm = (usePartNum == 8); + patchCache[0].dirty = true; holdpedal = false; - if (isRhythm) { - strcpy(name, "Rhythm"); + if (usePartNum == 8) { + // Nasty hack for rhythm patchTemp = NULL; timbreTemp = NULL; - rhythmTemp = &synth->mt32ram.params.rhythmSettings[0]; } else { sprintf(name, "Part %d", partNum + 1); - patchTemp = &synth->mt32ram.params.patchSettings[partNum]; - timbreTemp = &synth->mt32ram.params.timbreSettings[partNum]; - rhythmTemp = NULL; + patchTemp = &synth->mt32ram.patchSettings[partNum]; + timbreTemp = &synth->mt32ram.timbreSettings[partNum]; } currentInstr[0] = 0; currentInstr[10] = 0; - volume = 102; + volume = voltable[102]; //FIXME:KG: Original was just volume=102; I assume this is intended volumesetting.leftvol = 32767; volumesetting.rightvol = 32767; bend = 0.0f; memset(polyTable,0,sizeof(polyTable)); memset(patchCache, 0, sizeof(patchCache)); - - if (isRhythm) { - init = true; - refreshDrumCache(); - } - init = false; } void Part::setHoldPedal(bool pedalval) { @@ -90,16 +91,17 @@ void Part::setHoldPedal(bool pedalval) { holdpedal = pedalval; } -void Part::setBend(int midiBend) { - if (isRhythm) { - synth->printDebug("%s: Setting bend (%d) not supported on rhythm", name, midiBend); - return; - } - // FIXME:KG: Slightly uneven increments, but I wanted min -1.0, centre 0.0 and max 1.0 +void RhythmPart::setBend(unsigned int midiBend) { + synth->printDebug("%s: Setting bend (%d) not supported on rhythm", name, midiBend); + return; +} + +void Part::setBend(unsigned int midiBend) { + // FIXME:KG: Slightly unbalanced increments, but I wanted min -1.0, centre 0.0 and max 1.0 if (midiBend <= 0x2000) { - bend = (midiBend - 0x2000) / (float)0x2000; + bend = ((signed int)midiBend - 0x2000) / (float)0x2000; } else { - bend = (midiBend - 0x2000) / (float)0x1FFF; + bend = ((signed int)midiBend - 0x2000) / (float)0x1FFF; } // Loop through all partials to update their bend for (int i = 0; i < MT32EMU_MAX_POLY; i++) { @@ -111,15 +113,15 @@ void Part::setBend(int midiBend) { } } -void Part::setModulation(int vol) { - if (isRhythm) { - synth->printDebug("%s: Setting modulation (%d) not supported on rhythm", name, vol); - return; - } +void RhythmPart::setModulation(unsigned int midiModulation) { + synth->printDebug("%s: Setting modulation (%d) not supported on rhythm", name, midiModulation); +} + +void Part::setModulation(unsigned int midiModulation) { // Just a bloody guess, as always, before I get things figured out for (int t = 0; t < 4; t++) { if (patchCache[t].playPartial) { - int newrate = (patchCache[t].modsense * vol) >> 7; + int newrate = (patchCache[t].modsense * midiModulation) >> 7; //patchCache[t].lfoperiod = lfotable[newrate]; patchCache[t].lfodepth = newrate; //FIXME:KG: timbreTemp->partial[t].lfo.depth = @@ -127,52 +129,78 @@ void Part::setModulation(int vol) { } } -void Part::refreshDrumCache() { - if (!isRhythm) { - synth->printDebug("ERROR: RefreshDrumCache() called on non-rhythm part"); - } - // Cache drum patches - for (int m = 0; m < 64; m++) { - int drumTimbre = rhythmTemp[m].timbre; - if (drumTimbre >= 94) +void RhythmPart::refresh() { + // (Re-)cache all the mapped timbres ahead of time + for (unsigned int drumNum = 0; drumNum < 64; drumNum++) { + int drumTimbreNum = rhythmTemp[drumNum].timbre; + if (drumTimbreNum >= 94) continue; - setPatch(drumTimbre + 128); // This is to cache all the mapped drum timbres ahead of time - Bit16s pan = rhythmTemp[m].panpot; // They use R-L 0-14... + Bit16s pan = rhythmTemp[drumNum].panpot; // They use R-L 0-14... + // FIXME:KG: Panning cache should be backed up to partials using it, too // FIXME:KG: If I don't have left/right mixed up here, it's pure luck if (pan < 7) { - drumPan[m].leftvol = 32767; - drumPan[m].rightvol = pan * 4681; + drumPan[drumNum].leftvol = 32767; + drumPan[drumNum].rightvol = pan * 4681; } else { - drumPan[m].rightvol = 32767; - drumPan[m].leftvol = (14 - pan) * 4681; + drumPan[drumNum].rightvol = 32767; + drumPan[drumNum].leftvol = (14 - pan) * 4681; } + PatchCache *cache = drumCache[drumNum]; + backupCacheToPartials(cache); + for (int t = 0; t < 4; t++) { + // Common parameters, stored redundantly + cache[t].dirty = true; + cache[t].pitchShift = 0.0f; + cache[t].benderRange = 0.0f; + cache[t].pansetptr = &drumPan[drumNum]; + cache[t].reverb = rhythmTemp[drumNum].reverbSwitch > 0; + } + } +} + +void Part::refresh() { + backupCacheToPartials(patchCache); + for (int t = 0; t < 4; t++) { + // Common parameters, stored redundantly + patchCache[t].dirty = true; + patchCache[t].pitchShift = (patchTemp->patch.keyShift - 24) + (patchTemp->patch.fineTune - 50) / 100.0f; + patchCache[t].benderRange = patchTemp->patch.benderRange; + patchCache[t].pansetptr = &volumesetting; + patchCache[t].reverb = patchTemp->patch.reverbSwitch > 0; + } + memcpy(currentInstr, timbreTemp->common.name, 10); +} + +void RhythmPart::refreshTimbre(unsigned int absTimbreNum) { + for (int m = 0; m < 64; m++) { + if (rhythmTemp[m].timbre == absTimbreNum - 128) + drumCache[m][0].dirty = true; + } +} + +void Part::refreshTimbre(unsigned int absTimbreNum) { + if (getAbsTimbreNum() == absTimbreNum) { + memcpy(currentInstr, timbreTemp->common.name, 10); + patchCache[0].dirty = true; } } int Part::fixBiaslevel(int srcpnt, int *dir) { - int noteat = srcpnt & 63; + int noteat = srcpnt & 0x3F; int outnote; - *dir = 1; if (srcpnt < 64) *dir = 0; + else + *dir = 1; outnote = 33 + noteat; //synth->printDebug("Bias note %d, dir %d", outnote, *dir); return outnote; } -int Part::fixKeyfollow(int srckey, int *dir) { +int Part::fixKeyfollow(int srckey) { if (srckey>=0 && srckey<=16) { - //int keyfix[17] = { 256, 128, 64, 0, 32, 64, 96, 128, 128+32, 192, 192+32, 256, 256+64, 256+128, 512, 259, 269 }; - int keyfix[17] = { 256*16, 128*16, 64*16, 0, 32*16, 64*16, 96*16, 128*16, (128+32)*16, 192*16, (192+32)*16, 256*16, (256+64)*16, (256+128)*16, (512)*16, 4100, 4116}; - - if (srckey<3) - *dir = -1; - else if (srckey==3) - *dir = 0; - else - *dir = 1; - + int keyfix[17] = { -256*16, -128*16, -64*16, 0, 32*16, 64*16, 96*16, 128*16, (128+32)*16, 192*16, (192+32)*16, 256*16, (256+64)*16, (256+128)*16, (512)*16, 4100, 4116}; return keyfix[srckey]; } else { //LOG(LOG_ERROR|LOG_MISC,"Missed key: %d", srckey); @@ -180,10 +208,6 @@ int Part::fixKeyfollow(int srckey, int *dir) { } } -void Part::refreshPatch() { - setPatch(-1); -} - void Part::abortPoly(dpoly *poly) { if (!poly->isPlaying) { return; @@ -197,7 +221,7 @@ void Part::abortPoly(dpoly *poly) { poly->isPlaying = false; } -void Part::setPatch(PatchParam *patch) { +void Part::setPatch(const PatchParam *patch) { patchTemp->patch = *patch; } @@ -205,187 +229,165 @@ void Part::setTimbre(TimbreParam *timbre) { *timbreTemp = *timbre; } -unsigned int Part::getAbsTimbreNum() { - if (isRhythm) { - synth->printDebug("%s: Attempted to call getAbsTimbreNum() - doesn't make sense for rhythm"); - return 0; - } +unsigned int RhythmPart::getAbsTimbreNum() const { + synth->printDebug("%s: Attempted to call getAbsTimbreNum() - doesn't make sense for rhythm"); + return 0; +} + +unsigned int Part::getAbsTimbreNum() const { return (patchTemp->patch.timbreGroup * 64) + patchTemp->patch.timbreNum; } -void Part::setPatch(int patchNum) { - int absTimbreNum = -1; // Initialised to please compiler - const TimbreParam *timbre; - if (isRhythm) { - // "patchNum" is treated as "timbreNum" for rhythm part - if (patchNum < 128) { - synth->printDebug("%s: Patch #%d is not valid for rhythm (must be >= 128)", name, patchNum); - return; - } - absTimbreNum = patchNum; - timbre = &synth->mt32ram.params.timbres[absTimbreNum].timbre; - } else { - if (patchNum >= 0) { - setPatch(&synth->mt32ram.params.patches[patchNum]); - } - if (patchNum >= 0) { - setTimbre(&synth->mt32ram.params.timbres[getAbsTimbreNum()].timbre); - } - timbre = timbreTemp; +void RhythmPart::setProgram(unsigned int patchNum) { + synth->printDebug("%s: Attempt to set program (%d) on rhythm is invalid", name, patchNum); +} + +void Part::setProgram(unsigned int patchNum) { + setPatch(&synth->mt32ram.patches[patchNum]); + setTimbre(&synth->mt32ram.timbres[getAbsTimbreNum()].timbre); #if 0 - // Immediately stop all partials on this part (this is apparently *not* the correct behaviour) - for (int m = 0; m < MT32EMU_MAX_POLY; m++) { - AbortPoly(poly); - } -#else - // check if any partials are still playing with the old patch cache - // if so then duplicate the cached data from the part to the partial so that - // we can change the part's cache without affecting the partial. - // We delay this until now to avoid a copy operation with every note played - for (int m = 0; m < MT32EMU_MAX_POLY; m++) { - for (int i = 0; i < 4; i++) { - Partial *partial = polyTable[m].partials[i]; - if (partial != NULL && partial->patchCache == &patchCache[i]) { - // copy cache data - partial->cachebackup = patchCache[i]; - // update pointers - partial->patchCache = &partial->cachebackup; - } + // Immediately stop all partials on this part (this is apparently *not* the correct behaviour) + for (int m = 0; m < MT32EMU_MAX_POLY; m++) { + AbortPoly(poly); + } +#endif + + refresh(); + + allStop(); //FIXME:KG: Is this correct? +} + +void Part::backupCacheToPartials(PatchCache cache[4]) { + // check if any partials are still playing with the old patch cache + // if so then duplicate the cached data from the part to the partial so that + // we can change the part's cache without affecting the partial. + // We delay this until now to avoid a copy operation with every note played + for (int m = 0; m < MT32EMU_MAX_POLY; m++) { + for (int i = 0; i < 4; i++) { + Partial *partial = polyTable[m].partials[i]; + if (partial != NULL && partial->patchCache == &cache[i]) { + partial->cachebackup = cache[i]; + partial->patchCache = &partial->cachebackup; } } -#endif } +} - memcpy(currentInstr, timbre->common.name, 10); - +void Part::cacheTimbre(PatchCache cache[4], const TimbreParam *timbre) { + backupCacheToPartials(cache); int partialCount = 0; for (int t = 0; t < 4; t++) { if (((timbre->common.pmute >> t) & 0x1) == 1) { - patchCache[t].playPartial = true; + cache[t].playPartial = true; partialCount++; } else { - patchCache[t].playPartial = false; + cache[t].playPartial = false; continue; } // Calculate and cache common parameters - patchCache[t].pcm = timbre->partial[t].wg.pcmwave; - patchCache[t].useBender = (timbre->partial[t].wg.bender == 1); + cache[t].pcm = timbre->partial[t].wg.pcmwave; + cache[t].useBender = (timbre->partial[t].wg.bender == 1); switch (t) { case 0: - patchCache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct12] & 0x2) ? true : false; - patchCache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct12]; - patchCache[t].structurePosition = 0; - patchCache[t].structurePair = 1; + cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct12] & 0x2) ? true : false; + cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct12]; + cache[t].structurePosition = 0; + cache[t].structurePair = 1; break; case 1: - patchCache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct12] & 0x1) ? true : false; - patchCache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct12]; - patchCache[t].structurePosition = 1; - patchCache[t].structurePair = 0; + cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct12] & 0x1) ? true : false; + cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct12]; + cache[t].structurePosition = 1; + cache[t].structurePair = 0; break; case 2: - patchCache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct34] & 0x2) ? true : false; - patchCache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct34]; - patchCache[t].structurePosition = 0; - patchCache[t].structurePair = 3; + cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct34] & 0x2) ? true : false; + cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct34]; + cache[t].structurePosition = 0; + cache[t].structurePair = 3; break; case 3: - patchCache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct34] & 0x1) ? true : false; - patchCache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct34]; - patchCache[t].structurePosition = 1; - patchCache[t].structurePair = 2; + cache[t].PCMPartial = (PartialStruct[(int)timbre->common.pstruct34] & 0x1) ? true : false; + cache[t].structureMix = PartialMixStruct[(int)timbre->common.pstruct34]; + cache[t].structurePosition = 1; + cache[t].structurePair = 2; break; default: break; } - patchCache[t].waveform = timbre->partial[t].wg.waveform; - patchCache[t].pulsewidth = timbre->partial[t].wg.pulsewid; - patchCache[t].pwsens = timbre->partial[t].wg.pwvelo; - patchCache[t].pitchkeyfollow = fixKeyfollow(timbre->partial[t].wg.keyfollow, &patchCache[t].pitchkeydir); - - // Calculate and cache pitch stuff - patchCache[t].pitchshift = timbre->partial[t].wg.coarse; - Bit32s pFine, fShift; - pFine = (Bit32s)timbre->partial[t].wg.fine; - if (isRhythm) { - patchCache[t].pitchshift += 24; - fShift = pFine + 50; + cache[t].waveform = timbre->partial[t].wg.waveform; + cache[t].pulsewidth = timbre->partial[t].wg.pulsewid; + cache[t].pwsens = timbre->partial[t].wg.pwvelo; + if (timbre->partial[t].wg.keyfollow > 16) { + synth->printDebug("Bad keyfollow value in timbre!"); + cache[t].pitchKeyfollow = 1.0f; } else { - patchCache[t].pitchshift += patchTemp->patch.keyShift; - fShift = pFine + (Bit32s)patchTemp->patch.fineTune; + cache[t].pitchKeyfollow = floatKeyfollow[timbre->partial[t].wg.keyfollow]; } - patchCache[t].fineshift = finetable[fShift]; - patchCache[t].pitchEnv = timbre->partial[t].env; - patchCache[t].pitchEnv.sensitivity = (char)((float)patchCache[t].pitchEnv.sensitivity*1.27); - patchCache[t].pitchsustain = patchCache[t].pitchEnv.level[3]; + cache[t].pitch = timbre->partial[t].wg.coarse + (timbre->partial[t].wg.fine - 50) / 100.0f + 24.0f; + cache[t].pitchEnv = timbre->partial[t].env; + cache[t].pitchEnv.sensitivity = (char)((float)cache[t].pitchEnv.sensitivity * 1.27f); + cache[t].pitchsustain = cache[t].pitchEnv.level[3]; // Calculate and cache TVA envelope stuff - patchCache[t].ampEnv = timbre->partial[t].tva; + cache[t].ampEnv = timbre->partial[t].tva; for (int i = 0; i < 4; i++) - patchCache[t].ampEnv.envlevel[i] = (char)((float)patchCache[t].ampEnv.envlevel[i] * 1.27f); - patchCache[t].ampEnv.level = (char)((float)patchCache[t].ampEnv.level * 1.27f); + cache[t].ampEnv.envlevel[i] = (char)((float)cache[t].ampEnv.envlevel[i] * 1.27f); + cache[t].ampEnv.level = (char)((float)cache[t].ampEnv.level * 1.27f); float tvelo = ((float)timbre->partial[t].tva.velosens / 100.0f); float velo = fabs(tvelo-0.5f) * 2.0f; velo *= 63.0f; - patchCache[t].ampEnv.velosens = (char)velo; + cache[t].ampEnv.velosens = (char)velo; if (tvelo<0.5f) - patchCache[t].ampenvdir = 1; + cache[t].ampenvdir = 1; else - patchCache[t].ampenvdir = 0; + cache[t].ampenvdir = 0; - patchCache[t].ampbias[0] = fixBiaslevel(patchCache[t].ampEnv.biaspoint1, &patchCache[t].ampdir[0]); - patchCache[t].ampblevel[0] = 12 - patchCache[t].ampEnv.biaslevel1; - patchCache[t].ampbias[1] = fixBiaslevel(patchCache[t].ampEnv.biaspoint2, &patchCache[t].ampdir[1]); - patchCache[t].ampblevel[1] = 12 - patchCache[t].ampEnv.biaslevel2; - patchCache[t].ampdepth = patchCache[t].ampEnv.envvkf * patchCache[t].ampEnv.envvkf; - patchCache[t].ampsustain = patchCache[t].ampEnv.envlevel[3]; - patchCache[t].amplevel = patchCache[t].ampEnv.level; + cache[t].ampbias[0] = fixBiaslevel(cache[t].ampEnv.biaspoint1, &cache[t].ampdir[0]); + cache[t].ampblevel[0] = 12 - cache[t].ampEnv.biaslevel1; + cache[t].ampbias[1] = fixBiaslevel(cache[t].ampEnv.biaspoint2, &cache[t].ampdir[1]); + cache[t].ampblevel[1] = 12 - cache[t].ampEnv.biaslevel2; + cache[t].ampdepth = cache[t].ampEnv.envvkf * cache[t].ampEnv.envvkf; + cache[t].ampsustain = cache[t].ampEnv.envlevel[3]; + cache[t].amplevel = cache[t].ampEnv.level; // Calculate and cache filter stuff - patchCache[t].filtEnv = timbre->partial[t].tvf; - patchCache[t].tvfdepth = patchCache[t].filtEnv.envdkf; - patchCache[t].filtkeyfollow = fixKeyfollow(patchCache[t].filtEnv.keyfollow, &patchCache[t].keydir); - patchCache[t].filtEnv.envdepth = (char)((float)patchCache[t].filtEnv.envdepth * 1.27); - patchCache[t].tvfbias = fixBiaslevel(patchCache[t].filtEnv.biaspoint, &patchCache[t].tvfdir); - patchCache[t].tvfblevel = patchCache[t].filtEnv.biaslevel; - patchCache[t].filtsustain = patchCache[t].filtEnv.envlevel[3]; + cache[t].filtEnv = timbre->partial[t].tvf; + cache[t].tvfdepth = cache[t].filtEnv.envdkf; + cache[t].filtkeyfollow = fixKeyfollow(cache[t].filtEnv.keyfollow); + cache[t].filtEnv.envdepth = (char)((float)cache[t].filtEnv.envdepth * 1.27); + cache[t].tvfbias = fixBiaslevel(cache[t].filtEnv.biaspoint, &cache[t].tvfdir); + cache[t].tvfblevel = cache[t].filtEnv.biaslevel; + cache[t].filtsustain = cache[t].filtEnv.envlevel[3]; // Calculate and cache LFO stuff - patchCache[t].lfodepth = timbre->partial[t].lfo.depth; - patchCache[t].lfoperiod = lfotable[(int)timbre->partial[t].lfo.rate]; - patchCache[t].lforate = timbre->partial[t].lfo.rate; - patchCache[t].modsense = timbre->partial[t].lfo.modsense; + cache[t].lfodepth = timbre->partial[t].lfo.depth; + cache[t].lfoperiod = lfotable[(int)timbre->partial[t].lfo.rate]; + cache[t].lforate = timbre->partial[t].lfo.rate; + cache[t].modsense = timbre->partial[t].lfo.modsense; } for (int t = 0; t < 4; t++) { // Common parameters, stored redundantly - patchCache[t].partialCount = partialCount; - patchCache[t].sustain = (timbre->common.nosustain == 0); - if (isRhythm) { - patchCache[t].benderRange = 0; - } else { - patchCache[t].benderRange = patchTemp->patch.benderRange; - } + cache[t].dirty = false; + cache[t].partialCount = partialCount; + cache[t].sustain = (timbre->common.nosustain == 0); } - //synth->printDebug("Res 1: %d 2: %d 3: %d 4: %d", patchCache[0].waveform, patchCache[1].waveform, patchCache[2].waveform, patchCache[3].waveform); + //synth->printDebug("Res 1: %d 2: %d 3: %d 4: %d", cache[0].waveform, cache[1].waveform, cache[2].waveform, cache[3].waveform); - if (isRhythm) - memcpy(drumCache[absTimbreNum - 128], patchCache, sizeof(patchCache)); - else - allStop(); #if MT32EMU_MONITOR_INSTRUMENTS == 1 - synth->printDebug("%s: Recache, param %d (timbre: %s)", name, patchNum, currentInstr); + synth->printDebug("%s (%s): Recached timbre", name, currentInstr); for (int i = 0; i < 4; i++) { - synth->printDebug(" %d: play=%s, pcm=%s (%d), wave=%d", i, patchCache[i].playPartial ? "YES" : "NO", patchCache[i].PCMPartial ? "YES" : "NO", timbre->partial[i].wg.pcmwave, timbre->partial[i].wg.waveform); + synth->printDebug(" %d: play=%s, pcm=%s (%d), wave=%d", i, cache[i].playPartial ? "YES" : "NO", cache[i].PCMPartial ? "YES" : "NO", timbre->partial[i].wg.pcmwave, timbre->partial[i].wg.waveform); } #endif } -char *Part::getName() { +const char *Part::getName() const { return name; } @@ -393,72 +395,88 @@ void Part::setVolume(int vol) { volume = voltable[vol]; } -void Part::setPan(int pan) { +void RhythmPart::setPan(unsigned int midiPan) +{ // FIXME:KG: This is unchangeable for drums (they always use drumPan), is that correct? + synth->printDebug("%s: Setting pan (%d) not supported on rhythm", name, midiPan); +} + +void Part::setPan(unsigned int midiPan) { // FIXME:KG: Tweaked this a bit so that we have a left 100%, centre and right 100% // (But this makes the range somewhat skewed) - if (pan < 64) { + if (midiPan < 64) { volumesetting.leftvol = 32767; - volumesetting.rightvol = (Bit16s)(pan * 512); - } else if (pan == 64) { + volumesetting.rightvol = (Bit16s)(midiPan * 512); + } else if (midiPan == 64) { volumesetting.leftvol = 32767; volumesetting.rightvol = 32767; } else { volumesetting.rightvol = 32767; - volumesetting.leftvol = (Bit16s)((127 - pan) * 520); + volumesetting.leftvol = (Bit16s)((127 - midiPan) * 520); } //synth->printDebug("%s (%s): Set pan to %d", name, currentInstr, panpot); } -void Part::playNote(PartialManager *partialManager, unsigned int key, int vel) { - int drumNum = -1; // Initialised to please compiler - int drumTimbre = -1; // As above - int freqNum; +void RhythmPart::playNote(unsigned int key, int vel) { + if (key < 24 || key > 87) { + synth->printDebug("%s: Attempted to play invalid key %d", name, key); + return; + } + int drumNum = key - 24; + int drumTimbreNum = rhythmTemp[drumNum].timbre; + if (drumTimbreNum >= 94) { + synth->printDebug("%s: Attempted to play unmapped key %d", name, key); + return; + } + int absTimbreNum = drumTimbreNum + 128; + TimbreParam *timbre = &synth->mt32ram.timbres[absTimbreNum].timbre; + memcpy(currentInstr, timbre->common.name, 10); +#if MT32EMU_MONITOR_INSTRUMENTS == 1 + synth->printDebug("%s (%s): starting poly (drum %d, timbre %d) - Vel %d Key %d Vol %d", name, currentInstr, drumNum, absTimbreNum, vel, key, volume); +#endif + if (drumCache[drumNum][0].dirty) { + cacheTimbre(drumCache[drumNum], timbre); + } + playPoly(drumCache[drumNum], key, MIDDLEC, vel); +} - if (isRhythm) { - if (key < 24 || key > 87) { - synth->printDebug("%s: Attempted to play invalid key %d", name, key); - return; - } - drumNum = key - 24; - drumTimbre = rhythmTemp[drumNum].timbre; - if (drumTimbre >= 94) { - synth->printDebug("%s: Attempted to play unmapped key %d", name, key); - return; +void Part::playNote(unsigned int key, int vel) { + int freqNum = key; + if (freqNum < 12) { + synth->printDebug("%s (%s): Attempted to play invalid key %d < 12; moving up by octave", name, currentInstr, key); + freqNum += 12; + } else if (freqNum > 108) { + synth->printDebug("%s (%s): Attempted to play invalid key %d > 108; moving down by octave", name, currentInstr, key); + while (freqNum > 108) { + freqNum -= 12; } - memcpy(patchCache, drumCache[drumTimbre], sizeof(patchCache)); - memcpy(¤tInstr, synth->mt32ram.params.timbres[128 + drumTimbre].timbre.common.name, 10); - freqNum = MIDDLEC; - } else { - if (key < 12) { - synth->printDebug("%s (%s): Attempted to play invalid key %d < 12; moving up by octave", name, currentInstr, key); - key += 12; - } else if (key > 108) { - synth->printDebug("%s (%s): Attempted to play invalid key %d > 108; moving down by octave", name, currentInstr, key); - while (key > 108) { - key -= 12; - } - } - freqNum = key; } // POLY1 mode, Single Assign // Haven't found any software that uses any of the other poly modes // FIXME:KG: Should this also apply to rhythm? - if (!isRhythm) { - for (unsigned int i = 0; i < MT32EMU_MAX_POLY; i++) { - if (polyTable[i].isActive() && (polyTable[i].key == key)) { - //AbortPoly(&polyTable[i]); - stopNote(key); - break; - } + for (unsigned int i = 0; i < MT32EMU_MAX_POLY; i++) { + if (polyTable[i].isActive() && (polyTable[i].key == key)) { + //AbortPoly(&polyTable[i]); + stopNote(key); + break; } } +#if MT32EMU_MONITOR_INSTRUMENTS == 1 + synth->printDebug("%s (%s): starting poly - Vel %d Key %d Vol %d", name, currentInstr, vel, key, volume); +#endif + if (patchCache[0].dirty) { + cacheTimbre(patchCache, timbreTemp); + } + playPoly(patchCache, key, freqNum, vel); +} - unsigned int needPartials = patchCache[0].partialCount; +void Part::playPoly(const PatchCache cache[4], unsigned int key, int freqNum, int vel) { + unsigned int needPartials = cache[0].partialCount; + unsigned int freePartials = synth->partialManager->getFreePartialCount(); - if (needPartials > partialManager->GetFreePartialCount()) { - if (!partialManager->FreePartials(needPartials, partNum)) { - synth->printDebug("%s (%s): Insufficient free partials to play key %d (vel=%d)", name, currentInstr, key, vel); + if (freePartials < needPartials) { + if (!synth->partialManager->freePartials(needPartials - freePartials, partNum)) { + synth->printDebug("%s (%s): Insufficient free partials to play key %d (vel=%d); needed=%d, free=%d", name, currentInstr, key, vel, needPartials, synth->partialManager->getFreePartialCount()); return; } } @@ -485,8 +503,8 @@ void Part::playNote(PartialManager *partialManager, unsigned int key, int vel) { bool allnull = true; for (int x = 0; x < 4; x++) { - if (patchCache[x].playPartial) { - tpoly->partials[x] = partialManager->AllocPartial(partNum); + if (cache[x].playPartial) { + tpoly->partials[x] = synth->partialManager->allocPartial(partNum); allnull = false; } else { tpoly->partials[x] = NULL; @@ -496,27 +514,12 @@ void Part::playNote(PartialManager *partialManager, unsigned int key, int vel) { if (allnull) synth->printDebug("%s (%s): No partials to play for this instrument", name, this->currentInstr); - if (isRhythm) { - tpoly->pansetptr = &drumPan[drumNum]; - tpoly->reverb = rhythmTemp[drumNum].reverbSwitch > 0; - } else { - tpoly->pansetptr = &volumesetting; - tpoly->reverb = patchTemp->patch.reverbSwitch > 0; - } - tpoly->sustain = patchCache[0].sustain; + tpoly->sustain = cache[0].sustain; tpoly->volumeptr = &volume; -#if MT32EMU_MONITOR_INSTRUMENTS == 1 - if (isRhythm) { - synth->printDebug("%s (%s): starting poly %d (drum %d, timbre %d) - Vel %d Key %d Vol %d", name, currentInstr, m, drumNum, drumTimbre, vel, key, volume); - } else { - synth->printDebug("%s (%s): starting poly %d - Vel %d Key %d Vol %d", name, currentInstr, m, vel, key, volume); - } -#endif - for (int x = 0; x < 4; x++) { if (tpoly->partials[x] != NULL) { - tpoly->partials[x]->startPartial(tpoly, &patchCache[x], tpoly->partials[patchCache[x].structurePair]); + tpoly->partials[x]->startPartial(tpoly, &cache[x], tpoly->partials[cache[x].structurePair]); tpoly->partials[x]->setBend(bend); } } |