DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/mt32/PartialManager.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 <cstring>
00019 
00020 #include "mt32emu.h"
00021 #include "PartialManager.h"
00022 #include "FileStream.h"
00023 
00024 namespace MT32Emu {
00025 
00026 PartialManager::PartialManager(Synth *useSynth, Part **useParts) {
00027         synth = useSynth;
00028         parts = useParts;
00029         for (unsigned int i = 0; i < synth->getPartialLimit(); i++) {
00030                 partialTable[i] = new Partial(synth, i);
00031         }
00032 }
00033 
00034 PartialManager::~PartialManager(void) {
00035         for (unsigned int i = 0; i < synth->getPartialLimit(); i++) {
00036                 delete partialTable[i];
00037         }
00038 }
00039 
00040 void PartialManager::clearAlreadyOutputed() {
00041         for (unsigned int i = 0; i < synth->getPartialLimit(); i++) {
00042                 partialTable[i]->alreadyOutputed = false;
00043         }
00044 }
00045 
00046 bool PartialManager::shouldReverb(int i) {
00047         return partialTable[i]->shouldReverb();
00048 }
00049 
00050 bool PartialManager::produceOutput(int i, float *leftBuf, float *rightBuf, Bit32u bufferLength) {
00051         return partialTable[i]->produceOutput(leftBuf, rightBuf, bufferLength);
00052 }
00053 
00054 void PartialManager::deactivateAll() {
00055         for (unsigned int i = 0; i < synth->getPartialLimit(); i++) {
00056                 partialTable[i]->deactivate();
00057         }
00058 }
00059 
00060 unsigned int PartialManager::setReserve(Bit8u *rset) {
00061         unsigned int pr = 0;
00062         for (unsigned int x = 0; x <= 8; x++) {
00063                 numReservedPartialsForPart[x] = rset[x];
00064                 pr += rset[x];
00065         }
00066         return pr;
00067 }
00068 
00069 Partial *PartialManager::allocPartial(int partNum) {
00070         Partial *outPartial = NULL;
00071 
00072         // Get the first inactive partial
00073         for (unsigned int partialNum = 0; partialNum < synth->getPartialLimit(); partialNum++) {
00074                 if (!partialTable[partialNum]->isActive()) {
00075                         outPartial = partialTable[partialNum];
00076                         break;
00077                 }
00078         }
00079         if (outPartial != NULL) {
00080                 outPartial->activate(partNum);
00081         }
00082         return outPartial;
00083 }
00084 
00085 unsigned int PartialManager::getFreePartialCount(void) {
00086         unsigned int count = 0;
00087         for (unsigned int i = 0; i < synth->getPartialLimit(); i++) {
00088                 if (!partialTable[i]->isActive()) {
00089                         count++;
00090                 }
00091         }
00092         return count;
00093 }
00094 
00095 // This function is solely used to gather data for debug output at the moment.
00096 void PartialManager::getPerPartPartialUsage(unsigned int perPartPartialUsage[9]) {
00097         memset(perPartPartialUsage, 0, 9 * sizeof(unsigned int));
00098         for (unsigned int i = 0; i < synth->getPartialLimit(); i++) {
00099                 if (partialTable[i]->isActive()) {
00100                         perPartPartialUsage[partialTable[i]->getOwnerPart()]++;
00101                 }
00102         }
00103 }
00104 
00105 // Finds the lowest-priority part that is exceeding its reserved partial allocation and has a poly
00106 // in POLY_Releasing, then kills its first releasing poly.
00107 // Parts with higher priority than minPart are not checked.
00108 // Assumes that getFreePartials() has been called to make numReservedPartialsForPart up-to-date.
00109 bool PartialManager::abortFirstReleasingPolyWhereReserveExceeded(int minPart) {
00110         if (minPart == 8) {
00111                 // Rhythm is highest priority
00112                 minPart = -1;
00113         }
00114         for (int partNum = 7; partNum >= minPart; partNum--) {
00115                 int usePartNum = partNum == -1 ? 8 : partNum;
00116                 if (parts[usePartNum]->getActivePartialCount() > numReservedPartialsForPart[usePartNum]) {
00117                         // This part has exceeded its reserved partial count.
00118                         // If it has any releasing polys, kill its first one and we're done.
00119                         if (parts[usePartNum]->abortFirstPoly(POLY_Releasing)) {
00120                                 return true;
00121                         }
00122                 }
00123         }
00124         return false;
00125 }
00126 
00127 // Finds the lowest-priority part that is exceeding its reserved partial allocation and has a poly, then kills
00128 // its first poly in POLY_Held - or failing that, its first poly in any state.
00129 // Parts with higher priority than minPart are not checked.
00130 // Assumes that getFreePartials() has been called to make numReservedPartialsForPart up-to-date.
00131 bool PartialManager::abortFirstPolyPreferHeldWhereReserveExceeded(int minPart) {
00132         if (minPart == 8) {
00133                 // Rhythm is highest priority
00134                 minPart = -1;
00135         }
00136         for (int partNum = 7; partNum >= minPart; partNum--) {
00137                 int usePartNum = partNum == -1 ? 8 : partNum;
00138                 if (parts[usePartNum]->getActivePartialCount() > numReservedPartialsForPart[usePartNum]) {
00139                         // This part has exceeded its reserved partial count.
00140                         // If it has any polys, kill its first (preferably held) one and we're done.
00141                         if (parts[usePartNum]->abortFirstPolyPreferHeld()) {
00142                                 return true;
00143                         }
00144                 }
00145         }
00146         return false;
00147 }
00148 
00149 bool PartialManager::freePartials(unsigned int needed, int partNum) {
00150         // CONFIRMED: Barring bugs, this matches the real LAPC-I according to information from Mok.
00151 
00152         // BUG: There's a bug in the LAPC-I implementation:
00153         // When allocating for rhythm part, or when allocating for a part that is using fewer partials than it has reserved,
00154         // held and playing polys on the rhythm part can potentially be aborted before releasing polys on the rhythm part.
00155         // This bug isn't present on MT-32.
00156         // I consider this to be a bug because I think that playing polys should always have priority over held polys,
00157         // and held polys should always have priority over releasing polys.
00158 
00159         // NOTE: This code generally aborts polys in parts (according to certain conditions) in the following order:
00160         // 7, 6, 5, 4, 3, 2, 1, 0, 8 (rhythm)
00161         // (from lowest priority, meaning most likely to have polys aborted, to highest priority, meaning least likely)
00162 
00163         if (needed == 0) {
00164                 return true;
00165         }
00166 
00167         // Note that calling getFreePartialCount() also ensures that numReservedPartialsPerPart is up-to-date
00168         if (getFreePartialCount() >= needed) {
00169                 return true;
00170         }
00171 
00172         // Note: These #ifdefs are temporary until we have proper "quirk" configuration.
00173         // Also, the MT-32 version isn't properly confirmed yet.
00174 #ifdef MT32EMU_QUIRK_FREE_PARTIALS_MT32
00175         // On MT-32, we bail out before even killing releasing partials if the allocating part has exceeded its reserve and is configured for priority-to-earlier-polys.
00176         if (parts[partNum]->getActiveNonReleasingPartialCount() + needed > numReservedPartialsForPart[partNum] && (synth->getPart(partNum)->getPatchTemp()->patch.assignMode & 1)) {
00177                 return false;
00178         }
00179 #endif
00180 
00181         for (;;) {
00182 #ifdef MT32EMU_QUIRK_FREE_PARTIALS_MT32
00183                 // Abort releasing polys in parts that have exceeded their partial reservation (working backwards from part 7, with rhythm last)
00184                 if (!abortFirstReleasingPolyWhereReserveExceeded(-1)) {
00185                         break;
00186                 }
00187 #else
00188                 // Abort releasing polys in non-rhythm parts that have exceeded their partial reservation (working backwards from part 7)
00189                 if (!abortFirstReleasingPolyWhereReserveExceeded(0)) {
00190                         break;
00191                 }
00192 #endif
00193                 if (getFreePartialCount() >= needed) {
00194                         return true;
00195                 }
00196         }
00197 
00198         if (parts[partNum]->getActiveNonReleasingPartialCount() + needed > numReservedPartialsForPart[partNum]) {
00199                 // With the new partials we're freeing for, we would end up using more partials than we have reserved.
00200                 if (synth->getPart(partNum)->getPatchTemp()->patch.assignMode & 1) {
00201                         // Priority is given to earlier polys, so just give up
00202                         return false;
00203                 }
00204                 // Only abort held polys in the target part and parts that have a lower priority
00205                 // (higher part number = lower priority, except for rhythm, which has the highest priority).
00206                 for (;;) {
00207                         if (!abortFirstPolyPreferHeldWhereReserveExceeded(partNum)) {
00208                                 break;
00209                         }
00210                         if (getFreePartialCount() >= needed) {
00211                                 return true;
00212                         }
00213                 }
00214                 if (needed > numReservedPartialsForPart[partNum]) {
00215                         return false;
00216                 }
00217         } else {
00218                 // At this point, we're certain that we've reserved enough partials to play our poly.
00219                 // Check all parts from lowest to highest priority to see whether they've exceeded their
00220                 // reserve, and abort their polys until until we have enough free partials or they're within
00221                 // their reserve allocation.
00222                 for (;;) {
00223                         if (!abortFirstPolyPreferHeldWhereReserveExceeded(-1)) {
00224                                 break;
00225                         }
00226                         if (getFreePartialCount() >= needed) {
00227                                 return true;
00228                         }
00229                 }
00230         }
00231 
00232         // Abort polys in the target part until there are enough free partials for the new one
00233         for (;;) {
00234                 if (!parts[partNum]->abortFirstPolyPreferHeld()) {
00235                         break;
00236                 }
00237                 if (getFreePartialCount() >= needed) {
00238                         return true;
00239                 }
00240         }
00241 
00242         // Aww, not enough partials for you.
00243         return false;
00244 }
00245 
00246 const Partial *PartialManager::getPartial(unsigned int partialNum) const {
00247         if (partialNum > synth->getPartialLimit() - 1) {
00248                 return NULL;
00249         }
00250         return partialTable[partialNum];
00251 }
00252 
00253 }