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 <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 }