DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/mt32/Partial.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 <cmath>
00019 #include <cstdlib>
00020 #include <cstring>
00021 
00022 #include "mt32emu.h"
00023 #include "mmath.h"
00024 
00025 namespace MT32Emu {
00026 
00027 #ifdef INACCURATE_SMOOTH_PAN
00028 // Mok wanted an option for smoother panning, and we love Mok.
00029 static const float PAN_NUMERATOR_NORMAL[] = {0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 5.5f, 6.0f, 6.5f, 7.0f};
00030 #else
00031 // CONFIRMED by Mok: These NUMERATOR values (as bytes, not floats, obviously) are sent exactly like this to the LA32.
00032 static const float PAN_NUMERATOR_NORMAL[] = {0.0f, 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 6.0f, 7.0f};
00033 #endif
00034 static const float PAN_NUMERATOR_MASTER[] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f};
00035 static const float PAN_NUMERATOR_SLAVE[]  = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 7.0f, 7.0f, 7.0f, 7.0f, 7.0f, 7.0f, 7.0f};
00036 
00037 Partial::Partial(Synth *useSynth, int useDebugPartialNum) :
00038         synth(useSynth), debugPartialNum(useDebugPartialNum), sampleNum(0) {
00039         // Initialisation of tva, tvp and tvf uses 'this' pointer
00040         // and thus should not be in the initializer list to avoid a compiler warning
00041         tva = new TVA(this, &ampRamp);
00042         tvp = new TVP(this);
00043         tvf = new TVF(this, &cutoffModifierRamp);
00044         ownerPart = -1;
00045         poly = NULL;
00046         pair = NULL;
00047 
00048 
00049         // init ptr warnings (load state crashes)
00050         pcmWave = NULL;
00051         patchCache = NULL;
00052         cachebackup.partialParam = NULL;
00053 }
00054 
00055 Partial::~Partial() {
00056         delete tva;
00057         delete tvp;
00058         delete tvf;
00059 }
00060 
00061 // Only used for debugging purposes
00062 int Partial::debugGetPartialNum() const {
00063         return debugPartialNum;
00064 }
00065 
00066 // Only used for debugging purposes
00067 unsigned long Partial::debugGetSampleNum() const {
00068         return sampleNum;
00069 }
00070 
00071 int Partial::getOwnerPart() const {
00072         return ownerPart;
00073 }
00074 
00075 bool Partial::isActive() const {
00076         return ownerPart > -1;
00077 }
00078 
00079 const Poly *Partial::getPoly() const {
00080         return poly;
00081 }
00082 
00083 void Partial::activate(int part) {
00084         // This just marks the partial as being assigned to a part
00085         ownerPart = part;
00086 }
00087 
00088 void Partial::deactivate() {
00089         if (!isActive()) {
00090                 return;
00091         }
00092         ownerPart = -1;
00093         if (poly != NULL) {
00094                 poly->partialDeactivated(this);
00095         }
00096         synth->partialStateChanged(this, tva->getPhase(), TVA_PHASE_DEAD);
00097 #if MT32EMU_MONITOR_PARTIALS > 2
00098         synth->printDebug("[+%lu] [Partial %d] Deactivated", sampleNum, debugPartialNum);
00099         synth->printPartialUsage(sampleNum);
00100 #endif
00101         if (isRingModulatingSlave()) {
00102                 pair->la32Pair.deactivate(LA32PartialPair::SLAVE);
00103         } else {
00104                 la32Pair.deactivate(LA32PartialPair::MASTER);
00105                 if (hasRingModulatingSlave()) {
00106                         pair->deactivate();
00107                         pair = NULL;
00108                 }
00109         }
00110 
00111         // loadstate ptr warnings (sometimes points to freePolys)
00112         poly = NULL;
00113 
00114         if (pair != NULL) {
00115                 pair->pair = NULL;
00116         }
00117 }
00118 
00119 void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *usePatchCache, const MemParams::RhythmTemp *rhythmTemp, Partial *pairPartial) {
00120         if (usePoly == NULL || usePatchCache == NULL) {
00121                 synth->printDebug("[Partial %d] *** Error: Starting partial for owner %d, usePoly=%s, usePatchCache=%s", debugPartialNum, ownerPart, usePoly == NULL ? "*** NULL ***" : "OK", usePatchCache == NULL ? "*** NULL ***" : "OK");
00122                 return;
00123         }
00124         patchCache = usePatchCache;
00125         poly = usePoly;
00126         mixType = patchCache->structureMix;
00127         structurePosition = patchCache->structurePosition;
00128 
00129         Bit8u panSetting = rhythmTemp != NULL ? rhythmTemp->panpot : part->getPatchTemp()->panpot;
00130         float panVal;
00131         if (mixType == 3) {
00132                 if (structurePosition == 0) {
00133                         panVal = PAN_NUMERATOR_MASTER[panSetting];
00134                 } else {
00135                         panVal = PAN_NUMERATOR_SLAVE[panSetting];
00136                 }
00137                 // Do a normal mix independent of any pair partial.
00138                 mixType = 0;
00139                 pairPartial = NULL;
00140         } else {
00141                 panVal = PAN_NUMERATOR_NORMAL[panSetting];
00142         }
00143 
00144         // FIXME: Sample analysis suggests that the use of panVal is linear, but there are some some quirks that still need to be resolved.
00145         stereoVolume.leftVol = panVal / 7.0f;
00146         stereoVolume.rightVol = 1.0f - stereoVolume.leftVol;
00147 
00148         // SEMI-CONFIRMED: From sample analysis:
00149         // Found that timbres with 3 or 4 partials (i.e. one using two partial pairs) are mixed in two different ways.
00150         // Either partial pairs are added or subtracted, it depends on how the partial pairs are allocated.
00151         // It seems that partials are grouped into quarters and if the partial pairs are allocated in different quarters the subtraction happens.
00152         // Though, this matters little for the majority of timbres, it becomes crucial for timbres which contain several partials that sound very close.
00153         // In this case that timbre can sound totally different depending of the way it is mixed up.
00154         // Most easily this effect can be displayed with the help of a special timbre consisting of several identical square wave partials (3 or 4).
00155         // Say, it is 3-partial timbre. Just play any two notes simultaneously and the polys very probably are mixed differently.
00156         // Moreover, the partial allocator retains the last partial assignment it did and all the subsequent notes will sound the same as the last released one.
00157         // The situation is better with 4-partial timbres since then a whole quarter is assigned for each poly. However, if a 3-partial timbre broke the normal
00158         // whole-quarter assignment or after some partials got aborted, even 4-partial timbres can be found sounding differently.
00159         // This behaviour is also confirmed with two more special timbres: one with identical sawtooth partials, and one with PCM wave 02.
00160         // For my personal taste, this behaviour rather enriches the sounding and should be emulated.
00161         // Also, the current partial allocator model probably needs to be refined.
00162         if (debugPartialNum & 8) {
00163                 stereoVolume.leftVol = -stereoVolume.leftVol;
00164                 stereoVolume.rightVol = -stereoVolume.rightVol;
00165         }
00166 
00167         if (patchCache->PCMPartial) {
00168                 pcmNum = patchCache->pcm;
00169                 if (synth->controlROMMap->pcmCount > 128) {
00170                         // CM-32L, etc. support two "banks" of PCMs, selectable by waveform type parameter.
00171                         if (patchCache->waveform > 1) {
00172                                 pcmNum += 128;
00173                         }
00174                 }
00175                 pcmWave = &synth->pcmWaves[pcmNum];
00176         } else {
00177                 pcmWave = NULL;
00178         }
00179 
00180         // CONFIRMED: pulseWidthVal calculation is based on information from Mok
00181         pulseWidthVal = (poly->getVelocity() - 64) * (patchCache->srcPartial.wg.pulseWidthVeloSensitivity - 7) + Tables::getInstance().pulseWidth100To255[patchCache->srcPartial.wg.pulseWidth];
00182         if (pulseWidthVal < 0) {
00183                 pulseWidthVal = 0;
00184         } else if (pulseWidthVal > 255) {
00185                 pulseWidthVal = 255;
00186         }
00187 
00188         pair = pairPartial;
00189         alreadyOutputed = false;
00190         tva->reset(part, patchCache->partialParam, rhythmTemp);
00191         tvp->reset(part, patchCache->partialParam);
00192         tvf->reset(patchCache->partialParam, tvp->getBasePitch());
00193 
00194         LA32PartialPair::PairType pairType;
00195         LA32PartialPair *useLA32Pair;
00196         if (isRingModulatingSlave()) {
00197                 pairType = LA32PartialPair::SLAVE;
00198                 useLA32Pair = &pair->la32Pair;
00199         } else {
00200                 pairType = LA32PartialPair::MASTER;
00201                 la32Pair.init(hasRingModulatingSlave(), mixType == 1);
00202                 useLA32Pair = &la32Pair;
00203         }
00204         if (isPCM()) {
00205                 useLA32Pair->initPCM(pairType, &synth->pcmROMData[pcmWave->addr], pcmWave->len, pcmWave->loop);
00206         } else {
00207                 useLA32Pair->initSynth(pairType, (patchCache->waveform & 1) != 0, pulseWidthVal, patchCache->srcPartial.tvf.resonance + 1);
00208         }
00209         if (!hasRingModulatingSlave()) {
00210                 la32Pair.deactivate(LA32PartialPair::SLAVE);
00211         }
00212         // Temporary integration hack
00213         stereoVolume.leftVol /= 8192.0f;
00214         stereoVolume.rightVol /= 8192.0f;
00215 }
00216 
00217 Bit32u Partial::getAmpValue() {
00218         // SEMI-CONFIRMED: From sample analysis:
00219         // (1) Tested with a single partial playing PCM wave 77 with pitchCoarse 36 and no keyfollow, velocity follow, etc.
00220         // This gives results within +/- 2 at the output (before any DAC bitshifting)
00221         // when sustaining at levels 156 - 255 with no modifiers.
00222         // (2) Tested with a special square wave partial (internal capture ID tva5) at TVA envelope levels 155-255.
00223         // This gives deltas between -1 and 0 compared to the real output. Note that this special partial only produces
00224         // positive amps, so negative still needs to be explored, as well as lower levels.
00225         //
00226         // Also still partially unconfirmed is the behaviour when ramping between levels, as well as the timing.
00227         // TODO: The tests above were performed using the float model, to be refined
00228         Bit32u ampRampVal = 67117056 - ampRamp.nextValue();
00229         if (ampRamp.checkInterrupt()) {
00230                 tva->handleInterrupt();
00231         }
00232         return ampRampVal;
00233 }
00234 
00235 Bit32u Partial::getCutoffValue() {
00236         if (isPCM()) {
00237                 return 0;
00238         }
00239         Bit32u cutoffModifierRampVal = cutoffModifierRamp.nextValue();
00240         if (cutoffModifierRamp.checkInterrupt()) {
00241                 tvf->handleInterrupt();
00242         }
00243         return (tvf->getBaseCutoff() << 18) + cutoffModifierRampVal;
00244 }
00245 
00246 unsigned long Partial::generateSamples(Bit16s *partialBuf, unsigned long length) {
00247         if (!isActive() || alreadyOutputed) {
00248                 return 0;
00249         }
00250         if (poly == NULL) {
00251                 synth->printDebug("[Partial %d] *** ERROR: poly is NULL at Partial::generateSamples()!", debugPartialNum);
00252                 return 0;
00253         }
00254         alreadyOutputed = true;
00255 
00256         for (sampleNum = 0; sampleNum < length; sampleNum++) {
00257                 if (!tva->isPlaying() || !la32Pair.isActive(LA32PartialPair::MASTER)) {
00258                         deactivate();
00259                         break;
00260                 }
00261                 la32Pair.generateNextSample(LA32PartialPair::MASTER, getAmpValue(), tvp->nextPitch(), getCutoffValue());
00262                 if (hasRingModulatingSlave()) {
00263                         la32Pair.generateNextSample(LA32PartialPair::SLAVE, pair->getAmpValue(), pair->tvp->nextPitch(), pair->getCutoffValue());
00264                         if (!pair->tva->isPlaying() || !la32Pair.isActive(LA32PartialPair::SLAVE)) {
00265                                 pair->deactivate();
00266                                 if (mixType == 2) {
00267                                         deactivate();
00268                                         break;
00269                                 }
00270                         }
00271                 }
00272                 *partialBuf++ = la32Pair.nextOutSample();
00273         }
00274         unsigned long renderedSamples = sampleNum;
00275         sampleNum = 0;
00276         return renderedSamples;
00277 }
00278 
00279 bool Partial::hasRingModulatingSlave() const {
00280         return pair != NULL && structurePosition == 0 && (mixType == 1 || mixType == 2);
00281 }
00282 
00283 bool Partial::isRingModulatingSlave() const {
00284         return pair != NULL && structurePosition == 1 && (mixType == 1 || mixType == 2);
00285 }
00286 
00287 bool Partial::isPCM() const {
00288         return pcmWave != NULL;
00289 }
00290 
00291 const ControlROMPCMStruct *Partial::getControlROMPCMStruct() const {
00292         if (pcmWave != NULL) {
00293                 return pcmWave->controlROMPCMStruct;
00294         }
00295         return NULL;
00296 }
00297 
00298 Synth *Partial::getSynth() const {
00299         return synth;
00300 }
00301 
00302 bool Partial::produceOutput(float *leftBuf, float *rightBuf, unsigned long length) {
00303         if (!isActive() || alreadyOutputed || isRingModulatingSlave()) {
00304                 return false;
00305         }
00306         if (poly == NULL) {
00307                 synth->printDebug("[Partial %d] *** ERROR: poly is NULL at Partial::produceOutput()!", debugPartialNum);
00308                 return false;
00309         }
00310         unsigned long numGenerated = generateSamples(myBuffer, length);
00311         for (unsigned int i = 0; i < numGenerated; i++) {
00312                 *leftBuf++ = myBuffer[i] * stereoVolume.leftVol;
00313                 *rightBuf++ = myBuffer[i] * stereoVolume.rightVol;
00314         }
00315         for (; numGenerated < length; numGenerated++) {
00316                 *leftBuf++ = 0.0f;
00317                 *rightBuf++ = 0.0f;
00318         }
00319         return true;
00320 }
00321 
00322 bool Partial::shouldReverb() {
00323         if (!isActive()) {
00324                 return false;
00325         }
00326         return patchCache->reverb;
00327 }
00328 
00329 void Partial::startAbort() {
00330         // This is called when the partial manager needs to terminate partials for re-use by a new Poly.
00331         tva->startAbort();
00332 }
00333 
00334 void Partial::startDecayAll() {
00335         tva->startDecay();
00336         tvp->startDecay();
00337         tvf->startDecay();
00338 }
00339 
00340 }