DOSBox-X
|
00001 /* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher 00002 * Copyright (C) 2011, 2012, 2013 Dean Beeler, Jerome Fisher, Sergey V. Mikayev 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU Lesser General Public License as published by 00006 * the Free Software Foundation, either version 2.1 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #include <cstdio> 00019 #include <cstring> 00020 00021 #include "mt32emu.h" 00022 #include "PartialManager.h" 00023 00024 namespace MT32Emu { 00025 00026 static const Bit8u PartialStruct[13] = { 00027 0, 0, 2, 2, 1, 3, 00028 3, 0, 3, 0, 2, 1, 3 00029 }; 00030 00031 static const Bit8u PartialMixStruct[13] = { 00032 0, 1, 0, 1, 1, 0, 00033 1, 3, 3, 2, 2, 2, 2 00034 }; 00035 00036 #if 0//unused 00037 static const float floatKeyfollow[17] = { 00038 -1.0f, -1.0f / 2.0f, -1.0f / 4.0f, 0.0f, 00039 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, 00040 5.0f / 4.0f, 3.0f / 2.0f, 2.0f, 00041 1.0009765625f, 1.0048828125f 00042 }; 00043 #endif 00044 00045 00046 RhythmPart::RhythmPart(Synth *useSynth, unsigned int usePartNum): Part(useSynth, usePartNum) { 00047 strcpy(name, "Rhythm"); 00048 rhythmTemp = &synth->mt32ram.rhythmTemp[0]; 00049 RhythmPart::refresh(); 00050 } 00051 00052 Part::Part(Synth *useSynth, unsigned int usePartNum) { 00053 synth = useSynth; 00054 partNum = usePartNum; 00055 patchCache[0].dirty = true; 00056 holdpedal = false; 00057 patchTemp = &synth->mt32ram.patchTemp[partNum]; 00058 if (usePartNum == 8) { 00059 // Nasty hack for rhythm 00060 timbreTemp = NULL; 00061 } else { 00062 sprintf(name, "Part %u", partNum + 1); 00063 timbreTemp = &synth->mt32ram.timbreTemp[partNum]; 00064 } 00065 currentInstr[0] = 0; 00066 currentInstr[10] = 0; 00067 modulation = 0; 00068 expression = 100; 00069 pitchBend = 0; 00070 activePartialCount = 0; 00071 memset(patchCache, 0, sizeof(patchCache)); 00072 for (int i = 0; i < MT32EMU_MAX_POLY; i++) { 00073 freePolys.prepend(new Poly(synth,this)); 00074 } 00075 } 00076 00077 Part::~Part() { 00078 while (!activePolys.isEmpty()) { 00079 delete activePolys.takeFirst(); 00080 } 00081 while (!freePolys.isEmpty()) { 00082 delete freePolys.takeFirst(); 00083 } 00084 } 00085 00086 void Part::setDataEntryMSB(unsigned char midiDataEntryMSB) { 00087 if (nrpn) { 00088 // The last RPN-related control change was for an NRPN, 00089 // which the real synths don't support. 00090 return; 00091 } 00092 if (rpn != 0) { 00093 // The RPN has been set to something other than 0, 00094 // which is the only RPN that these synths support 00095 return; 00096 } 00097 patchTemp->patch.benderRange = midiDataEntryMSB > 24 ? 24 : midiDataEntryMSB; 00098 updatePitchBenderRange(); 00099 } 00100 00101 void Part::setNRPN() { 00102 nrpn = true; 00103 } 00104 00105 void Part::setRPNLSB(unsigned char midiRPNLSB) { 00106 nrpn = false; 00107 rpn = (rpn & 0xFF00) | midiRPNLSB; 00108 } 00109 00110 void Part::setRPNMSB(unsigned char midiRPNMSB) { 00111 nrpn = false; 00112 rpn = (rpn & 0x00FF) | (midiRPNMSB << 8); 00113 } 00114 00115 void Part::setHoldPedal(bool pressed) { 00116 if (holdpedal && !pressed) { 00117 holdpedal = false; 00118 stopPedalHold(); 00119 } else { 00120 holdpedal = pressed; 00121 } 00122 } 00123 00124 Bit32s Part::getPitchBend() const { 00125 return pitchBend; 00126 } 00127 00128 void Part::setBend(unsigned int midiBend) { 00129 // CONFIRMED: 00130 pitchBend = (((signed)midiBend - 8192) * pitchBenderRange) >> 14; // PORTABILITY NOTE: Assumes arithmetic shift 00131 } 00132 00133 Bit8u Part::getModulation() const { 00134 return modulation; 00135 } 00136 00137 void Part::setModulation(unsigned int midiModulation) { 00138 modulation = (Bit8u)midiModulation; 00139 } 00140 00141 void Part::resetAllControllers() { 00142 modulation = 0; 00143 expression = 100; 00144 pitchBend = 0; 00145 setHoldPedal(false); 00146 } 00147 00148 void Part::reset() { 00149 resetAllControllers(); 00150 allSoundOff(); 00151 rpn = 0xFFFF; 00152 } 00153 00154 void RhythmPart::refresh() { 00155 // (Re-)cache all the mapped timbres ahead of time 00156 for (unsigned int drumNum = 0; drumNum < synth->controlROMMap->rhythmSettingsCount; drumNum++) { 00157 int drumTimbreNum = rhythmTemp[drumNum].timbre; 00158 if (drumTimbreNum >= 127) { // 94 on MT-32 00159 continue; 00160 } 00161 PatchCache *cache = drumCache[drumNum]; 00162 backupCacheToPartials(cache); 00163 for (int t = 0; t < 4; t++) { 00164 // Common parameters, stored redundantly 00165 cache[t].dirty = true; 00166 cache[t].reverb = rhythmTemp[drumNum].reverbSwitch > 0; 00167 } 00168 } 00169 updatePitchBenderRange(); 00170 } 00171 00172 void Part::refresh() { 00173 backupCacheToPartials(patchCache); 00174 for (int t = 0; t < 4; t++) { 00175 // Common parameters, stored redundantly 00176 patchCache[t].dirty = true; 00177 patchCache[t].reverb = patchTemp->patch.reverbSwitch > 0; 00178 } 00179 memcpy(currentInstr, timbreTemp->common.name, 10); 00180 updatePitchBenderRange(); 00181 } 00182 00183 const char *Part::getCurrentInstr() const { 00184 return ¤tInstr[0]; 00185 } 00186 00187 void RhythmPart::refreshTimbre(unsigned int absTimbreNum) { 00188 for (int m = 0; m < 85; m++) { 00189 if (rhythmTemp[m].timbre == absTimbreNum - 128) { 00190 drumCache[m][0].dirty = true; 00191 } 00192 } 00193 } 00194 00195 void Part::refreshTimbre(unsigned int absTimbreNum) { 00196 if (getAbsTimbreNum() == absTimbreNum) { 00197 memcpy(currentInstr, timbreTemp->common.name, 10); 00198 patchCache[0].dirty = true; 00199 } 00200 } 00201 00202 void Part::setPatch(const PatchParam *patch) { 00203 patchTemp->patch = *patch; 00204 } 00205 00206 void RhythmPart::setTimbre(TimbreParam * /*timbre*/) { 00207 synth->printDebug("%s: Attempted to call setTimbre() - doesn't make sense for rhythm", name); 00208 } 00209 00210 void Part::setTimbre(TimbreParam *timbre) { 00211 *timbreTemp = *timbre; 00212 synth->newTimbreSet(partNum, timbre->common.name); 00213 } 00214 00215 unsigned int RhythmPart::getAbsTimbreNum() const { 00216 synth->printDebug("%s: Attempted to call getAbsTimbreNum() - doesn't make sense for rhythm", name); 00217 return 0; 00218 } 00219 00220 unsigned int Part::getAbsTimbreNum() const { 00221 return (patchTemp->patch.timbreGroup * 64) + patchTemp->patch.timbreNum; 00222 } 00223 00224 #if MT32EMU_MONITOR_MIDI > 0 00225 void RhythmPart::setProgram(unsigned int patchNum) { 00226 synth->printDebug("%s: Attempt to set program (%d) on rhythm is invalid", name, patchNum); 00227 } 00228 #else 00229 void RhythmPart::setProgram(unsigned int) { } 00230 #endif 00231 00232 void Part::setProgram(unsigned int patchNum) { 00233 setPatch(&synth->mt32ram.patches[patchNum]); 00234 holdpedal = false; 00235 allSoundOff(); 00236 setTimbre(&synth->mt32ram.timbres[getAbsTimbreNum()].timbre); 00237 refresh(); 00238 } 00239 00240 void Part::updatePitchBenderRange() { 00241 pitchBenderRange = patchTemp->patch.benderRange * 683; 00242 } 00243 00244 void Part::backupCacheToPartials(PatchCache cache[4]) { 00245 // check if any partials are still playing with the old patch cache 00246 // if so then duplicate the cached data from the part to the partial so that 00247 // we can change the part's cache without affecting the partial. 00248 // We delay this until now to avoid a copy operation with every note played 00249 for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { 00250 poly->backupCacheToPartials(cache); 00251 } 00252 } 00253 00254 void Part::cacheTimbre(PatchCache cache[4], const TimbreParam *timbre) { 00255 backupCacheToPartials(cache); 00256 int partialCount = 0; 00257 for (int t = 0; t < 4; t++) { 00258 if (((timbre->common.partialMute >> t) & 0x1) == 1) { 00259 cache[t].playPartial = true; 00260 partialCount++; 00261 } else { 00262 cache[t].playPartial = false; 00263 continue; 00264 } 00265 00266 // Calculate and cache common parameters 00267 cache[t].srcPartial = timbre->partial[t]; 00268 00269 cache[t].pcm = timbre->partial[t].wg.pcmWave; 00270 00271 switch (t) { 00272 case 0: 00273 cache[t].PCMPartial = (PartialStruct[(int)timbre->common.partialStructure12] & 0x2) ? true : false; 00274 cache[t].structureMix = PartialMixStruct[(int)timbre->common.partialStructure12]; 00275 cache[t].structurePosition = 0; 00276 cache[t].structurePair = 1; 00277 break; 00278 case 1: 00279 cache[t].PCMPartial = (PartialStruct[(int)timbre->common.partialStructure12] & 0x1) ? true : false; 00280 cache[t].structureMix = PartialMixStruct[(int)timbre->common.partialStructure12]; 00281 cache[t].structurePosition = 1; 00282 cache[t].structurePair = 0; 00283 break; 00284 case 2: 00285 cache[t].PCMPartial = (PartialStruct[(int)timbre->common.partialStructure34] & 0x2) ? true : false; 00286 cache[t].structureMix = PartialMixStruct[(int)timbre->common.partialStructure34]; 00287 cache[t].structurePosition = 0; 00288 cache[t].structurePair = 3; 00289 break; 00290 case 3: 00291 cache[t].PCMPartial = (PartialStruct[(int)timbre->common.partialStructure34] & 0x1) ? true : false; 00292 cache[t].structureMix = PartialMixStruct[(int)timbre->common.partialStructure34]; 00293 cache[t].structurePosition = 1; 00294 cache[t].structurePair = 2; 00295 break; 00296 default: 00297 break; 00298 } 00299 00300 cache[t].partialParam = &timbre->partial[t]; 00301 00302 cache[t].waveform = timbre->partial[t].wg.waveform; 00303 } 00304 for (int t = 0; t < 4; t++) { 00305 // Common parameters, stored redundantly 00306 cache[t].dirty = false; 00307 cache[t].partialCount = partialCount; 00308 cache[t].sustain = (timbre->common.noSustain == 0); 00309 } 00310 //synth->printDebug("Res 1: %d 2: %d 3: %d 4: %d", cache[0].waveform, cache[1].waveform, cache[2].waveform, cache[3].waveform); 00311 00312 #if MT32EMU_MONITOR_INSTRUMENTS > 0 00313 synth->printDebug("%s (%s): Recached timbre", name, currentInstr); 00314 for (int i = 0; i < 4; i++) { 00315 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); 00316 } 00317 #endif 00318 } 00319 00320 const char *Part::getName() const { 00321 return name; 00322 } 00323 00324 void Part::setVolume(unsigned int midiVolume) { 00325 // CONFIRMED: This calculation matches the table used in the control ROM 00326 patchTemp->outputLevel = (Bit8u)(midiVolume * 100 / 127); 00327 //synth->printDebug("%s (%s): Set volume to %d", name, currentInstr, midiVolume); 00328 } 00329 00330 Bit8u Part::getVolume() const { 00331 return patchTemp->outputLevel; 00332 } 00333 00334 Bit8u Part::getExpression() const { 00335 return expression; 00336 } 00337 00338 void Part::setExpression(unsigned int midiExpression) { 00339 // CONFIRMED: This calculation matches the table used in the control ROM 00340 expression = (Bit8u)(midiExpression * 100 / 127); 00341 } 00342 00343 void RhythmPart::setPan(unsigned int midiPan) { 00344 // CONFIRMED: This does change patchTemp, but has no actual effect on playback. 00345 #if MT32EMU_MONITOR_MIDI > 0 00346 synth->printDebug("%s: Pointlessly setting pan (%d) on rhythm part", name, midiPan); 00347 #endif 00348 Part::setPan(midiPan); 00349 } 00350 00351 void Part::setPan(unsigned int midiPan) { 00352 // NOTE: Panning is inverted compared to GM. 00353 00354 // CM-32L: Divide by 8.5 00355 patchTemp->panpot = (Bit8u)((midiPan << 3) / 68); 00356 // FIXME: MT-32: Divide by 9 00357 //patchTemp->panpot = (Bit8u)(midiPan / 9); 00358 00359 //synth->printDebug("%s (%s): Set pan to %d", name, currentInstr, panpot); 00360 } 00361 00365 unsigned int Part::midiKeyToKey(unsigned int midiKey) { 00366 int key = midiKey + patchTemp->patch.keyShift; 00367 if (key < 36) { 00368 // After keyShift is applied, key < 36, so move up by octaves 00369 while (key < 36) { 00370 key += 12; 00371 } 00372 } else if (key > 132) { 00373 // After keyShift is applied, key > 132, so move down by octaves 00374 while (key > 132) { 00375 key -= 12; 00376 } 00377 } 00378 key -= 24; 00379 return key; 00380 } 00381 00382 void RhythmPart::noteOn(unsigned int midiKey, unsigned int velocity) { 00383 if (midiKey < 24 || midiKey > 108) { /*> 87 on MT-32)*/ 00384 synth->printDebug("%s: Attempted to play invalid key %d (velocity %d)", name, midiKey, velocity); 00385 return; 00386 } 00387 unsigned int key = midiKey; 00388 unsigned int drumNum = key - 24; 00389 int drumTimbreNum = rhythmTemp[drumNum].timbre; 00390 if (drumTimbreNum >= 127) { // 94 on MT-32 00391 synth->printDebug("%s: Attempted to play unmapped key %d (velocity %d)", name, midiKey, velocity); 00392 return; 00393 } 00394 // CONFIRMED: Two special cases described by Mok 00395 if (drumTimbreNum == 64 + 6) { 00396 noteOff(0); 00397 key = 1; 00398 } else if (drumTimbreNum == 64 + 7) { 00399 // This noteOff(0) is not performed on MT-32, only LAPC-I 00400 noteOff(0); 00401 key = 0; 00402 } 00403 int absTimbreNum = drumTimbreNum + 128; 00404 TimbreParam *timbre = &synth->mt32ram.timbres[absTimbreNum].timbre; 00405 memcpy(currentInstr, timbre->common.name, 10); 00406 if (drumCache[drumNum][0].dirty) { 00407 cacheTimbre(drumCache[drumNum], timbre); 00408 } 00409 #if MT32EMU_MONITOR_INSTRUMENTS > 0 00410 synth->printDebug("%s (%s): Start poly (drum %d, timbre %d): midiKey %u, key %u, velo %u, mod %u, exp %u, bend %u", name, currentInstr, drumNum, absTimbreNum, midiKey, key, velocity, modulation, expression, pitchBend); 00411 #if MT32EMU_MONITOR_INSTRUMENTS > 1 00412 // According to info from Mok, keyShift does not appear to affect anything on rhythm part on LAPC-I, but may do on MT-32 - needs investigation 00413 synth->printDebug(" Patch: (timbreGroup %u), (timbreNum %u), (keyShift %u), fineTune %u, benderRange %u, assignMode %u, (reverbSwitch %u)", patchTemp->patch.timbreGroup, patchTemp->patch.timbreNum, patchTemp->patch.keyShift, patchTemp->patch.fineTune, patchTemp->patch.benderRange, patchTemp->patch.assignMode, patchTemp->patch.reverbSwitch); 00414 synth->printDebug(" PatchTemp: outputLevel %u, (panpot %u)", patchTemp->outputLevel, patchTemp->panpot); 00415 synth->printDebug(" RhythmTemp: timbre %u, outputLevel %u, panpot %u, reverbSwitch %u", rhythmTemp[drumNum].timbre, rhythmTemp[drumNum].outputLevel, rhythmTemp[drumNum].panpot, rhythmTemp[drumNum].reverbSwitch); 00416 #endif 00417 #endif 00418 playPoly(drumCache[drumNum], &rhythmTemp[drumNum], midiKey, key, velocity); 00419 } 00420 00421 void Part::noteOn(unsigned int midiKey, unsigned int velocity) { 00422 unsigned int key = midiKeyToKey(midiKey); 00423 if (patchCache[0].dirty) { 00424 cacheTimbre(patchCache, timbreTemp); 00425 } 00426 #if MT32EMU_MONITOR_INSTRUMENTS > 0 00427 synth->printDebug("%s (%s): Start poly: midiKey %u, key %u, velo %u, mod %u, exp %u, bend %u", name, currentInstr, midiKey, key, velocity, modulation, expression, pitchBend); 00428 #if MT32EMU_MONITOR_INSTRUMENTS > 1 00429 synth->printDebug(" Patch: timbreGroup %u, timbreNum %u, keyShift %u, fineTune %u, benderRange %u, assignMode %u, reverbSwitch %u", patchTemp->patch.timbreGroup, patchTemp->patch.timbreNum, patchTemp->patch.keyShift, patchTemp->patch.fineTune, patchTemp->patch.benderRange, patchTemp->patch.assignMode, patchTemp->patch.reverbSwitch); 00430 synth->printDebug(" PatchTemp: outputLevel %u, panpot %u", patchTemp->outputLevel, patchTemp->panpot); 00431 #endif 00432 #endif 00433 playPoly(patchCache, NULL, midiKey, key, velocity); 00434 } 00435 00436 void Part::abortPoly(Poly *poly) { 00437 if (poly->startAbort()) { 00438 while (poly->isActive()) { 00439 if (!synth->prerender()) { 00440 synth->printDebug("%s (%s): Ran out of prerender space to abort poly gracefully", name, currentInstr); 00441 poly->terminate(); 00442 break; 00443 } 00444 } 00445 } 00446 } 00447 00448 bool Part::abortFirstPoly(unsigned int key) { 00449 for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { 00450 if (poly->getKey() == key) { 00451 abortPoly(poly); 00452 return true; 00453 } 00454 } 00455 return false; 00456 } 00457 00458 bool Part::abortFirstPoly(PolyState polyState) { 00459 for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { 00460 if (poly->getState() == polyState) { 00461 abortPoly(poly); 00462 return true; 00463 } 00464 } 00465 return false; 00466 } 00467 00468 bool Part::abortFirstPolyPreferHeld() { 00469 if (abortFirstPoly(POLY_Held)) { 00470 return true; 00471 } 00472 return abortFirstPoly(); 00473 } 00474 00475 bool Part::abortFirstPoly() { 00476 if (activePolys.isEmpty()) { 00477 return false; 00478 } 00479 abortPoly(activePolys.getFirst()); 00480 return true; 00481 } 00482 00483 void Part::playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhythmTemp, unsigned int midiKey, unsigned int key, unsigned int velocity) { 00484 // CONFIRMED: Even in single-assign mode, we don't abort playing polys if the timbre to play is completely muted. 00485 unsigned int needPartials = cache[0].partialCount; 00486 if (needPartials == 0) { 00487 synth->printDebug("%s (%s): Completely muted instrument", name, currentInstr); 00488 return; 00489 } 00490 00491 if ((patchTemp->patch.assignMode & 2) == 0) { 00492 // Single-assign mode 00493 abortFirstPoly(key); 00494 } 00495 00496 if (!synth->partialManager->freePartials(needPartials, partNum)) { 00497 #if MT32EMU_MONITOR_PARTIALS > 0 00498 synth->printDebug("%s (%s): Insufficient free partials to play key %d (velocity %d); needed=%d, free=%d, assignMode=%d", name, currentInstr, midiKey, velocity, needPartials, synth->partialManager->getFreePartialCount(), patchTemp->patch.assignMode); 00499 synth->printPartialUsage(); 00500 #endif 00501 return; 00502 } 00503 00504 if (freePolys.isEmpty()) { 00505 synth->printDebug("%s (%s): No free poly to play key %d (velocity %d)", name, currentInstr, midiKey, velocity); 00506 return; 00507 } 00508 Poly *poly = freePolys.takeFirst(); 00509 if (patchTemp->patch.assignMode & 1) { 00510 // Priority to data first received 00511 activePolys.prepend(poly); 00512 } else { 00513 activePolys.append(poly); 00514 } 00515 00516 Partial *partials[4]; 00517 for (int x = 0; x < 4; x++) { 00518 if (cache[x].playPartial) { 00519 partials[x] = synth->partialManager->allocPartial(partNum); 00520 activePartialCount++; 00521 } else { 00522 partials[x] = NULL; 00523 } 00524 } 00525 poly->reset(key, velocity, cache[0].sustain, partials); 00526 00527 for (int x = 0; x < 4; x++) { 00528 if (partials[x] != NULL) { 00529 #if MT32EMU_MONITOR_PARTIALS > 2 00530 synth->printDebug("%s (%s): Allocated partial %d", name, currentInstr, partials[x]->debugGetPartialNum()); 00531 #endif 00532 partials[x]->startPartial(this, poly, &cache[x], rhythmTemp, partials[cache[x].structurePair]); 00533 } 00534 } 00535 #if MT32EMU_MONITOR_PARTIALS > 1 00536 synth->printPartialUsage(); 00537 #endif 00538 synth->partStateChanged(partNum, true); 00539 synth->polyStateChanged(partNum); 00540 } 00541 00542 void Part::allNotesOff() { 00543 // The MIDI specification states - and Mok confirms - that all notes off (0x7B) 00544 // should treat the hold pedal as usual. 00545 for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { 00546 // FIXME: This has special handling of key 0 in NoteOff that Mok has not yet confirmed applies to AllNotesOff. 00547 // if (poly->canSustain() || poly->getKey() == 0) { 00548 // FIXME: The real devices are found to be ignoring non-sustaining polys while processing AllNotesOff. Need to be confirmed. 00549 if (poly->canSustain()) { 00550 poly->noteOff(holdpedal); 00551 } 00552 } 00553 } 00554 00555 void Part::allSoundOff() { 00556 // MIDI "All sound off" (0x78) should release notes immediately regardless of the hold pedal. 00557 // This controller is not actually implemented by the synths, though (according to the docs and Mok) - 00558 // we're only using this method internally. 00559 for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { 00560 poly->startDecay(); 00561 } 00562 } 00563 00564 void Part::stopPedalHold() { 00565 for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { 00566 poly->stopPedalHold(); 00567 } 00568 } 00569 00570 void RhythmPart::noteOff(unsigned int midiKey) { 00571 stopNote(midiKey); 00572 } 00573 00574 void Part::noteOff(unsigned int midiKey) { 00575 stopNote(midiKeyToKey(midiKey)); 00576 } 00577 00578 void Part::stopNote(unsigned int key) { 00579 #if MT32EMU_MONITOR_INSTRUMENTS > 0 00580 synth->printDebug("%s (%s): stopping key %d", name, currentInstr, key); 00581 #endif 00582 00583 for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { 00584 // Generally, non-sustaining instruments ignore note off. They die away eventually anyway. 00585 // Key 0 (only used by special cases on rhythm part) reacts to note off even if non-sustaining or pedal held. 00586 if (poly->getKey() == key && (poly->canSustain() || key == 0)) { 00587 if (poly->noteOff(holdpedal && key != 0)) { 00588 break; 00589 } 00590 } 00591 } 00592 } 00593 00594 const MemParams::PatchTemp *Part::getPatchTemp() const { 00595 return patchTemp; 00596 } 00597 00598 unsigned int Part::getActivePartialCount() const { 00599 return activePartialCount; 00600 } 00601 00602 unsigned int Part::getActiveNonReleasingPartialCount() const { 00603 unsigned int activeNonReleasingPartialCount = 0; 00604 for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { 00605 if (poly->getState() != POLY_Releasing) { 00606 activeNonReleasingPartialCount += poly->getActivePartialCount(); 00607 } 00608 } 00609 return activeNonReleasingPartialCount; 00610 } 00611 00612 void Part::partialDeactivated(Poly *poly) { 00613 activePartialCount--; 00614 if (!poly->isActive()) { 00615 activePolys.remove(poly); 00616 freePolys.prepend(poly); 00617 synth->polyStateChanged(partNum); 00618 } 00619 if (activePartialCount == 0) { 00620 synth->partStateChanged(partNum, false); 00621 } 00622 } 00623 00624 //#define POLY_LIST_DEBUG 00625 00626 PolyList::PolyList() : firstPoly(NULL), lastPoly(NULL) {} 00627 00628 bool PolyList::isEmpty() const { 00629 #ifdef POLY_LIST_DEBUG 00630 if ((firstPoly == NULL || lastPoly == NULL) && firstPoly != lastPoly) { 00631 printf("PolyList: desynchronised firstPoly & lastPoly pointers\n"); 00632 } 00633 #endif 00634 return firstPoly == NULL && lastPoly == NULL; 00635 } 00636 00637 Poly *PolyList::getFirst() const { 00638 return firstPoly; 00639 } 00640 00641 Poly *PolyList::getLast() const { 00642 return lastPoly; 00643 } 00644 00645 void PolyList::prepend(Poly *poly) { 00646 #ifdef POLY_LIST_DEBUG 00647 if (poly->getNext() != NULL) { 00648 printf("PolyList: Non-NULL next field in a Poly being prepended is ignored\n"); 00649 } 00650 #endif 00651 poly->setNext(firstPoly); 00652 firstPoly = poly; 00653 if (lastPoly == NULL) { 00654 lastPoly = poly; 00655 } 00656 } 00657 00658 void PolyList::append(Poly *poly) { 00659 #ifdef POLY_LIST_DEBUG 00660 if (poly->getNext() != NULL) { 00661 printf("PolyList: Non-NULL next field in a Poly being appended is ignored\n"); 00662 } 00663 #endif 00664 poly->setNext(NULL); 00665 if (lastPoly != NULL) { 00666 #ifdef POLY_LIST_DEBUG 00667 if (lastPoly->getNext() != NULL) { 00668 printf("PolyList: Non-NULL next field in the lastPoly\n"); 00669 } 00670 #endif 00671 lastPoly->setNext(poly); 00672 } 00673 lastPoly = poly; 00674 if (firstPoly == NULL) { 00675 firstPoly = poly; 00676 } 00677 } 00678 00679 Poly *PolyList::takeFirst() { 00680 Poly *oldFirst = firstPoly; 00681 firstPoly = oldFirst->getNext(); 00682 if (firstPoly == NULL) { 00683 #ifdef POLY_LIST_DEBUG 00684 if (lastPoly != oldFirst) { 00685 printf("PolyList: firstPoly != lastPoly in a list with a single Poly\n"); 00686 } 00687 #endif 00688 lastPoly = NULL; 00689 } 00690 oldFirst->setNext(NULL); 00691 return oldFirst; 00692 } 00693 00694 void PolyList::remove(Poly * const polyToRemove) { 00695 if (polyToRemove == firstPoly) { 00696 takeFirst(); 00697 return; 00698 } 00699 for (Poly *poly = firstPoly; poly != NULL; poly = poly->getNext()) { 00700 if (poly->getNext() == polyToRemove) { 00701 if (polyToRemove == lastPoly) { 00702 #ifdef POLY_LIST_DEBUG 00703 if (lastPoly->getNext() != NULL) { 00704 printf("PolyList: Non-NULL next field in the lastPoly\n"); 00705 } 00706 #endif 00707 lastPoly = poly; 00708 } 00709 poly->setNext(polyToRemove->getNext()); 00710 polyToRemove->setNext(NULL); 00711 break; 00712 } 00713 } 00714 } 00715 00716 // TODO: WE NEED TO REFRESH THIS (FROM) 00717 const Poly *Part::getActivePoly(int num) 00718 { 00719 if( (size_t)num >= sizeof(activePolys) ) return NULL; 00720 00721 for( Poly* polyIt = activePolys.getFirst(); polyIt != activePolys.getLast(); polyIt++ ) { 00722 if( num == 0 ) return polyIt; 00723 00724 num--; 00725 } 00726 00727 return NULL; 00728 } 00729 00730 00731 int Part::getActivePolyCount() 00732 { 00733 return sizeof(activePolys); 00734 } 00735 // TODO: WE NEED TO REFRESH THIS (TO) 00736 00737 const PatchCache *Part::getPatchCache(int num) 00738 { 00739 return &patchCache[num]; 00740 } 00741 00742 00743 const PatchCache *RhythmPart::getDrumCache(int num1, int num2) 00744 { 00745 return &drumCache[num1][num2]; 00746 } 00747 00748 }