DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/mt32/Synth.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 <cerrno>
00019 #include <cmath>
00020 #include <cstdlib>
00021 #include <cstring>
00022 #include <stdexcept>
00023 #include <exception>
00024 
00025 #include "mt32emu.h"
00026 #include "mmath.h"
00027 #include "PartialManager.h"
00028 
00029 #if MT32EMU_USE_REVERBMODEL == 1
00030 #include "AReverbModel.h"
00031 #elif MT32EMU_USE_REVERBMODEL == 2
00032 #include "BReverbModel.h"
00033 #else
00034 #include "FreeverbModel.h"
00035 #endif
00036 #include "DelayReverb.h"
00037 
00038 namespace MT32Emu {
00039 
00040 static const ControlROMMap ControlROMMaps[7] = {
00041     // ID    IDc IDbytes                     PCMmap  PCMc  tmbrA   tmbrAO, tmbrAC tmbrB   tmbrBO, tmbrBC tmbrR   trC  rhythm  rhyC  rsrv    panpot  prog    rhyMax  patMax  sysMax  timMax
00042     {0x4014, 22, "\000 ver1.04 14 July 87 ", 0x3000,  128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200,  30, 0x73A6,  85,  0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A},
00043     {0x4014, 22, "\000 ver1.05 06 Aug, 87 ", 0x3000,  128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200,  30, 0x7414,  85,  0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A},
00044     {0x4014, 22, "\000 ver1.06 31 Aug, 87 ", 0x3000,  128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200,  30, 0x7414,  85,  0x57D9, 0x57F4, 0x57E2, 0x5264, 0x5270, 0x5280, 0x521C},
00045     {0x4010, 22, "\000 ver1.07 10 Oct, 87 ", 0x3000,  128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200,  30, 0x73fe,  85,  0x57B1, 0x57CC, 0x57BA, 0x523C, 0x5248, 0x5258, 0x51F4}, // MT-32 revision 1
00046     {0x4010, 22, "\000verX.XX  30 Sep, 88 ", 0x3000,  128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200,  30, 0x741C,  85,  0x57E5, 0x5800, 0x57EE, 0x5270, 0x527C, 0x528C, 0x5228}, // MT-32 Blue Ridge mod
00047     {0x2205, 22, "\000CM32/LAPC1.00 890404", 0x8100,  256, 0x8000, 0x8000, false, 0x8080, 0x8000, false, 0x8500,  64, 0x8580,  85,  0x4F65, 0x4F80, 0x4F6E, 0x48A1, 0x48A5, 0x48BE, 0x48D5},
00048     {0x2205, 22, "\000CM32/LAPC1.02 891205", 0x8100,  256, 0x8000, 0x8000, true,  0x8080, 0x8000, true,  0x8500,  64, 0x8580,  85,  0x4F93, 0x4FAE, 0x4F9C, 0x48CB, 0x48CF, 0x48E8, 0x48FF}  // CM-32L
00049     // (Note that all but CM-32L ROM actually have 86 entries for rhythmTemp)
00050 };
00051 
00052 static inline Bit16s *streamOffset(Bit16s *stream, Bit32u pos) {
00053     return stream == NULL ? NULL : stream + pos;
00054 }
00055 
00056 static inline void clearIfNonNull(Bit16s *stream, Bit32u len) {
00057     if (stream != NULL) {
00058         memset(stream, 0, len * sizeof(Bit16s));
00059     }
00060 }
00061 
00062 static inline void mix(float *target, const float *stream, Bit32u len) {
00063     while (len--) {
00064         *target += *stream;
00065         stream++;
00066         target++;
00067     }
00068 }
00069 
00070 static inline void clearFloats(float *leftBuf, float *rightBuf, Bit32u len) {
00071     // FIXME: Use memset() where compatibility is guaranteed (if this turns out to be a win)
00072     while (len--) {
00073         *leftBuf++ = 0.0f;
00074         *rightBuf++ = 0.0f;
00075     }
00076 }
00077 
00078 static inline Bit16s clipBit16s(Bit32s a) {
00079     // Clamp values above 32767 to 32767, and values below -32768 to -32768
00080     if ((a + 32768) & ~65535) {
00081         return (a >> 31) ^ 32767;
00082     }
00083     return a;
00084 }
00085 
00086 static void floatToBit16s_nice(Bit16s *target, const float *source, Bit32u len, float outputGain) {
00087     float gain = outputGain * 16384.0f;
00088     while (len--) {
00089         // Since we're not shooting for accuracy here, don't worry about the rounding mode.
00090         *target = clipBit16s((Bit32s)(*source * gain));
00091         source++;
00092         target++;
00093     }
00094 }
00095 
00096 static void floatToBit16s_pure(Bit16s *target, const float *source, Bit32u len, float /*outputGain*/) {
00097     while (len--) {
00098         *target = clipBit16s((Bit32s)floor(*source * 8192.0f));
00099         source++;
00100         target++;
00101     }
00102 }
00103 
00104 static void floatToBit16s_reverb(Bit16s *target, const float *source, Bit32u len, float outputGain) {
00105     float gain = outputGain * 8192.0f;
00106     while (len--) {
00107         *target = clipBit16s((Bit32s)floor(*source * gain));
00108         source++;
00109         target++;
00110     }
00111 }
00112 
00113 static void floatToBit16s_generation1(Bit16s *target, const float *source, Bit32u len, float outputGain) {
00114     float gain = outputGain * 8192.0f;
00115     while (len--) {
00116         *target = clipBit16s((Bit32s)floor(*source * gain));
00117         *target = (*target & 0x8000) | ((*target << 1) & 0x7FFE);
00118         source++;
00119         target++;
00120     }
00121 }
00122 
00123 static void floatToBit16s_generation2(Bit16s *target, const float *source, Bit32u len, float outputGain) {
00124     float gain = outputGain * 8192.0f;
00125     while (len--) {
00126         *target = clipBit16s((Bit32s)floor(*source * gain));
00127         *target = (*target & 0x8000) | ((*target << 1) & 0x7FFE) | ((*target >> 14) & 0x0001);
00128         source++;
00129         target++;
00130     }
00131 }
00132 
00133 Bit8u Synth::calcSysexChecksum(const Bit8u *data, Bit32u len, Bit8u checksum) {
00134     for (unsigned int i = 0; i < len; i++) {
00135         checksum = checksum + data[i];
00136     }
00137     checksum = checksum & 0x7f;
00138     if (checksum) {
00139         checksum = 0x80 - checksum;
00140     }
00141     return checksum;
00142 }
00143 
00144 Synth::Synth(ReportHandler *useReportHandler) {
00145     isOpen = false;
00146     reverbEnabled = true;
00147     reverbOverridden = false;
00148 
00149     if (useReportHandler == NULL) {
00150         reportHandler = new ReportHandler;
00151         isDefaultReportHandler = true;
00152     } else {
00153         reportHandler = useReportHandler;
00154         isDefaultReportHandler = false;
00155     }
00156 
00157 #if MT32EMU_USE_REVERBMODEL == 1
00158     reverbModels[REVERB_MODE_ROOM] = new AReverbModel(REVERB_MODE_ROOM);
00159     reverbModels[REVERB_MODE_HALL] = new AReverbModel(REVERB_MODE_HALL);
00160     reverbModels[REVERB_MODE_PLATE] = new AReverbModel(REVERB_MODE_PLATE);
00161     reverbModels[REVERB_MODE_TAP_DELAY] = new DelayReverb();
00162 #elif MT32EMU_USE_REVERBMODEL == 2
00163     reverbModels[REVERB_MODE_ROOM] = new BReverbModel(REVERB_MODE_ROOM);
00164     reverbModels[REVERB_MODE_HALL] = new BReverbModel(REVERB_MODE_HALL);
00165     reverbModels[REVERB_MODE_PLATE] = new BReverbModel(REVERB_MODE_PLATE);
00166     reverbModels[REVERB_MODE_TAP_DELAY] = new BReverbModel(REVERB_MODE_TAP_DELAY);
00167 #else
00168     reverbModels[REVERB_MODE_ROOM] = new FreeverbModel(0.76f, 0.687770909f, 0.63f, 0, 0.5f);
00169     reverbModels[REVERB_MODE_HALL] = new FreeverbModel(2.0f, 0.712025098f, 0.86f, 1, 0.5f);
00170     reverbModels[REVERB_MODE_PLATE] = new FreeverbModel(0.4f, 0.939522749f, 0.38f, 2, 0.05f);
00171     reverbModels[REVERB_MODE_TAP_DELAY] = new DelayReverb();
00172 #endif
00173 
00174     reverbModel = NULL;
00175     setDACInputMode(DACInputMode_NICE);
00176     setOutputGain(1.0f);
00177     setReverbOutputGain(0.68f);
00178     partialManager = NULL;
00179     memset(parts, 0, sizeof(parts));
00180     renderedSampleCount = 0;
00181 
00182     partialLimit = MT32EMU_MAX_PARTIALS;
00183 }
00184 
00185 Synth::~Synth() {
00186     close(); // Make sure we're closed and everything is freed
00187     for (int i = 0; i < 4; i++) {
00188         delete reverbModels[i];
00189     }
00190     if (isDefaultReportHandler) {
00191         delete reportHandler;
00192     }
00193 }
00194 
00195 void ReportHandler::showLCDMessage(const char *data) {
00196     printf("WRITE-LCD: %s", data);
00197     printf("\n");
00198 }
00199 
00200 void ReportHandler::printDebug(const char *fmt, va_list list) {
00201         vprintf(fmt, list);
00202         printf("\n");
00203 }
00204 
00205 void Synth::partStateChanged(int partNum, bool isPartActive) {
00206     reportHandler->onPartStateChanged(partNum, isPartActive);
00207 }
00208 
00209 void Synth::polyStateChanged(int partNum) {
00210     reportHandler->onPolyStateChanged(partNum);
00211 }
00212 
00213 void Synth::partialStateChanged(const Partial * const partial, int oldPartialPhase, int newPartialPhase) {
00214     for (unsigned int i = 0; i < getPartialLimit(); i++) {
00215         if (getPartial(i) == partial) {
00216             reportHandler->onPartialStateChanged(i, oldPartialPhase, newPartialPhase);
00217             break;
00218         }
00219     }
00220 }
00221 
00222 void Synth::newTimbreSet(int partNum, char patchName[]) {
00223     reportHandler->onProgramChanged(partNum, patchName);
00224 }
00225 
00226 void Synth::printDebug(const char *fmt, ...) {
00227     va_list ap;
00228     va_start(ap, fmt);
00229 #if MT32EMU_DEBUG_SAMPLESTAMPS > 0
00230     reportHandler->printDebug("[%u] ", renderedSampleCount);
00231 #endif
00232     reportHandler->printDebug(fmt, ap);
00233     va_end(ap);
00234 }
00235 
00236 void Synth::setReverbEnabled(bool newReverbEnabled) {
00237     reverbEnabled = newReverbEnabled;
00238 }
00239 
00240 bool Synth::isReverbEnabled() const {
00241     return reverbEnabled;
00242 }
00243 
00244 void Synth::setReverbOverridden(bool newReverbOverridden) {
00245     reverbOverridden = newReverbOverridden;
00246 }
00247 
00248 bool Synth::isReverbOverridden() const {
00249     return reverbOverridden;
00250 }
00251 
00252 void Synth::setDACInputMode(DACInputMode mode) {
00253     switch(mode) {
00254     case DACInputMode_GENERATION1:
00255         la32FloatToBit16sFunc = floatToBit16s_generation1;
00256         reverbFloatToBit16sFunc = floatToBit16s_reverb;
00257         break;
00258     case DACInputMode_GENERATION2:
00259         la32FloatToBit16sFunc = floatToBit16s_generation2;
00260         reverbFloatToBit16sFunc = floatToBit16s_reverb;
00261         break;
00262     case DACInputMode_PURE:
00263         la32FloatToBit16sFunc = floatToBit16s_pure;
00264         reverbFloatToBit16sFunc = floatToBit16s_pure;
00265         break;
00266     case DACInputMode_NICE:
00267     default:
00268         la32FloatToBit16sFunc = floatToBit16s_nice;
00269         reverbFloatToBit16sFunc = floatToBit16s_reverb;
00270         break;
00271     }
00272 }
00273 
00274 void Synth::setOutputGain(float newOutputGain) {
00275     outputGain = newOutputGain;
00276 }
00277 
00278 void Synth::setReverbOutputGain(float newReverbOutputGain) {
00279     reverbOutputGain = newReverbOutputGain;
00280 }
00281 
00282 bool Synth::loadControlROM(const ROMImage &controlROMImage) {
00283 //    if (&controlROMImage == NULL) return false;
00284     File *file = controlROMImage.getFile();
00285     const ROMInfo *controlROMInfo = controlROMImage.getROMInfo();
00286     if ((controlROMInfo == NULL)
00287             || (controlROMInfo->type != ROMInfo::Control)
00288             || (controlROMInfo->pairType != ROMInfo::Full)) {
00289         return false;
00290     }
00291 #if MT32EMU_MONITOR_INIT
00292     printDebug("Found Control ROM: %s, %s", controlROMInfo->shortName, controlROMInfo->description);
00293 #endif
00294     const Bit8u *fileData = file->getData();
00295     memcpy(controlROMData, fileData, CONTROL_ROM_SIZE);
00296 
00297     // Control ROM successfully loaded, now check whether it's a known type
00298     controlROMMap = NULL;
00299     for (unsigned int i = 0; i < sizeof(ControlROMMaps) / sizeof(ControlROMMaps[0]); i++) {
00300         if (memcmp(&controlROMData[ControlROMMaps[i].idPos], ControlROMMaps[i].idBytes, ControlROMMaps[i].idLen) == 0) {
00301             controlROMMap = &ControlROMMaps[i];
00302             return true;
00303         }
00304     }
00305 #if MT32EMU_MONITOR_INIT
00306     printDebug("Control ROM failed to load");
00307 #endif
00308     return false;
00309 }
00310 
00311 bool Synth::loadPCMROM(const ROMImage &pcmROMImage) {
00312 //    if (&pcmROMImage == NULL) return false;
00313     File *file = pcmROMImage.getFile();
00314     const ROMInfo *pcmROMInfo = pcmROMImage.getROMInfo();
00315     if ((pcmROMInfo == NULL)
00316             || (pcmROMInfo->type != ROMInfo::PCM)
00317             || (pcmROMInfo->pairType != ROMInfo::Full)) {
00318         return false;
00319     }
00320 #if MT32EMU_MONITOR_INIT
00321     printDebug("Found PCM ROM: %s, %s", pcmROMInfo->shortName, pcmROMInfo->description);
00322 #endif
00323     size_t fileSize = file->getSize();
00324     if (fileSize != (2 * pcmROMSize)) {
00325 #if MT32EMU_MONITOR_INIT
00326         printDebug("PCM ROM file has wrong size (expected %d, got %d)", 2 * pcmROMSize, fileSize);
00327 #endif
00328         return false;
00329     }
00330     const Bit8u *fileData = file->getData();
00331     for (size_t i = 0; i < pcmROMSize; i++) {
00332         Bit8u s = *(fileData++);
00333         Bit8u c = *(fileData++);
00334 
00335         int order[16] = {0, 9, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 8};
00336 
00337         signed short log = 0;
00338         for (int u = 0; u < 15; u++) {
00339             int bit;
00340             if (order[u] < 8) {
00341                 bit = (s >> (7 - order[u])) & 0x1;
00342             } else {
00343                 bit = (c >> (7 - (order[u] - 8))) & 0x1;
00344             }
00345             log = log | (short)(bit << (15 - u));
00346         }
00347         pcmROMData[i] = log;
00348     }
00349     return true;
00350 }
00351 
00352 bool Synth::initPCMList(Bit16u mapAddress, Bit16u count) {
00353     ControlROMPCMStruct *tps = (ControlROMPCMStruct *)&controlROMData[mapAddress];
00354     for (int i = 0; i < count; i++) {
00355         size_t rAddr = tps[i].pos * 0x800;
00356         size_t rLenExp = (tps[i].len & 0x70) >> 4;
00357         size_t rLen = 0x800 << rLenExp;
00358         if (rAddr + rLen > pcmROMSize) {
00359             printDebug("Control ROM error: Wave map entry %d points to invalid PCM address 0x%04X, length 0x%04X", i, rAddr, rLen);
00360             return false;
00361         }
00362         pcmWaves[i].addr = (Bit32u)rAddr;
00363         pcmWaves[i].len = (Bit32u)rLen;
00364         pcmWaves[i].loop = (tps[i].len & 0x80) != 0;
00365         pcmWaves[i].controlROMPCMStruct = &tps[i];
00366         //int pitch = (tps[i].pitchMSB << 8) | tps[i].pitchLSB;
00367         //bool unaffectedByMasterTune = (tps[i].len & 0x01) == 0;
00368         //printDebug("PCM %d: pos=%d, len=%d, pitch=%d, loop=%s, unaffectedByMasterTune=%s", i, rAddr, rLen, pitch, pcmWaves[i].loop ? "YES" : "NO", unaffectedByMasterTune ? "YES" : "NO");
00369     }
00370     return false;
00371 }
00372 
00373 bool Synth::initCompressedTimbre(int timbreNum, const Bit8u *src, unsigned int srcLen) {
00374     // "Compressed" here means that muted partials aren't present in ROM (except in the case of partial 0 being muted).
00375     // Instead the data from the previous unmuted partial is used.
00376     if (srcLen < sizeof(TimbreParam::CommonParam)) {
00377         return false;
00378     }
00379     TimbreParam *timbre = &mt32ram.timbres[timbreNum].timbre;
00380     timbresMemoryRegion->write(timbreNum, 0, src, sizeof(TimbreParam::CommonParam), true);
00381     unsigned int srcPos = sizeof(TimbreParam::CommonParam);
00382     unsigned int memPos = sizeof(TimbreParam::CommonParam);
00383     for (int t = 0; t < 4; t++) {
00384         if (t != 0 && ((timbre->common.partialMute >> t) & 0x1) == 0x00) {
00385             // This partial is muted - we'll copy the previously copied partial, then
00386             srcPos -= sizeof(TimbreParam::PartialParam);
00387         } else if (srcPos + sizeof(TimbreParam::PartialParam) >= srcLen) {
00388             return false;
00389         }
00390         timbresMemoryRegion->write(timbreNum, memPos, src + srcPos, sizeof(TimbreParam::PartialParam));
00391         srcPos += sizeof(TimbreParam::PartialParam);
00392         memPos += sizeof(TimbreParam::PartialParam);
00393     }
00394     return true;
00395 }
00396 
00397 bool Synth::initTimbres(Bit16u mapAddress, Bit16u offset, int count, int startTimbre, bool compressed) {
00398     const Bit8u *timbreMap = &controlROMData[mapAddress];
00399     for (Bit16u i = 0; i < count * 2; i += 2) {
00400         Bit16u address = (timbreMap[i + 1] << 8) | timbreMap[i];
00401         if (!compressed && (address + offset + sizeof(TimbreParam) > CONTROL_ROM_SIZE)) {
00402             printDebug("Control ROM error: Timbre map entry 0x%04x for timbre %d points to invalid timbre address 0x%04x", i, startTimbre, address);
00403             return false;
00404         }
00405         address += offset;
00406         if (compressed) {
00407             if (!initCompressedTimbre(startTimbre, &controlROMData[address], CONTROL_ROM_SIZE - address)) {
00408                 printDebug("Control ROM error: Timbre map entry 0x%04x for timbre %d points to invalid timbre at 0x%04x", i, startTimbre, address);
00409                 return false;
00410             }
00411         } else {
00412             timbresMemoryRegion->write(startTimbre, 0, &controlROMData[address], sizeof(TimbreParam), true);
00413         }
00414         startTimbre++;
00415     }
00416     return true;
00417 }
00418 
00419 bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage) {
00420     if (isOpen) {
00421         return false;
00422     }
00423     prerenderReadIx = prerenderWriteIx = 0;
00424 #if MT32EMU_MONITOR_INIT
00425     printDebug("Initialising Constant Tables");
00426 #endif
00427 #if !MT32EMU_REDUCE_REVERB_MEMORY
00428     for (int i = 0; i < 4; i++) {
00429         reverbModels[i]->open(useProp.sampleRate);
00430     }
00431 #endif
00432 
00433     // This is to help detect bugs
00434     memset(&mt32ram, '?', sizeof(mt32ram));
00435 
00436 #if MT32EMU_MONITOR_INIT
00437     printDebug("Loading Control ROM");
00438 #endif
00439     if (!loadControlROM(controlROMImage)) {
00440         printDebug("Init Error - Missing or invalid Control ROM image");
00441         reportHandler->onErrorControlROM();
00442         return false;
00443     }
00444 
00445     initMemoryRegions();
00446 
00447     // 512KB PCM ROM for MT-32, etc.
00448     // 1MB PCM ROM for CM-32L, LAPC-I, CM-64, CM-500
00449     // Note that the size below is given in samples (16-bit), not bytes
00450     pcmROMSize = controlROMMap->pcmCount == 256 ? 512 * 1024 : 256 * 1024;
00451     pcmROMData = new Bit16s[pcmROMSize];
00452 
00453 #if MT32EMU_MONITOR_INIT
00454     printDebug("Loading PCM ROM");
00455 #endif
00456     if (!loadPCMROM(pcmROMImage)) {
00457         printDebug("Init Error - Missing PCM ROM image");
00458         reportHandler->onErrorPCMROM();
00459         return false;
00460     }
00461 
00462 #if MT32EMU_MONITOR_INIT
00463     printDebug("Initialising Timbre Bank A");
00464 #endif
00465     if (!initTimbres(controlROMMap->timbreAMap, controlROMMap->timbreAOffset, 0x40, 0, controlROMMap->timbreACompressed)) {
00466         return false;
00467     }
00468 
00469 #if MT32EMU_MONITOR_INIT
00470     printDebug("Initialising Timbre Bank B");
00471 #endif
00472     if (!initTimbres(controlROMMap->timbreBMap, controlROMMap->timbreBOffset, 0x40, 64, controlROMMap->timbreBCompressed)) {
00473         return false;
00474     }
00475 
00476 #if MT32EMU_MONITOR_INIT
00477     printDebug("Initialising Timbre Bank R");
00478 #endif
00479     if (!initTimbres(controlROMMap->timbreRMap, 0, controlROMMap->timbreRCount, 192, true)) {
00480         return false;
00481     }
00482 
00483 #if MT32EMU_MONITOR_INIT
00484     printDebug("Initialising Timbre Bank M");
00485 #endif
00486     // CM-64 seems to initialise all bytes in this bank to 0.
00487     memset(&mt32ram.timbres[128], 0, sizeof(mt32ram.timbres[128]) * 64);
00488 
00489     partialManager = new PartialManager(this, parts);
00490 
00491     pcmWaves = new PCMWaveEntry[controlROMMap->pcmCount];
00492 
00493 #if MT32EMU_MONITOR_INIT
00494     printDebug("Initialising PCM List");
00495 #endif
00496     initPCMList(controlROMMap->pcmTable, controlROMMap->pcmCount);
00497 
00498 #if MT32EMU_MONITOR_INIT
00499     printDebug("Initialising Rhythm Temp");
00500 #endif
00501     memcpy(mt32ram.rhythmTemp, &controlROMData[controlROMMap->rhythmSettings], controlROMMap->rhythmSettingsCount * 4);
00502 
00503 #if MT32EMU_MONITOR_INIT
00504     printDebug("Initialising Patches");
00505 #endif
00506     for (Bit8u i = 0; i < 128; i++) {
00507         PatchParam *patch = &mt32ram.patches[i];
00508         patch->timbreGroup = i / 64;
00509         patch->timbreNum = i % 64;
00510         patch->keyShift = 24;
00511         patch->fineTune = 50;
00512         patch->benderRange = 12;
00513         patch->assignMode = 0;
00514         patch->reverbSwitch = 1;
00515         patch->dummy = 0;
00516     }
00517 
00518 #if MT32EMU_MONITOR_INIT
00519     printDebug("Initialising System");
00520 #endif
00521     // The MT-32 manual claims that "Standard pitch" is 442Hz.
00522     mt32ram.system.masterTune = 0x4A; // Confirmed on CM-64
00523     mt32ram.system.reverbMode = 0; // Confirmed
00524     mt32ram.system.reverbTime = 5; // Confirmed
00525     mt32ram.system.reverbLevel = 3; // Confirmed
00526     memcpy(mt32ram.system.reserveSettings, &controlROMData[controlROMMap->reserveSettings], 9); // Confirmed
00527     for (Bit8u i = 0; i < 9; i++) {
00528         // This is the default: {1, 2, 3, 4, 5, 6, 7, 8, 9}
00529         // An alternative configuration can be selected by holding "Master Volume"
00530         // and pressing "PART button 1" on the real MT-32's frontpanel.
00531         // The channel assignment is then {0, 1, 2, 3, 4, 5, 6, 7, 9}
00532         mt32ram.system.chanAssign[i] = i + 1;
00533     }
00534     mt32ram.system.masterVol = 100; // Confirmed
00535     refreshSystem();
00536 
00537     for (int i = 0; i < 9; i++) {
00538         MemParams::PatchTemp *patchTemp = &mt32ram.patchTemp[i];
00539 
00540         // Note that except for the rhythm part, these patch fields will be set in setProgram() below anyway.
00541         patchTemp->patch.timbreGroup = 0;
00542         patchTemp->patch.timbreNum = 0;
00543         patchTemp->patch.keyShift = 24;
00544         patchTemp->patch.fineTune = 50;
00545         patchTemp->patch.benderRange = 12;
00546         patchTemp->patch.assignMode = 0;
00547         patchTemp->patch.reverbSwitch = 1;
00548         patchTemp->patch.dummy = 0;
00549 
00550         patchTemp->outputLevel = 80;
00551         patchTemp->panpot = controlROMData[controlROMMap->panSettings + i];
00552         memset(patchTemp->dummyv, 0, sizeof(patchTemp->dummyv));
00553         patchTemp->dummyv[1] = 127;
00554 
00555         if (i < 8) {
00556             parts[i] = new Part(this, i);
00557             parts[i]->setProgram(controlROMData[controlROMMap->programSettings + i]);
00558         } else {
00559             parts[i] = new RhythmPart(this, i);
00560         }
00561     }
00562 
00563     // For resetting mt32 mid-execution
00564     mt32default = mt32ram;
00565 
00566     isOpen = true;
00567     isEnabled = false;
00568 
00569 #if MT32EMU_MONITOR_INIT
00570     printDebug("*** Initialisation complete ***");
00571 #endif
00572     return true;
00573 }
00574 
00575 void Synth::close() {
00576     if (!isOpen) {
00577         return;
00578     }
00579 
00580     delete partialManager;
00581     partialManager = NULL;
00582 
00583     for (int i = 0; i < 9; i++) {
00584         delete parts[i];
00585         parts[i] = NULL;
00586     }
00587 
00588     delete[] pcmWaves;
00589     delete[] pcmROMData;
00590 
00591     deleteMemoryRegions();
00592 
00593     for (int i = 0; i < 4; i++) {
00594         reverbModels[i]->close();
00595     }
00596     reverbModel = NULL;
00597     isOpen = false;
00598 }
00599 
00600 void Synth::playMsg(Bit32u msg) {
00601     // FIXME: Implement active sensing
00602     unsigned char code     = (unsigned char)((msg & 0x0000F0) >> 4);
00603     unsigned char chan     = (unsigned char)(msg & 0x00000F);
00604     unsigned char note     = (unsigned char)((msg & 0x00FF00) >> 8);
00605     unsigned char velocity = (unsigned char)((msg & 0xFF0000) >> 16);
00606     isEnabled = true;
00607 
00608     //printDebug("Playing chan %d, code 0x%01x note: 0x%02x", chan, code, note);
00609 
00610     char part = chantable[chan];
00611     if (part < 0 || part > 8) {
00612 #if MT32EMU_MONITOR_MIDI > 0
00613         printDebug("Play msg on unreg chan %d (%d): code=0x%01x, vel=%d", chan, part, code, velocity);
00614 #endif
00615         return;
00616     }
00617     playMsgOnPart(part, code, note, velocity);
00618 
00619     // This ensures minimum 1-sample delay between sequential MIDI events
00620     // Without this, a sequence of NoteOn and immediately succeeding NoteOff messages is always silent
00621     // Technically, it's also impossible to send events through the MIDI interface faster than about each millisecond
00622     prerender();
00623 }
00624 
00625 void Synth::playMsgOnPart(unsigned char part, unsigned char code, unsigned char note, unsigned char velocity) {
00626     Bit32u bend;
00627 
00628     //printDebug("Synth::playMsgOnPart(%02x, %02x, %02x, %02x)", part, code, note, velocity);
00629     switch (code) {
00630     case 0x8:
00631         //printDebug("Note OFF - Part %d", part);
00632         // The MT-32 ignores velocity for note off
00633         parts[part]->noteOff(note);
00634         break;
00635     case 0x9:
00636         //printDebug("Note ON - Part %d, Note %d Vel %d", part, note, velocity);
00637         if (velocity == 0) {
00638             // MIDI defines note-on with velocity 0 as being the same as note-off with velocity 40
00639             parts[part]->noteOff(note);
00640         } else {
00641             parts[part]->noteOn(note, velocity);
00642         }
00643         break;
00644     case 0xB: // Control change
00645         switch (note) {
00646         case 0x01:  // Modulation
00647             //printDebug("Modulation: %d", velocity);
00648             parts[part]->setModulation(velocity);
00649             break;
00650         case 0x06:
00651             parts[part]->setDataEntryMSB(velocity);
00652             break;
00653         case 0x07:  // Set volume
00654             //printDebug("Volume set: %d", velocity);
00655             parts[part]->setVolume(velocity);
00656             break;
00657         case 0x0A:  // Pan
00658             //printDebug("Pan set: %d", velocity);
00659             parts[part]->setPan(velocity);
00660             break;
00661         case 0x0B:
00662             //printDebug("Expression set: %d", velocity);
00663             parts[part]->setExpression(velocity);
00664             break;
00665         case 0x40: // Hold (sustain) pedal
00666             //printDebug("Hold pedal set: %d", velocity);
00667             parts[part]->setHoldPedal(velocity >= 64);
00668             break;
00669 
00670         case 0x62:
00671         case 0x63:
00672             parts[part]->setNRPN();
00673             break;
00674         case 0x64:
00675             parts[part]->setRPNLSB(velocity);
00676             break;
00677         case 0x65:
00678             parts[part]->setRPNMSB(velocity);
00679             break;
00680 
00681         case 0x79: // Reset all controllers
00682             //printDebug("Reset all controllers");
00683             parts[part]->resetAllControllers();
00684             break;
00685 
00686         case 0x7B: // All notes off
00687             //printDebug("All notes off");
00688             parts[part]->allNotesOff();
00689             break;
00690 
00691         case 0x7C:
00692         case 0x7D:
00693         case 0x7E:
00694         case 0x7F:
00695             // CONFIRMED:Mok: A real LAPC-I responds to these controllers as follows:
00696             parts[part]->setHoldPedal(false);
00697             parts[part]->allNotesOff();
00698             break;
00699 
00700         default:
00701 #if MT32EMU_MONITOR_MIDI > 0
00702             printDebug("Unknown MIDI Control code: 0x%02x - vel 0x%02x", note, velocity);
00703 #endif
00704             break;
00705         }
00706 
00707         break;
00708     case 0xC: // Program change
00709         //printDebug("Program change %01x", note);
00710         parts[part]->setProgram(note);
00711         break;
00712     case 0xE: // Pitch bender
00713         bend = (velocity << 7) | (note);
00714         //printDebug("Pitch bender %02x", bend);
00715         parts[part]->setBend(bend);
00716         break;
00717     default:
00718 #if MT32EMU_MONITOR_MIDI > 0
00719         printDebug("Unknown Midi code: 0x%01x - %02x - %02x", code, note, velocity);
00720 #endif
00721         break;
00722     }
00723 
00724     //midiOutShortMsg(m_out, msg);
00725 }
00726 
00727 void Synth::playSysex(const Bit8u *sysex, Bit32u len) {
00728     if (len < 2) {
00729         printDebug("playSysex: Message is too short for sysex (%d bytes)", len);
00730     }
00731     if (sysex[0] != 0xF0) {
00732         printDebug("playSysex: Message lacks start-of-sysex (0xF0)");
00733         return;
00734     }
00735     // Due to some programs (e.g. Java) sending buffers with junk at the end, we have to go through and find the end marker rather than relying on len.
00736     Bit32u endPos;
00737     for (endPos = 1; endPos < len; endPos++) {
00738         if (sysex[endPos] == 0xF7) {
00739             break;
00740         }
00741     }
00742     if (endPos == len) {
00743         printDebug("playSysex: Message lacks end-of-sysex (0xf7)");
00744         return;
00745     }
00746     playSysexWithoutFraming(sysex + 1, endPos - 1);
00747 }
00748 
00749 void Synth::playSysexWithoutFraming(const Bit8u *sysex, Bit32u len) {
00750     if (len < 4) {
00751         printDebug("playSysexWithoutFraming: Message is too short (%d bytes)!", len);
00752         return;
00753     }
00754     if (sysex[0] != SYSEX_MANUFACTURER_ROLAND) {
00755         printDebug("playSysexWithoutFraming: Header not intended for this device manufacturer: %02x %02x %02x %02x", (int)sysex[0], (int)sysex[1], (int)sysex[2], (int)sysex[3]);
00756         return;
00757     }
00758     if (sysex[2] == SYSEX_MDL_D50) {
00759         printDebug("playSysexWithoutFraming: Header is intended for model D-50 (not yet supported): %02x %02x %02x %02x", (int)sysex[0], (int)sysex[1], (int)sysex[2], (int)sysex[3]);
00760         return;
00761     } else if (sysex[2] != SYSEX_MDL_MT32) {
00762         printDebug("playSysexWithoutFraming: Header not intended for model MT-32: %02x %02x %02x %02x", (int)sysex[0], (int)sysex[1], (int)sysex[2], (int)sysex[3]);
00763         return;
00764     }
00765     playSysexWithoutHeader(sysex[1], sysex[3], sysex + 4, len - 4);
00766 }
00767 
00768 void Synth::playSysexWithoutHeader(unsigned char device, unsigned char command, const Bit8u *sysex, Bit32u len) {
00769     if (device > 0x10) {
00770         // We have device ID 0x10 (default, but changeable, on real MT-32), < 0x10 is for channels
00771         printDebug("playSysexWithoutHeader: Message is not intended for this device ID (provided: %02x, expected: 0x10 or channel)", (int)device);
00772         return;
00773     }
00774     // This is checked early in the real devices (before any sysex length checks or further processing)
00775     // FIXME: Response to SYSEX_CMD_DAT reset with partials active (and in general) is untested.
00776     if ((command == SYSEX_CMD_DT1 || command == SYSEX_CMD_DAT) && sysex[0] == 0x7F) {
00777         reset();
00778         return;
00779     }
00780     if (len < 4) {
00781         printDebug("playSysexWithoutHeader: Message is too short (%d bytes)!", len);
00782         return;
00783     }
00784     unsigned char checksum = calcSysexChecksum(sysex, len - 1, 0);
00785     if (checksum != sysex[len - 1]) {
00786         printDebug("playSysexWithoutHeader: Message checksum is incorrect (provided: %02x, expected: %02x)!", sysex[len - 1], checksum);
00787         return;
00788     }
00789     len -= 1; // Exclude checksum
00790     switch (command) {
00791     case SYSEX_CMD_DAT:
00792         if (hasActivePartials()) {
00793             printDebug("playSysexWithoutHeader: Got SYSEX_CMD_DAT but partials are active - ignoring");
00794             // FIXME: We should send SYSEX_CMD_RJC in this case
00795             break;
00796         }
00797         // Deliberate fall-through
00798     case SYSEX_CMD_DT1:
00799         writeSysex(device, sysex, len);
00800         break;
00801     case SYSEX_CMD_RQD:
00802         if (hasActivePartials()) {
00803             printDebug("playSysexWithoutHeader: Got SYSEX_CMD_RQD but partials are active - ignoring");
00804             // FIXME: We should send SYSEX_CMD_RJC in this case
00805             break;
00806         }
00807         // Deliberate fall-through
00808     case SYSEX_CMD_RQ1:
00809         readSysex(device, sysex, len);
00810         break;
00811     default:
00812         printDebug("playSysexWithoutHeader: Unsupported command %02x", command);
00813         return;
00814     }
00815 }
00816 
00817 void Synth::readSysex(unsigned char /*device*/, const Bit8u * /*sysex*/, Bit32u /*len*/) const {
00818     // NYI
00819 }
00820 
00821 void Synth::writeSysex(unsigned char device, const Bit8u *sysex, Bit32u len) {
00822     Bit32u addr = (sysex[0] << 16) | (sysex[1] << 8) | (sysex[2]);
00823     addr = MT32EMU_MEMADDR(addr);
00824     sysex += 3;
00825     len -= 3;
00826     //printDebug("Sysex addr: 0x%06x", MT32EMU_SYSEXMEMADDR(addr));
00827     // NOTE: Please keep both lower and upper bounds in each check, for ease of reading
00828 
00829     // Process channel-specific sysex by converting it to device-global
00830     if (device < 0x10) {
00831 #if MT32EMU_MONITOR_SYSEX > 0
00832         printDebug("WRITE-CHANNEL: Channel %d temp area 0x%06x", device, MT32EMU_SYSEXMEMADDR(addr));
00833 #endif
00834         if (/*addr >= MT32EMU_MEMADDR(0x000000) && */addr < MT32EMU_MEMADDR(0x010000)) {
00835             int offset;
00836             if (chantable[device] == -1) {
00837 #if MT32EMU_MONITOR_SYSEX > 0
00838                 printDebug(" (Channel not mapped to a part... 0 offset)");
00839 #endif
00840                 offset = 0;
00841             } else if (chantable[device] == 8) {
00842 #if MT32EMU_MONITOR_SYSEX > 0
00843                 printDebug(" (Channel mapped to rhythm... 0 offset)");
00844 #endif
00845                 offset = 0;
00846             } else {
00847                 offset = chantable[device] * sizeof(MemParams::PatchTemp);
00848 #if MT32EMU_MONITOR_SYSEX > 0
00849                 printDebug(" (Setting extra offset to %d)", offset);
00850 #endif
00851             }
00852             addr += MT32EMU_MEMADDR(0x030000) + offset;
00853         } else if (/*addr >= MT32EMU_MEMADDR(0x010000) && */ addr < MT32EMU_MEMADDR(0x020000)) {
00854             addr += MT32EMU_MEMADDR(0x030110) - MT32EMU_MEMADDR(0x010000);
00855         } else if (/*addr >= MT32EMU_MEMADDR(0x020000) && */ addr < MT32EMU_MEMADDR(0x030000)) {
00856             int offset;
00857             if (chantable[device] == -1) {
00858 #if MT32EMU_MONITOR_SYSEX > 0
00859                 printDebug(" (Channel not mapped to a part... 0 offset)");
00860 #endif
00861                 offset = 0;
00862             } else if (chantable[device] == 8) {
00863 #if MT32EMU_MONITOR_SYSEX > 0
00864                 printDebug(" (Channel mapped to rhythm... 0 offset)");
00865 #endif
00866                 offset = 0;
00867             } else {
00868                 offset = chantable[device] * sizeof(TimbreParam);
00869 #if MT32EMU_MONITOR_SYSEX > 0
00870                 printDebug(" (Setting extra offset to %d)", offset);
00871 #endif
00872             }
00873             addr += MT32EMU_MEMADDR(0x040000) - MT32EMU_MEMADDR(0x020000) + offset;
00874         } else {
00875 #if MT32EMU_MONITOR_SYSEX > 0
00876             printDebug(" Invalid channel");
00877 #endif
00878             return;
00879         }
00880     }
00881 
00882     // Process device-global sysex (possibly converted from channel-specific sysex above)
00883     for (;;) {
00884         // Find the appropriate memory region
00885         const MemoryRegion *region = findMemoryRegion(addr);
00886 
00887         if (region == NULL) {
00888             printDebug("Sysex write to unrecognised address %06x, len %d", MT32EMU_SYSEXMEMADDR(addr), len);
00889             break;
00890         }
00891         writeMemoryRegion(region, addr, region->getClampedLen(addr, len), sysex);
00892 
00893         Bit32u next = region->next(addr, len);
00894         if (next == 0) {
00895             break;
00896         }
00897         addr += next;
00898         sysex += next;
00899         len -= next;
00900     }
00901 }
00902 
00903 void Synth::readMemory(Bit32u addr, Bit32u len, Bit8u *data) {
00904     const MemoryRegion *region = findMemoryRegion(addr);
00905     if (region != NULL) {
00906         readMemoryRegion(region, addr, len, data);
00907     }
00908 }
00909 
00910 void Synth::initMemoryRegions() {
00911     // Timbre max tables are slightly more complicated than the others, which are used directly from the ROM.
00912     // The ROM (sensibly) just has maximums for TimbreParam.commonParam followed by just one TimbreParam.partialParam,
00913     // so we produce a table with all partialParams filled out, as well as padding for PaddedTimbre, for quick lookup.
00914     paddedTimbreMaxTable = new Bit8u[sizeof(MemParams::PaddedTimbre)];
00915     memcpy(&paddedTimbreMaxTable[0], &controlROMData[controlROMMap->timbreMaxTable], sizeof(TimbreParam::CommonParam) + sizeof(TimbreParam::PartialParam)); // commonParam and one partialParam
00916     int pos = sizeof(TimbreParam::CommonParam) + sizeof(TimbreParam::PartialParam);
00917     for (int i = 0; i < 3; i++) {
00918         memcpy(&paddedTimbreMaxTable[pos], &controlROMData[controlROMMap->timbreMaxTable + sizeof(TimbreParam::CommonParam)], sizeof(TimbreParam::PartialParam));
00919         pos += sizeof(TimbreParam::PartialParam);
00920     }
00921     memset(&paddedTimbreMaxTable[pos], 0, 10); // Padding
00922     patchTempMemoryRegion = new PatchTempMemoryRegion(this, (Bit8u *)&mt32ram.patchTemp[0], &controlROMData[controlROMMap->patchMaxTable]);
00923     rhythmTempMemoryRegion = new RhythmTempMemoryRegion(this, (Bit8u *)&mt32ram.rhythmTemp[0], &controlROMData[controlROMMap->rhythmMaxTable]);
00924     timbreTempMemoryRegion = new TimbreTempMemoryRegion(this, (Bit8u *)&mt32ram.timbreTemp[0], paddedTimbreMaxTable);
00925     patchesMemoryRegion = new PatchesMemoryRegion(this, (Bit8u *)&mt32ram.patches[0], &controlROMData[controlROMMap->patchMaxTable]);
00926     timbresMemoryRegion = new TimbresMemoryRegion(this, (Bit8u *)&mt32ram.timbres[0], paddedTimbreMaxTable);
00927     systemMemoryRegion = new SystemMemoryRegion(this, (Bit8u *)&mt32ram.system, &controlROMData[controlROMMap->systemMaxTable]);
00928     displayMemoryRegion = new DisplayMemoryRegion(this);
00929     resetMemoryRegion = new ResetMemoryRegion(this);
00930 }
00931 
00932 void Synth::deleteMemoryRegions() {
00933     delete patchTempMemoryRegion;
00934     patchTempMemoryRegion = NULL;
00935     delete rhythmTempMemoryRegion;
00936     rhythmTempMemoryRegion = NULL;
00937     delete timbreTempMemoryRegion;
00938     timbreTempMemoryRegion = NULL;
00939     delete patchesMemoryRegion;
00940     patchesMemoryRegion = NULL;
00941     delete timbresMemoryRegion;
00942     timbresMemoryRegion = NULL;
00943     delete systemMemoryRegion;
00944     systemMemoryRegion = NULL;
00945     delete displayMemoryRegion;
00946     displayMemoryRegion = NULL;
00947     delete resetMemoryRegion;
00948     resetMemoryRegion = NULL;
00949 
00950     delete[] paddedTimbreMaxTable;
00951     paddedTimbreMaxTable = NULL;
00952 }
00953 
00954 MemoryRegion *Synth::findMemoryRegion(Bit32u addr) {
00955     MemoryRegion *regions[] = {
00956         patchTempMemoryRegion,
00957         rhythmTempMemoryRegion,
00958         timbreTempMemoryRegion,
00959         patchesMemoryRegion,
00960         timbresMemoryRegion,
00961         systemMemoryRegion,
00962         displayMemoryRegion,
00963         resetMemoryRegion,
00964         NULL
00965     };
00966     for (int pos = 0; regions[pos] != NULL; pos++) {
00967         if (regions[pos]->contains(addr)) {
00968             return regions[pos];
00969         }
00970     }
00971     return NULL;
00972 }
00973 
00974 void Synth::readMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, Bit8u *data) {
00975     unsigned int first = region->firstTouched(addr);
00976     //unsigned int last = region->lastTouched(addr, len);
00977     unsigned int off = region->firstTouchedOffset(addr);
00978     len = region->getClampedLen(addr, len);
00979 
00980     if (region->isReadable()) {
00981         region->read(first, off, data, len);
00982     } else {
00983         // FIXME: We might want to do these properly in future
00984         for (unsigned int m = 0; m < len; m += 2) {
00985             data[m] = 0xff;
00986             if (m + 1 < len) {
00987                 data[m+1] = (Bit8u)region->type;
00988             }
00989         }
00990     }
00991 }
00992 
00993 void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, const Bit8u *data) {
00994     unsigned int first = region->firstTouched(addr);
00995     unsigned int last = region->lastTouched(addr, len);
00996     unsigned int off = region->firstTouchedOffset(addr);
00997     switch (region->type) {
00998     case MR_PatchTemp:
00999         region->write(first, off, data, len);
01000         //printDebug("Patch temp: Patch %d, offset %x, len %d", off/16, off % 16, len);
01001 
01002         for (unsigned int i = first; i <= last; i++) {
01003             int absTimbreNum = mt32ram.patchTemp[i].patch.timbreGroup * 64 + mt32ram.patchTemp[i].patch.timbreNum;
01004             char timbreName[11];
01005             memcpy(timbreName, mt32ram.timbres[absTimbreNum].timbre.common.name, 10);
01006             timbreName[10] = 0;
01007 #if MT32EMU_MONITOR_SYSEX > 0
01008             printDebug("WRITE-PARTPATCH (%d-%d@%d..%d): %d; timbre=%d (%s), outlevel=%d", first, last, off, off + len, i, absTimbreNum, timbreName, mt32ram.patchTemp[i].outputLevel);
01009 #endif
01010             if (parts[i] != NULL) {
01011                 if (i != 8) {
01012                     // Note: Confirmed on CM-64 that we definitely *should* update the timbre here,
01013                     // but only in the case that the sysex actually writes to those values
01014                     if (i == first && off > 2) {
01015 #if MT32EMU_MONITOR_SYSEX > 0
01016                         printDebug(" (Not updating timbre, since those values weren't touched)");
01017 #endif
01018                     } else {
01019                         parts[i]->setTimbre(&mt32ram.timbres[parts[i]->getAbsTimbreNum()].timbre);
01020                     }
01021                 }
01022                 parts[i]->refresh();
01023             }
01024         }
01025         break;
01026     case MR_RhythmTemp:
01027         region->write(first, off, data, len);
01028         for (unsigned int i = first; i <= last; i++) {
01029             int timbreNum = mt32ram.rhythmTemp[i].timbre;
01030             char timbreName[11];
01031             if (timbreNum < 94) {
01032                 memcpy(timbreName, mt32ram.timbres[128 + timbreNum].timbre.common.name, 10);
01033                 timbreName[10] = 0;
01034             } else {
01035                 strcpy(timbreName, "[None]");
01036             }
01037 #if MT32EMU_MONITOR_SYSEX > 0
01038             printDebug("WRITE-RHYTHM (%d-%d@%d..%d): %d; level=%02x, panpot=%02x, reverb=%02x, timbre=%d (%s)", first, last, off, off + len, i, mt32ram.rhythmTemp[i].outputLevel, mt32ram.rhythmTemp[i].panpot, mt32ram.rhythmTemp[i].reverbSwitch, mt32ram.rhythmTemp[i].timbre, timbreName);
01039 #endif
01040         }
01041         if (parts[8] != NULL) {
01042             parts[8]->refresh();
01043         }
01044         break;
01045     case MR_TimbreTemp:
01046         region->write(first, off, data, len);
01047         for (unsigned int i = first; i <= last; i++) {
01048             char instrumentName[11];
01049             memcpy(instrumentName, mt32ram.timbreTemp[i].common.name, 10);
01050             instrumentName[10] = 0;
01051 #if MT32EMU_MONITOR_SYSEX > 0
01052             printDebug("WRITE-PARTTIMBRE (%d-%d@%d..%d): timbre=%d (%s)", first, last, off, off + len, i, instrumentName);
01053 #endif
01054             if (parts[i] != NULL) {
01055                 parts[i]->refresh();
01056             }
01057         }
01058         break;
01059     case MR_Patches:
01060         region->write(first, off, data, len);
01061 #if MT32EMU_MONITOR_SYSEX > 0
01062         for (unsigned int i = first; i <= last; i++) {
01063             PatchParam *patch = &mt32ram.patches[i];
01064             int patchAbsTimbreNum = patch->timbreGroup * 64 + patch->timbreNum;
01065             char instrumentName[11];
01066             memcpy(instrumentName, mt32ram.timbres[patchAbsTimbreNum].timbre.common.name, 10);
01067             instrumentName[10] = 0;
01068             Bit8u *n = (Bit8u *)patch;
01069             printDebug("WRITE-PATCH (%d-%d@%d..%d): %d; timbre=%d (%s) %02X%02X%02X%02X%02X%02X%02X%02X", first, last, off, off + len, i, patchAbsTimbreNum, instrumentName, n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7]);
01070         }
01071 #endif
01072         break;
01073     case MR_Timbres:
01074         // Timbres
01075         first += 128;
01076         last += 128;
01077         region->write(first, off, data, len);
01078         for (unsigned int i = first; i <= last; i++) {
01079 #if MT32EMU_MONITOR_TIMBRES >= 1
01080             TimbreParam *timbre = &mt32ram.timbres[i].timbre;
01081             char instrumentName[11];
01082             memcpy(instrumentName, timbre->common.name, 10);
01083             instrumentName[10] = 0;
01084             printDebug("WRITE-TIMBRE (%d-%d@%d..%d): %d; name=\"%s\"", first, last, off, off + len, i, instrumentName);
01085 #if MT32EMU_MONITOR_TIMBRES >= 2
01086 #define DT(x) printDebug(" " #x ": %d", timbre->x)
01087             DT(common.partialStructure12);
01088             DT(common.partialStructure34);
01089             DT(common.partialMute);
01090             DT(common.noSustain);
01091 
01092 #define DTP(x) \
01093             DT(partial[x].wg.pitchCoarse); \
01094             DT(partial[x].wg.pitchFine); \
01095             DT(partial[x].wg.pitchKeyfollow); \
01096             DT(partial[x].wg.pitchBenderEnabled); \
01097             DT(partial[x].wg.waveform); \
01098             DT(partial[x].wg.pcmWave); \
01099             DT(partial[x].wg.pulseWidth); \
01100             DT(partial[x].wg.pulseWidthVeloSensitivity); \
01101             DT(partial[x].pitchEnv.depth); \
01102             DT(partial[x].pitchEnv.veloSensitivity); \
01103             DT(partial[x].pitchEnv.timeKeyfollow); \
01104             DT(partial[x].pitchEnv.time[0]); \
01105             DT(partial[x].pitchEnv.time[1]); \
01106             DT(partial[x].pitchEnv.time[2]); \
01107             DT(partial[x].pitchEnv.time[3]); \
01108             DT(partial[x].pitchEnv.level[0]); \
01109             DT(partial[x].pitchEnv.level[1]); \
01110             DT(partial[x].pitchEnv.level[2]); \
01111             DT(partial[x].pitchEnv.level[3]); \
01112             DT(partial[x].pitchEnv.level[4]); \
01113             DT(partial[x].pitchLFO.rate); \
01114             DT(partial[x].pitchLFO.depth); \
01115             DT(partial[x].pitchLFO.modSensitivity); \
01116             DT(partial[x].tvf.cutoff); \
01117             DT(partial[x].tvf.resonance); \
01118             DT(partial[x].tvf.keyfollow); \
01119             DT(partial[x].tvf.biasPoint); \
01120             DT(partial[x].tvf.biasLevel); \
01121             DT(partial[x].tvf.envDepth); \
01122             DT(partial[x].tvf.envVeloSensitivity); \
01123             DT(partial[x].tvf.envDepthKeyfollow); \
01124             DT(partial[x].tvf.envTimeKeyfollow); \
01125             DT(partial[x].tvf.envTime[0]); \
01126             DT(partial[x].tvf.envTime[1]); \
01127             DT(partial[x].tvf.envTime[2]); \
01128             DT(partial[x].tvf.envTime[3]); \
01129             DT(partial[x].tvf.envTime[4]); \
01130             DT(partial[x].tvf.envLevel[0]); \
01131             DT(partial[x].tvf.envLevel[1]); \
01132             DT(partial[x].tvf.envLevel[2]); \
01133             DT(partial[x].tvf.envLevel[3]); \
01134             DT(partial[x].tva.level); \
01135             DT(partial[x].tva.veloSensitivity); \
01136             DT(partial[x].tva.biasPoint1); \
01137             DT(partial[x].tva.biasLevel1); \
01138             DT(partial[x].tva.biasPoint2); \
01139             DT(partial[x].tva.biasLevel2); \
01140             DT(partial[x].tva.envTimeKeyfollow); \
01141             DT(partial[x].tva.envTimeVeloSensitivity); \
01142             DT(partial[x].tva.envTime[0]); \
01143             DT(partial[x].tva.envTime[1]); \
01144             DT(partial[x].tva.envTime[2]); \
01145             DT(partial[x].tva.envTime[3]); \
01146             DT(partial[x].tva.envTime[4]); \
01147             DT(partial[x].tva.envLevel[0]); \
01148             DT(partial[x].tva.envLevel[1]); \
01149             DT(partial[x].tva.envLevel[2]); \
01150             DT(partial[x].tva.envLevel[3]);
01151 
01152             DTP(0);
01153             DTP(1);
01154             DTP(2);
01155             DTP(3);
01156 #undef DTP
01157 #undef DT
01158 #endif
01159 #endif
01160             // FIXME:KG: Not sure if the stuff below should be done (for rhythm and/or parts)...
01161             // Does the real MT-32 automatically do this?
01162             for (unsigned int part = 0; part < 9; part++) {
01163                 if (parts[part] != NULL) {
01164                     parts[part]->refreshTimbre(i);
01165                 }
01166             }
01167         }
01168         break;
01169     case MR_System:
01170         region->write(0, off, data, len);
01171 
01172         reportHandler->onDeviceReconfig();
01173         // FIXME: We haven't properly confirmed any of this behaviour
01174         // In particular, we tend to reset things such as reverb even if the write contained
01175         // the same parameters as were already set, which may be wrong.
01176         // On the other hand, the real thing could be resetting things even when they aren't touched
01177         // by the write at all.
01178 #if MT32EMU_MONITOR_SYSEX > 0
01179         printDebug("WRITE-SYSTEM:");
01180 #endif
01181         if (off <= SYSTEM_MASTER_TUNE_OFF && off + len > SYSTEM_MASTER_TUNE_OFF) {
01182             refreshSystemMasterTune();
01183         }
01184         if (off <= SYSTEM_REVERB_LEVEL_OFF && off + len > SYSTEM_REVERB_MODE_OFF) {
01185             refreshSystemReverbParameters();
01186         }
01187         if (off <= SYSTEM_RESERVE_SETTINGS_END_OFF && off + len > SYSTEM_RESERVE_SETTINGS_START_OFF) {
01188             refreshSystemReserveSettings();
01189         }
01190         if (off <= SYSTEM_CHAN_ASSIGN_END_OFF && off + len > SYSTEM_CHAN_ASSIGN_START_OFF) {
01191             int firstPart = off - SYSTEM_CHAN_ASSIGN_START_OFF;
01192             if(firstPart < 0)
01193                 firstPart = 0;
01194             int lastPart = off + len - SYSTEM_CHAN_ASSIGN_START_OFF;
01195             if(lastPart > 9)
01196                 lastPart = 9;
01197             refreshSystemChanAssign(firstPart, lastPart);
01198         }
01199         if (off <= SYSTEM_MASTER_VOL_OFF && off + len > SYSTEM_MASTER_VOL_OFF) {
01200             refreshSystemMasterVol();
01201         }
01202         break;
01203     case MR_Display:
01204         char buf[MAX_SYSEX_SIZE];
01205         memcpy(&buf, &data[0], len);
01206         buf[len] = 0;
01207 #if MT32EMU_MONITOR_SYSEX > 0
01208         printDebug("WRITE-LCD: %s", buf);
01209 #endif
01210         reportHandler->showLCDMessage(buf);
01211         break;
01212     case MR_Reset:
01213         reset();
01214         break;
01215     }
01216 }
01217 
01218 void Synth::refreshSystemMasterTune() {
01219 #if MT32EMU_MONITOR_SYSEX > 0
01220     //FIXME:KG: This is just an educated guess.
01221     // The LAPC-I documentation claims a range of 427.5Hz-452.6Hz (similar to what we have here)
01222     // The MT-32 documentation claims a range of 432.1Hz-457.6Hz
01223     float masterTune = 440.0f * EXP2F((mt32ram.system.masterTune - 64.0f) / (128.0f * 12.0f));
01224     printDebug(" Master Tune: %f", masterTune);
01225 #endif
01226 }
01227 
01228 void Synth::refreshSystemReverbParameters() {
01229 #if MT32EMU_MONITOR_SYSEX > 0
01230     printDebug(" Reverb: mode=%d, time=%d, level=%d", mt32ram.system.reverbMode, mt32ram.system.reverbTime, mt32ram.system.reverbLevel);
01231 #endif
01232     if (reverbOverridden && reverbModel != NULL) {
01233 #if MT32EMU_MONITOR_SYSEX > 0
01234         printDebug(" (Reverb overridden - ignoring)");
01235 #endif
01236         return;
01237     }
01238     reportHandler->onNewReverbMode(mt32ram.system.reverbMode);
01239     reportHandler->onNewReverbTime(mt32ram.system.reverbTime);
01240     reportHandler->onNewReverbLevel(mt32ram.system.reverbLevel);
01241 
01242     ReverbModel *newReverbModel = reverbModels[mt32ram.system.reverbMode];
01243 #if MT32EMU_REDUCE_REVERB_MEMORY
01244     if (reverbModel != newReverbModel) {
01245         if (reverbModel != NULL) {
01246             reverbModel->close();
01247         }
01248         newReverbModel->open();
01249     }
01250 #endif
01251     reverbModel = newReverbModel;
01252     reverbModel->setParameters(mt32ram.system.reverbTime, mt32ram.system.reverbLevel);
01253 }
01254 
01255 void Synth::refreshSystemReserveSettings() {
01256     Bit8u *rset = mt32ram.system.reserveSettings;
01257 #if MT32EMU_MONITOR_SYSEX > 0
01258     printDebug(" Partial reserve: 1=%02d 2=%02d 3=%02d 4=%02d 5=%02d 6=%02d 7=%02d 8=%02d Rhythm=%02d", rset[0], rset[1], rset[2], rset[3], rset[4], rset[5], rset[6], rset[7], rset[8]);
01259 #endif
01260     partialManager->setReserve(rset);
01261 }
01262 
01263 void Synth::refreshSystemChanAssign(unsigned int firstPart, unsigned int lastPart) {
01264     memset(chantable, -1, sizeof(chantable));
01265 
01266     // CONFIRMED: In the case of assigning a channel to multiple parts, the lower part wins.
01267     for (unsigned int i = 0; i <= 8; i++) {
01268         if (parts[i] != NULL && i >= firstPart && i <= lastPart) {
01269             // CONFIRMED: Decay is started for all polys, and all controllers are reset, for every part whose assignment was touched by the sysex write.
01270             parts[i]->allSoundOff();
01271             parts[i]->resetAllControllers();
01272         }
01273         int chan = mt32ram.system.chanAssign[i];
01274         if (chan != 16 && chantable[chan] == -1) {
01275             chantable[chan] = i;
01276         }
01277     }
01278 
01279 #if MT32EMU_MONITOR_SYSEX > 0
01280     Bit8u *rset = mt32ram.system.chanAssign;
01281     printDebug(" Part assign:     1=%02d 2=%02d 3=%02d 4=%02d 5=%02d 6=%02d 7=%02d 8=%02d Rhythm=%02d", rset[0], rset[1], rset[2], rset[3], rset[4], rset[5], rset[6], rset[7], rset[8]);
01282 #endif
01283 }
01284 
01285 void Synth::refreshSystemMasterVol() {
01286 #if MT32EMU_MONITOR_SYSEX > 0
01287     printDebug(" Master volume: %d", mt32ram.system.masterVol);
01288 #endif
01289 }
01290 
01291 void Synth::refreshSystem() {
01292     refreshSystemMasterTune();
01293     refreshSystemReverbParameters();
01294     refreshSystemReserveSettings();
01295     refreshSystemChanAssign(0, 8);
01296     refreshSystemMasterVol();
01297 }
01298 
01299 void Synth::reset() {
01300 #if MT32EMU_MONITOR_SYSEX > 0
01301     printDebug("RESET");
01302 #endif
01303     reportHandler->onDeviceReset();
01304     partialManager->deactivateAll();
01305     mt32ram = mt32default;
01306     for (int i = 0; i < 9; i++) {
01307         parts[i]->reset();
01308         if (i != 8) {
01309             parts[i]->setProgram(controlROMData[controlROMMap->programSettings + i]);
01310         } else {
01311             parts[8]->refresh();
01312         }
01313     }
01314     refreshSystem();
01315     isEnabled = false;
01316 }
01317 
01318 void Synth::render(Bit16s *stream, Bit32u len) {
01319     if (!isEnabled) {
01320         memset(stream, 0, len * sizeof(Bit16s) * 2);
01321         return;
01322     }
01323     while (len > 0) {
01324         Bit32u thisLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len;
01325         renderStreams(tmpNonReverbLeft, tmpNonReverbRight, tmpReverbDryLeft, tmpReverbDryRight, tmpReverbWetLeft, tmpReverbWetRight, thisLen);
01326         for (Bit32u i = 0; i < thisLen; i++) {
01327             stream[0] = clipBit16s((Bit32s)tmpNonReverbLeft[i] + (Bit32s)tmpReverbDryLeft[i] + (Bit32s)tmpReverbWetLeft[i]);
01328             stream[1] = clipBit16s((Bit32s)tmpNonReverbRight[i] + (Bit32s)tmpReverbDryRight[i] + (Bit32s)tmpReverbWetRight[i]);
01329             stream += 2;
01330         }
01331         len -= thisLen;
01332     }
01333 }
01334 
01335 bool Synth::prerender() {
01336     int newPrerenderWriteIx = (prerenderWriteIx + 1) % MAX_PRERENDER_SAMPLES;
01337     if (newPrerenderWriteIx == prerenderReadIx) {
01338         // The prerender buffer is full
01339         return false;
01340     }
01341     doRenderStreams(
01342         prerenderNonReverbLeft + prerenderWriteIx,
01343         prerenderNonReverbRight + prerenderWriteIx,
01344         prerenderReverbDryLeft + prerenderWriteIx,
01345         prerenderReverbDryRight + prerenderWriteIx,
01346         prerenderReverbWetLeft + prerenderWriteIx,
01347         prerenderReverbWetRight + prerenderWriteIx,
01348         1);
01349     prerenderWriteIx = newPrerenderWriteIx;
01350     return true;
01351 }
01352 
01353 static inline void maybeCopy(Bit16s *out, Bit32u outPos, Bit16s *in, Bit32u inPos, Bit32u len) {
01354     if (out == NULL) {
01355         return;
01356     }
01357     memcpy(out + outPos, in + inPos, len * sizeof(Bit16s));
01358 }
01359 
01360 void Synth::copyPrerender(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u pos, Bit32u len) {
01361     maybeCopy(nonReverbLeft, pos, prerenderNonReverbLeft, prerenderReadIx, len);
01362     maybeCopy(nonReverbRight, pos, prerenderNonReverbRight, prerenderReadIx, len);
01363     maybeCopy(reverbDryLeft, pos, prerenderReverbDryLeft, prerenderReadIx, len);
01364     maybeCopy(reverbDryRight, pos, prerenderReverbDryRight, prerenderReadIx, len);
01365     maybeCopy(reverbWetLeft, pos, prerenderReverbWetLeft, prerenderReadIx, len);
01366     maybeCopy(reverbWetRight, pos, prerenderReverbWetRight, prerenderReadIx, len);
01367 }
01368 
01369 void Synth::checkPrerender(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u &pos, Bit32u &len) {
01370     if (prerenderReadIx > prerenderWriteIx) {
01371         // There's data in the prerender buffer, and the write index has wrapped.
01372         Bit32u prerenderCopyLen = MAX_PRERENDER_SAMPLES - prerenderReadIx;
01373         if (prerenderCopyLen > len) {
01374             prerenderCopyLen = len;
01375         }
01376         copyPrerender(nonReverbLeft, nonReverbRight, reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, pos, prerenderCopyLen);
01377         len -= prerenderCopyLen;
01378         pos += prerenderCopyLen;
01379         prerenderReadIx = (prerenderReadIx + prerenderCopyLen) % MAX_PRERENDER_SAMPLES;
01380     }
01381     if (prerenderReadIx < prerenderWriteIx) {
01382         // There's data in the prerender buffer, and the write index is ahead of the read index.
01383         Bit32u prerenderCopyLen = prerenderWriteIx - prerenderReadIx;
01384         if (prerenderCopyLen > len) {
01385             prerenderCopyLen = len;
01386         }
01387         copyPrerender(nonReverbLeft, nonReverbRight, reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, pos, prerenderCopyLen);
01388         len -= prerenderCopyLen;
01389         pos += prerenderCopyLen;
01390         prerenderReadIx += prerenderCopyLen;
01391     }
01392     if (prerenderReadIx == prerenderWriteIx) {
01393         // If the ring buffer's empty, reset it to start at 0 to minimise wrapping,
01394         // which requires two writes instead of one.
01395         prerenderReadIx = prerenderWriteIx = 0;
01396     }
01397 }
01398 
01399 void Synth::renderStreams(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u len) {
01400     if (!isEnabled) {
01401         clearIfNonNull(nonReverbLeft, len);
01402         clearIfNonNull(nonReverbRight, len);
01403         clearIfNonNull(reverbDryLeft, len);
01404         clearIfNonNull(reverbDryRight, len);
01405         clearIfNonNull(reverbWetLeft, len);
01406         clearIfNonNull(reverbWetRight, len);
01407         return;
01408     }
01409     Bit32u pos = 0;
01410 
01411     // First, check for data in the prerender buffer and spit that out before generating anything new.
01412     // Note that the prerender buffer is rarely used - see comments elsewhere for details.
01413     checkPrerender(nonReverbLeft, nonReverbRight, reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, pos, len);
01414 
01415     while (len > 0) {
01416         Bit32u thisLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len;
01417         doRenderStreams(
01418             streamOffset(nonReverbLeft, pos),
01419             streamOffset(nonReverbRight, pos),
01420             streamOffset(reverbDryLeft, pos),
01421             streamOffset(reverbDryRight, pos),
01422             streamOffset(reverbWetLeft, pos),
01423             streamOffset(reverbWetRight, pos),
01424             thisLen);
01425         len -= thisLen;
01426         pos += thisLen;
01427     }
01428 }
01429 
01430 // FIXME: Using more temporary buffers than we need to
01431 void Synth::doRenderStreams(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u len) {
01432     clearFloats(&tmpBufMixLeft[0], &tmpBufMixRight[0], len);
01433     if (!reverbEnabled) {
01434         for (unsigned int i = 0; i < getPartialLimit(); i++) {
01435             if (partialManager->produceOutput(i, &tmpBufPartialLeft[0], &tmpBufPartialRight[0], len)) {
01436                 mix(&tmpBufMixLeft[0], &tmpBufPartialLeft[0], len);
01437                 mix(&tmpBufMixRight[0], &tmpBufPartialRight[0], len);
01438             }
01439         }
01440         if (nonReverbLeft != NULL) {
01441             la32FloatToBit16sFunc(nonReverbLeft, &tmpBufMixLeft[0], len, outputGain);
01442         }
01443         if (nonReverbRight != NULL) {
01444             la32FloatToBit16sFunc(nonReverbRight, &tmpBufMixRight[0], len, outputGain);
01445         }
01446         clearIfNonNull(reverbDryLeft, len);
01447         clearIfNonNull(reverbDryRight, len);
01448         clearIfNonNull(reverbWetLeft, len);
01449         clearIfNonNull(reverbWetRight, len);
01450     } else {
01451         for (unsigned int i = 0; i < getPartialLimit(); i++) {
01452             if (!partialManager->shouldReverb(i)) {
01453                 if (partialManager->produceOutput(i, &tmpBufPartialLeft[0], &tmpBufPartialRight[0], len)) {
01454                     mix(&tmpBufMixLeft[0], &tmpBufPartialLeft[0], len);
01455                     mix(&tmpBufMixRight[0], &tmpBufPartialRight[0], len);
01456                 }
01457             }
01458         }
01459         if (nonReverbLeft != NULL) {
01460             la32FloatToBit16sFunc(nonReverbLeft, &tmpBufMixLeft[0], len, outputGain);
01461         }
01462         if (nonReverbRight != NULL) {
01463             la32FloatToBit16sFunc(nonReverbRight, &tmpBufMixRight[0], len, outputGain);
01464         }
01465 
01466         clearFloats(&tmpBufMixLeft[0], &tmpBufMixRight[0], len);
01467         for (unsigned int i = 0; i < getPartialLimit(); i++) {
01468             if (partialManager->shouldReverb(i)) {
01469                 if (partialManager->produceOutput(i, &tmpBufPartialLeft[0], &tmpBufPartialRight[0], len)) {
01470                     mix(&tmpBufMixLeft[0], &tmpBufPartialLeft[0], len);
01471                     mix(&tmpBufMixRight[0], &tmpBufPartialRight[0], len);
01472                 }
01473             }
01474         }
01475         if (reverbDryLeft != NULL) {
01476             la32FloatToBit16sFunc(reverbDryLeft, &tmpBufMixLeft[0], len, outputGain);
01477         }
01478         if (reverbDryRight != NULL) {
01479             la32FloatToBit16sFunc(reverbDryRight, &tmpBufMixRight[0], len, outputGain);
01480         }
01481 
01482         // FIXME: Note that on the real devices, reverb input and output are signed linear 16-bit (well, kinda, there's some fudging) PCM, not float.
01483         reverbModel->process(&tmpBufMixLeft[0], &tmpBufMixRight[0], &tmpBufReverbOutLeft[0], &tmpBufReverbOutRight[0], len);
01484         if (reverbWetLeft != NULL) {
01485             reverbFloatToBit16sFunc(reverbWetLeft, &tmpBufReverbOutLeft[0], len, reverbOutputGain);
01486         }
01487         if (reverbWetRight != NULL) {
01488             reverbFloatToBit16sFunc(reverbWetRight, &tmpBufReverbOutRight[0], len, reverbOutputGain);
01489         }
01490     }
01491     partialManager->clearAlreadyOutputed();
01492     renderedSampleCount += len;
01493 }
01494 
01495 void Synth::printPartialUsage(unsigned long sampleOffset) {
01496     unsigned int partialUsage[9];
01497     partialManager->getPerPartPartialUsage(partialUsage);
01498     if (sampleOffset > 0) {
01499         printDebug("[+%lu] Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d  TOTAL: %02d", sampleOffset, partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], getPartialLimit() - partialManager->getFreePartialCount());
01500     } else {
01501         printDebug("Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d  TOTAL: %02d", partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], getPartialLimit() - partialManager->getFreePartialCount());
01502     }
01503 }
01504 
01505 bool Synth::hasActivePartials() const {
01506     if (prerenderReadIx != prerenderWriteIx) {
01507         // Data in the prerender buffer means that the current isActive() states are "in the future".
01508         // It also means that partials are definitely active at this render point.
01509         return true;
01510     }
01511     for (unsigned int partialNum = 0; partialNum < getPartialLimit(); partialNum++) {
01512         if (partialManager->getPartial(partialNum)->isActive()) {
01513             return true;
01514         }
01515     }
01516     return false;
01517 }
01518 
01519 bool Synth::isActive() const {
01520     if (hasActivePartials()) {
01521         return true;
01522     }
01523     if (reverbEnabled) {
01524         return reverbModel->isActive();
01525     }
01526     return false;
01527 }
01528 
01529 const Partial *Synth::getPartial(unsigned int partialNum) const {
01530     return partialManager->getPartial(partialNum);
01531 }
01532 
01533 const Part *Synth::getPart(unsigned int partNum) const {
01534     if (partNum > 8) {
01535         return NULL;
01536     }
01537     return parts[partNum];
01538 }
01539 
01540 void MemoryRegion::read(unsigned int entry, unsigned int off, Bit8u *dst, unsigned int len) const {
01541     off += entry * entrySize;
01542     // This method should never be called with out-of-bounds parameters,
01543     // or on an unsupported region - seeing any of this debug output indicates a bug in the emulator
01544     if (off > entrySize * entries - 1) {
01545 #if MT32EMU_MONITOR_SYSEX > 0
01546         synth->printDebug("read[%d]: parameters start out of bounds: entry=%d, off=%d, len=%d", type, entry, off, len);
01547 #endif
01548         return;
01549     }
01550     if (off + len > entrySize * entries) {
01551 #if MT32EMU_MONITOR_SYSEX > 0
01552         synth->printDebug("read[%d]: parameters end out of bounds: entry=%d, off=%d, len=%d", type, entry, off, len);
01553 #endif
01554         len = entrySize * entries - off;
01555     }
01556     Bit8u *src = getRealMemory();
01557     if (src == NULL) {
01558 #if MT32EMU_MONITOR_SYSEX > 0
01559         synth->printDebug("read[%d]: unreadable region: entry=%d, off=%d, len=%d", type, entry, off, len);
01560 #endif
01561         return;
01562     }
01563     memcpy(dst, src + off, len);
01564 }
01565 
01566 void MemoryRegion::write(unsigned int entry, unsigned int off, const Bit8u *src, unsigned int len, bool init) const {
01567     unsigned int memOff = entry * entrySize + off;
01568     // This method should never be called with out-of-bounds parameters,
01569     // or on an unsupported region - seeing any of this debug output indicates a bug in the emulator
01570     if (off > entrySize * entries - 1) {
01571 #if MT32EMU_MONITOR_SYSEX > 0
01572         synth->printDebug("write[%d]: parameters start out of bounds: entry=%d, off=%d, len=%d", type, entry, off, len);
01573 #endif
01574         return;
01575     }
01576     if (off + len > entrySize * entries) {
01577 #if MT32EMU_MONITOR_SYSEX > 0
01578         synth->printDebug("write[%d]: parameters end out of bounds: entry=%d, off=%d, len=%d", type, entry, off, len);
01579 #endif
01580         len = entrySize * entries - off;
01581     }
01582     Bit8u *dest = getRealMemory();
01583     if (dest == NULL) {
01584 #if MT32EMU_MONITOR_SYSEX > 0
01585         synth->printDebug("write[%d]: unwritable region: entry=%d, off=%d, len=%d", type, entry, off, len);
01586 #endif
01587     }
01588 
01589     for (unsigned int i = 0; i < len; i++) {
01590         Bit8u desiredValue = src[i];
01591         Bit8u maxValue = getMaxValue(memOff);
01592         // maxValue == 0 means write-protected unless called from initialisation code, in which case it really means the maximum value is 0.
01593         if (maxValue != 0 || init) {
01594             if (desiredValue > maxValue) {
01595 #if MT32EMU_MONITOR_SYSEX > 0
01596                 synth->printDebug("write[%d]: Wanted 0x%02x at %d, but max 0x%02x", type, desiredValue, memOff, maxValue);
01597 #endif
01598                 desiredValue = maxValue;
01599             }
01600             dest[memOff] = desiredValue;
01601         } else if (desiredValue != 0) {
01602 #if MT32EMU_MONITOR_SYSEX > 0
01603             // Only output debug info if they wanted to write non-zero, since a lot of things cause this to spit out a lot of debug info otherwise.
01604             synth->printDebug("write[%d]: Wanted 0x%02x at %d, but write-protected", type, desiredValue, memOff);
01605 #endif
01606         }
01607         memOff++;
01608     }
01609 }
01610 
01611 
01612 void Synth::setPartialLimit( unsigned int _partialLimit )
01613 {
01614     /* NTS: A memory leak can occur if we open the synth with the initial (max)
01615         number of partials, then allow DOSBox-X to call setPartialLimit()
01616         with an (often lower) partial count, because the PartialManager()
01617         will later free only that lower count of partials. To prevent this,
01618         we throw a C++ exception if an attempt is made while the synth is
01619         open to call this function. */
01620     if (isOpen) throw std::runtime_error("MT32 attempt to change partial limit while synth is open");
01621     partialLimit = _partialLimit;
01622 }
01623 
01624 
01625 unsigned int Synth::getPartialLimit() const
01626 {
01627     return partialLimit;
01628 }
01629 
01630 
01631 void Synth::findPart( const Part *src, Bit8u *index_out )
01632 {
01633     Bit8u part_idx;
01634 
01635 
01636     part_idx = 0xff;
01637     if( src != NULL ) {
01638 #ifdef WIN32_DEBUG
01639         bool stop = false;
01640 #endif
01641     
01642         part_idx = 0;
01643         for( unsigned int lcv=0; lcv<9; lcv++ ) {
01644             if( src == getPart(lcv) ) {
01645 #ifdef WIN32_DEBUG
01646                 stop = true;
01647 #endif
01648                 break;
01649             }
01650 
01651             part_idx++;
01652         }
01653 
01654 #ifdef WIN32_DEBUG
01655         // DEBUG
01656         if( stop == false ) __asm int 3
01657 #endif
01658     }
01659 
01660 
01661     *index_out = part_idx;
01662 }
01663 
01664 
01665 void Synth::findPartial( const Partial *src, Bit8u *index_out )
01666 {
01667     Bit8u partials_idx;
01668 
01669 
01670     partials_idx = 0xff;
01671     if( src != NULL ) {
01672 #ifdef WIN32_DEBUG
01673         bool stop = false;
01674 #endif
01675 
01676         partials_idx = 0;
01677         for( unsigned int lcv=0; lcv<getPartialLimit(); lcv++ ) {
01678             if( src == getPartial(lcv) ) {
01679 #ifdef WIN32_DEBUG
01680                 stop = true;
01681 #endif
01682                 break;
01683             }
01684 
01685             partials_idx++;
01686         }
01687 
01688 #ifdef WIN32_DEBUG
01689         // DEBUG
01690         if( stop == false ) __asm int 3
01691 #endif
01692     }
01693 
01694 
01695     *index_out = partials_idx;
01696 }
01697 
01698 
01699 void Synth::findPartialParam( const TimbreParam::PartialParam *src, Bit16u *index_out1, Bit16u *index_out2 )
01700 {
01701     Bit16u partialParam_idx1, partialParam_idx2;
01702 
01703     partialParam_idx1 = 0xffff;
01704     partialParam_idx2 = 0xffff;
01705 
01706     if( src != NULL ) {
01707         bool stop = false;
01708         partialParam_idx1 = 0;
01709 
01710         // #1 = mt32ram.timbres[] - partial
01711         for( int lcv1=0; lcv1<256; lcv1++ ) {
01712             partialParam_idx2 = 0;
01713 
01714             for( int lcv2=0; lcv2<4; lcv2++ ) {
01715                 if( src == &mt32ram.timbres[lcv1].timbre.partial[lcv2] ) { stop = true; break; }
01716 
01717                 partialParam_idx2++;
01718             }
01719             if( stop == true ) break;
01720 
01721             partialParam_idx1++;
01722         }
01723 
01724 
01725         if( stop == false ) {
01726             partialParam_idx1 = 0x1000;
01727 
01728             // #2 = mt32ram.timbreTemp - partial[]
01729             for( int lcv1=0; lcv1<8; lcv1++ ) {
01730                 partialParam_idx2 = 0;
01731 
01732                 for( int lcv2=0; lcv2<4; lcv2++ ) {
01733                     if( src == &mt32ram.timbreTemp[lcv1].partial[lcv2] ) { stop = true; break; }
01734 
01735                     partialParam_idx2++;
01736                 }
01737                 if( stop == true ) break;
01738 
01739                 partialParam_idx1++;
01740             }
01741         }
01742 
01743 
01744         if( stop == false ) {
01745             partialParam_idx1 = 0x2000;
01746 
01747             // #3 = parts[0-7] - patchCache[0-3].srcPartial
01748             for( int lcv1=0; lcv1<8; lcv1++ ) {
01749                 partialParam_idx2 = 0;
01750 
01751                 for( int lcv2=0; lcv2<4; lcv2++ ) {
01752                     Part *part;
01753 
01754                     part = (Part *) getPart(lcv1);
01755                     if( src == &part->getPatchCache(lcv2)->srcPartial ) { stop = true; break; }
01756 
01757                     partialParam_idx2++;
01758                 }
01759                 if( stop == true ) break;
01760 
01761                 partialParam_idx1++;
01762             }
01763         }
01764 
01765 
01766         if( stop == false ) {
01767             partialParam_idx1 = 0x3000;
01768 
01769             // #4 = parts[8] - patchCache[0-3].srcPartial (Rhythm)
01770             for( int lcv1=0; lcv1<1; lcv1++ ) {
01771                 partialParam_idx2 = 0;
01772 
01773                 for( int lcv2=0; lcv2<4; lcv2++ ) {
01774                     RhythmPart *part;
01775 
01776                     part = (RhythmPart *) getPart(8);
01777                     if( src == &part->getPatchCache(lcv2)->srcPartial ) { stop = true; break; }
01778 
01779                     partialParam_idx2++;
01780                 }
01781                 if( stop == true ) break;
01782 
01783                 partialParam_idx1++;
01784             }
01785         }
01786 
01787 
01788         if( stop == false ) {
01789             partialParam_idx1 = 0x4000;
01790 
01791             // #5 = parts[8] - drumCache[][].srcPartial (Rhythm)
01792             for( int lcv1=0; lcv1<85; lcv1++ ) {
01793                 partialParam_idx2 = 0;
01794 
01795                 for( int lcv2=0; lcv2<4; lcv2++ ) {
01796                     RhythmPart *part;
01797 
01798                     part = (RhythmPart *) getPart(8);
01799                     if( src == &part->getDrumCache(lcv1,lcv2)->srcPartial ) { stop = true; break; }
01800 
01801                     partialParam_idx2++;
01802                 }
01803                 if( stop == true ) break;
01804 
01805                 partialParam_idx1++;
01806             }
01807         }
01808 
01809 
01810         if( stop == false ) {
01811             partialParam_idx1 = 0x5000;
01812 
01813             // #6 = partials[] - cacheBackup
01814             for( unsigned int lcv1=0; lcv1<getPartialLimit(); lcv1++ ) {
01815                 partialParam_idx2 = 0;
01816 
01817                 for( int lcv2=0; lcv2<1; lcv2++ ) {
01818                     if( src == &getPartial(lcv1)->cachebackup.srcPartial ) { stop = true; break; }
01819 
01820                     partialParam_idx2++;
01821                 }
01822                 if( stop == true ) break;
01823 
01824                 partialParam_idx1++;
01825             }
01826 
01827 
01828 #ifdef WIN32_DEBUG
01829             // DEBUG
01830             if( stop == false ) __asm int 3
01831 #endif
01832         }
01833     }
01834 
01835 
01836     *index_out1 = partialParam_idx1;
01837     *index_out2 = partialParam_idx2;
01838 }
01839 
01840 
01841 void Synth::findPatchCache( const PatchCache *src, Bit16u *index_out1, Bit16u *index_out2 )
01842 {
01843     Bit16u patchCache_idx1, patchCache_idx2;
01844 
01845     patchCache_idx1 = 0xffff;
01846     patchCache_idx2 = 0xffff;
01847 
01848     if( src != NULL ) {
01849         bool stop = false;
01850         patchCache_idx1 = 0;
01851 
01852         // #1 = parts[0-7] - patchCache
01853         for( int lcv1=0; lcv1<8; lcv1++ ) {
01854             patchCache_idx2 = 0;
01855 
01856             for( int lcv2=0; lcv2<4; lcv2++ ) {
01857                 Part *part;
01858 
01859                 part = (Part *) getPart(lcv1);
01860                 if( src == part->getPatchCache(lcv2) ) { stop = true; break; }
01861 
01862                 patchCache_idx2++;
01863             }
01864             if( stop == true ) break;
01865 
01866             patchCache_idx1++;
01867         }
01868 
01869 
01870         if( stop == false ) {
01871             patchCache_idx1 = 0x1000;
01872 
01873             // #2 parts[8] - patchCache (Rhythm)
01874             for( int lcv1=0; lcv1<1; lcv1++ ) {
01875                 patchCache_idx2 = 0;
01876 
01877                 for( int lcv2=0; lcv2<4; lcv2++ ) {
01878                     RhythmPart *part;
01879 
01880                     part = (RhythmPart *) getPart(8);
01881                     if( src == part->getPatchCache(lcv2) ) { stop = true; break; }
01882 
01883                     patchCache_idx2++;
01884                 }
01885                 if( stop == true ) break;
01886 
01887                 patchCache_idx1++;
01888             }
01889         }
01890 
01891 
01892         if( stop == false ) {
01893             patchCache_idx1 = 0x2000;
01894 
01895             // #3 parts[8] - drumcache[][] (Rhythm)
01896             for( int lcv1=0; lcv1<85; lcv1++ ) {
01897                 patchCache_idx2 = 0;
01898 
01899                 for( int lcv2=0; lcv2<4; lcv2++ ) {
01900                     RhythmPart *part;
01901 
01902                     part = (RhythmPart *) getPart(8);
01903                     if( src == part->getDrumCache(lcv1,lcv2) ) { stop = true; break; }
01904 
01905                     patchCache_idx2++;
01906                 }
01907                 if( stop == true ) break;
01908 
01909                 patchCache_idx1++;
01910             }
01911         }
01912 
01913 
01914         if( stop == false ) {
01915             patchCache_idx1 = 0x3000;
01916 
01917             // #4 partials[] - cacheBackup
01918             for( unsigned int lcv1=0; lcv1<getPartialLimit(); lcv1++ ) {
01919                 patchCache_idx2 = 0;
01920 
01921                 for( int lcv2=0; lcv2<1; lcv2++ ) {
01922                     if( src == &getPartial(lcv1)->cachebackup ) { stop = true; break; }
01923 
01924                     patchCache_idx2++;
01925                 }
01926                 if( stop == true ) break;
01927 
01928                 patchCache_idx1++;
01929             }
01930 
01931 
01932 #ifdef WIN32_DEBUG
01933             // DEBUG
01934             if( stop == false ) __asm int 3
01935 #endif
01936         }
01937     }
01938 
01939 
01940     *index_out1 = patchCache_idx1;
01941     *index_out2 = patchCache_idx2;
01942 }
01943 
01944 
01945 void Synth::findPatchTemp( const MemParams::PatchTemp *src, Bit8u *index_out )
01946 {
01947     Bit8u patchTemp_idx;
01948 
01949 
01950     patchTemp_idx = 0xff;
01951     if( src != NULL ) {
01952 #ifdef WIN32_DEBUG
01953         bool stop = false;
01954 #endif
01955 
01956         patchTemp_idx = 0;
01957         for( int lcv=0; lcv<9; lcv++ ) {
01958             if( src == &mt32ram.patchTemp[lcv] ) {
01959 #ifdef WIN32_DEBUG
01960                 stop = true;
01961 #endif
01962                 break;
01963             }
01964 
01965             patchTemp_idx++;
01966         }
01967 
01968 
01969 #ifdef WIN32_DEBUG
01970         // DEBUG
01971         if( stop == false ) __asm int 3
01972 #endif
01973     }
01974 
01975 
01976     *index_out = patchTemp_idx;
01977 }
01978 
01979 
01980 void Synth::findPCMWaveEntry( const PCMWaveEntry *src, Bit16u *index_out )
01981 {
01982     Bit16u PCMWaveEntry_idx;
01983 
01984     PCMWaveEntry_idx = 0xffff;
01985     if( src != NULL ) {
01986 #ifdef WIN32_DEBUG
01987         bool stop = false;
01988 #endif
01989 
01990         PCMWaveEntry_idx = 0;
01991         for( int lcv=0; lcv<controlROMMap->pcmCount; lcv++ ) {
01992             if( src == &pcmWaves[lcv] ) {
01993 #ifdef WIN32_DEBUG
01994                 stop = true;
01995 #endif
01996                 break;
01997             }
01998 
01999             PCMWaveEntry_idx++;
02000         }
02001 
02002 
02003 #ifdef WIN32_DEBUG
02004         // DEBUG
02005         if( stop == false ) __asm int 3
02006 #endif
02007     }
02008 
02009 
02010     *index_out = PCMWaveEntry_idx;
02011 }
02012 
02013 // WE NEED TO REFRESH THIS
02014 void Synth::findPoly( const Poly *src, Bit16u *index_out1, Bit16u *index_out2 )
02015 {
02016     Bit16u poly_idx1, poly_idx2;
02017 
02018 
02019     poly_idx1 = 0xffff;
02020     poly_idx2 = 0xffff;
02021 
02022     if( src != NULL ) {
02023         bool stop;
02024 
02025         poly_idx1 = 0;
02026         stop = false;
02027 
02028         for( int lcv1=0; lcv1<9; lcv1++ ) {
02029             Part *part;
02030             part = (Part *) getPart(lcv1);
02031 
02032             poly_idx2 = 0;
02033 
02034             for( int lcv2=0; lcv2<part->getActivePolyCount(); lcv2++ ) {
02035                 if( src == part->getActivePoly(lcv2) ) { stop = true; break; }
02036 
02037                 poly_idx2++;
02038             }
02039             if( stop ) break;
02040 
02041             poly_idx1++;
02042         }
02043 
02044 
02045 #ifdef WIN32_DEBUG
02046         // DEBUG
02047         if( stop == false ) __asm int 3
02048 #endif
02049     }
02050 
02051     *index_out1 = poly_idx1;
02052     *index_out2 = poly_idx2;
02053 }
02054 
02055 
02056 
02057 void Synth::findRhythmTemp( const MemParams::RhythmTemp *src, Bit8u *index_out )
02058 {
02059     Bit8u rhythmTemp_idx;
02060 
02061     rhythmTemp_idx = 0xff;
02062     if( src != NULL ) {
02063 #ifdef WIN32_DEBUG
02064         bool stop = false;
02065 #endif
02066 
02067         rhythmTemp_idx = 0;
02068         for( int lcv=0; lcv<85; lcv++ ) {
02069             if( src == &mt32ram.rhythmTemp[lcv] ) {
02070 #ifdef WIN32_DEBUG
02071                 stop = true;
02072 #endif
02073                 break;
02074             }
02075 
02076             rhythmTemp_idx++;
02077         }
02078 
02079 #ifdef WIN32_DEBUG
02080         // DEBUG
02081         if( stop == false ) __asm int 3
02082 #endif
02083     }
02084 
02085 
02086     *index_out = rhythmTemp_idx;
02087 }
02088 
02089 
02090 void Synth::findTimbreParam( const TimbreParam *src, Bit8u *index_out )
02091 {
02092     Bit8u timbreParam_idx;
02093 
02094 
02095     timbreParam_idx = 0xff;
02096     if( src != NULL ) {
02097 #ifdef WIN32_DEBUG
02098         bool stop = false;
02099 #endif
02100 
02101         timbreParam_idx = 0;
02102         for( int lcv=0; lcv<8; lcv++ ) {
02103             if( src == &mt32ram.timbreTemp[lcv] ) {
02104 #ifdef WIN32_DEBUG
02105                 stop = true;
02106 #endif
02107                 break;
02108             }
02109 
02110             timbreParam_idx++;
02111         }
02112 
02113 #ifdef WIN32_DEBUG
02114         // DEBUG
02115         if( stop == false ) __asm int 3
02116 #endif
02117     }
02118 
02119 
02120     *index_out = timbreParam_idx;
02121 }
02122 
02123 
02124 Part *Synth::indexPart( Bit8u index )
02125 {
02126     Part *ptr;
02127 
02128     ptr = NULL;
02129     if( index != 0xff )
02130         ptr = (Part *) getPart(index);
02131 
02132     return ptr;
02133 }
02134 
02135 
02136 Partial *Synth::indexPartial( Bit8u index )
02137 {
02138     Partial *ptr;
02139 
02140     ptr = NULL;
02141     if( index != 0xff )
02142         ptr = (Partial *) getPartial(index);
02143 
02144     return ptr;
02145 }
02146 
02147 
02148 TimbreParam::PartialParam *Synth::indexPartialParam( Bit16u index1, Bit16u index2 )
02149 {
02150     TimbreParam::PartialParam *ptr;
02151 
02152 
02153     ptr = NULL;
02154     if( index1 < 0x1000 ) {
02155         index1 -= 0x0000;
02156 
02157         ptr = &mt32ram.timbres[index1].timbre.partial[index2];
02158     }
02159     else if( index1 < 0x2000 ) {
02160         index1 -= 0x1000;
02161 
02162         ptr = &mt32ram.timbreTemp[index1].partial[index2];
02163     }
02164     else if( index1 < 0x3000 ) {
02165         Part *part;
02166 
02167         index1 -= 0x2000;
02168 
02169         part = (Part *) getPart(index1);
02170         ptr = (TimbreParam::PartialParam *) &part->getPatchCache(index2)->srcPartial;
02171     }
02172     else if( index1 < 0x4000 ) {
02173         RhythmPart *part;
02174 
02175         index1 -= 0x3000;
02176 
02177         part = (RhythmPart *) getPart(8);
02178         ptr = (TimbreParam::PartialParam *) &part->getPatchCache(index2)->srcPartial;
02179     }
02180     else if( index1 < 0x5000 ) {
02181         RhythmPart *part;
02182 
02183         index1 -= 0x4000;
02184 
02185         part = (RhythmPart *) getPart(8);
02186         ptr = (TimbreParam::PartialParam *) &part->getDrumCache(index1,index2)->srcPartial;
02187     }
02188     else if( index1 < 0x6000 ) {
02189         index1 -= 0x5000;
02190 
02191         ptr = (TimbreParam::PartialParam *) &getPartial(index1)->cachebackup.srcPartial;
02192     }
02193 
02194 
02195     return ptr;
02196 }
02197 
02198 
02199 PatchCache *Synth::indexPatchCache( Bit16u index1, Bit16u index2 )
02200 {
02201     PatchCache *ptr;
02202 
02203 
02204     ptr = NULL;
02205     if( index1 < 0x1000 ) {
02206         Part *part;
02207 
02208         index1 -= 0x0000;
02209 
02210         part = (Part *) getPart(index1);
02211         ptr = (PatchCache *) part->getPatchCache(index2);
02212     }
02213     else if( index1 < 0x2000 ) {
02214         RhythmPart *part;
02215 
02216         index1 -= 0x1000;
02217 
02218         part = (RhythmPart *) getPart(8);
02219         ptr = (PatchCache *) part->getPatchCache(index2);
02220     }
02221     else if( index1 < 0x3000 ) {
02222         RhythmPart *part;
02223 
02224         index1 -= 0x2000;
02225 
02226         part = (RhythmPart *) getPart(8);
02227         ptr = (PatchCache *) part->getDrumCache(index1, index2);
02228     }
02229     else if( index1 < 0x4000 ) {
02230         index1 -= 0x3000;
02231 
02232         ptr = (PatchCache *) &getPartial(index1)->cachebackup;
02233     }
02234 
02235 
02236     return ptr;
02237 }
02238 
02239 
02240 MemParams::PatchTemp *Synth::indexPatchTemp( Bit8u index )
02241 {
02242     MemParams::PatchTemp *ptr;
02243 
02244     ptr = NULL;
02245     if( index != 0xff )
02246         ptr = &mt32ram.patchTemp[index];
02247 
02248     return ptr;
02249 }
02250 
02251 
02252 PCMWaveEntry *Synth::indexPCMWaveEntry( Bit16u index )
02253 {
02254     PCMWaveEntry *ptr;
02255 
02256     ptr = NULL;
02257     if( index != 0xffff ) {
02258         ptr = &pcmWaves[index];
02259     }
02260 
02261     return ptr;
02262 }
02263 
02264 // WE NEED TO REFRESH THIS
02265 Poly *Synth::indexPoly( Bit16u index1, Bit16u index2 )
02266 {
02267     Poly *ptr;
02268 
02269 
02270     ptr = NULL;
02271     if( index1 != 0xffff ) {
02272         Part *part;
02273         part = (Part *) getPart(index1);
02274 
02275         ptr = (Poly *) part->getActivePoly(index2);
02276     }
02277 
02278 
02279     return ptr;
02280 }
02281 
02282 
02283 MemParams::RhythmTemp *Synth::indexRhythmTemp( Bit8u index )
02284 {
02285     MemParams::RhythmTemp *ptr;
02286 
02287     ptr = NULL;
02288     if( index != 0xff ) {
02289         ptr = &mt32ram.rhythmTemp[index];
02290     }
02291 
02292     return ptr;
02293 }
02294 
02295 
02296 TimbreParam *Synth::indexTimbreParam( Bit8u index )
02297 {
02298     TimbreParam *ptr;
02299 
02300     ptr = NULL;
02301     if( index != 0xff )
02302         ptr = &mt32ram.timbreTemp[index];
02303 
02304     return ptr;
02305 }
02306 
02307 }
02308