DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/mt32/Part.cpp
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 &currentInstr[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 }