DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/mt32/LA32WaveGenerator.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 "mt32emu.h"
00020 #include "mmath.h"
00021 #include "LA32WaveGenerator.h"
00022 
00023 #if MT32EMU_ACCURATE_WG == 0
00024 
00025 namespace MT32Emu {
00026 
00027 static const Bit32u SINE_SEGMENT_RELATIVE_LENGTH = 1 << 18;
00028 static const Bit32u MIDDLE_CUTOFF_VALUE = 128 << 18;
00029 static const Bit32u RESONANCE_DECAY_THRESHOLD_CUTOFF_VALUE = 144 << 18;
00030 static const Bit32u MAX_CUTOFF_VALUE = 240 << 18;
00031 static const LogSample SILENCE = {65535, LogSample::POSITIVE};
00032 
00033 Bit16u LA32Utilites::interpolateExp(const Bit16u fract) {
00034         Bit16u expTabIndex = fract >> 3;
00035         Bit16u extraBits = ~fract & 7;
00036         Bit16u expTabEntry2 = 8191 - Tables::getInstance().exp9[expTabIndex];
00037         Bit16u expTabEntry1 = expTabIndex == 0 ? 8191 : (8191 - Tables::getInstance().exp9[expTabIndex - 1]);
00038         return expTabEntry2 + (((expTabEntry1 - expTabEntry2) * extraBits) >> 3);
00039 }
00040 
00041 Bit16s LA32Utilites::unlog(const LogSample &logSample) {
00042         //Bit16s sample = (Bit16s)EXP2F(13.0f - logSample.logValue / 1024.0f);
00043         Bit32u intLogValue = logSample.logValue >> 12;
00044         Bit16u fracLogValue = logSample.logValue & 4095;
00045         Bit16s sample = interpolateExp(fracLogValue) >> intLogValue;
00046         return logSample.sign == LogSample::POSITIVE ? sample : -sample;
00047 }
00048 
00049 void LA32Utilites::addLogSamples(LogSample &logSample1, const LogSample &logSample2) {
00050         Bit32u logSampleValue = logSample1.logValue + logSample2.logValue;
00051         logSample1.logValue = logSampleValue < 65536 ? (Bit16u)logSampleValue : 65535;
00052         logSample1.sign = logSample1.sign == logSample2.sign ? LogSample::POSITIVE : LogSample::NEGATIVE;
00053 }
00054 
00055 Bit32u LA32WaveGenerator::getSampleStep() {
00056         // sampleStep = EXP2F(pitch / 4096.0f + 4.0f)
00057         Bit32u sampleStep = LA32Utilites::interpolateExp(~pitch & 4095);
00058         sampleStep <<= pitch >> 12;
00059         sampleStep >>= 8;
00060         sampleStep &= ~1;
00061         return sampleStep;
00062 }
00063 
00064 Bit32u LA32WaveGenerator::getResonanceWaveLengthFactor(Bit32u effectiveCutoffValue) {
00065         // resonanceWaveLengthFactor = (Bit32u)EXP2F(12.0f + effectiveCutoffValue / 4096.0f);
00066         Bit32u resonanceWaveLengthFactor = LA32Utilites::interpolateExp(~effectiveCutoffValue & 4095);
00067         resonanceWaveLengthFactor <<= effectiveCutoffValue >> 12;
00068         return resonanceWaveLengthFactor;
00069 }
00070 
00071 Bit32u LA32WaveGenerator::getHighLinearLength(Bit32u effectiveCutoffValue) {
00072         // Ratio of positive segment to wave length
00073         Bit32u effectivePulseWidthValue = 0;
00074         if (pulseWidth > 128) {
00075                 effectivePulseWidthValue = (pulseWidth - 128) << 6;
00076         }
00077 
00078         Bit32u highLinearLength = 0;
00079         // highLinearLength = EXP2F(19.0f - effectivePulseWidthValue / 4096.0f + effectiveCutoffValue / 4096.0f) - 2 * SINE_SEGMENT_RELATIVE_LENGTH;
00080         if (effectivePulseWidthValue < effectiveCutoffValue) {
00081                 Bit32u expArg = effectiveCutoffValue - effectivePulseWidthValue;
00082                 highLinearLength = LA32Utilites::interpolateExp(~expArg & 4095);
00083                 highLinearLength <<= 7 + (expArg >> 12);
00084                 highLinearLength -= 2 * SINE_SEGMENT_RELATIVE_LENGTH;
00085         }
00086         return highLinearLength;
00087 }
00088 
00089 void LA32WaveGenerator::computePositions(Bit32u highLinearLength, Bit32u lowLinearLength, Bit32u resonanceWaveLengthFactor) {
00090         // Assuming 12-bit multiplication used here
00091         squareWavePosition = resonanceSinePosition = (wavePosition >> 8) * (resonanceWaveLengthFactor >> 4);
00092         if (squareWavePosition < SINE_SEGMENT_RELATIVE_LENGTH) {
00093                 phase = POSITIVE_RISING_SINE_SEGMENT;
00094                 return;
00095         }
00096         squareWavePosition -= SINE_SEGMENT_RELATIVE_LENGTH;
00097         if (squareWavePosition < highLinearLength) {
00098                 phase = POSITIVE_LINEAR_SEGMENT;
00099                 return;
00100         }
00101         squareWavePosition -= highLinearLength;
00102         if (squareWavePosition < SINE_SEGMENT_RELATIVE_LENGTH) {
00103                 phase = POSITIVE_FALLING_SINE_SEGMENT;
00104                 return;
00105         }
00106         squareWavePosition -= SINE_SEGMENT_RELATIVE_LENGTH;
00107         resonanceSinePosition = squareWavePosition;
00108         if (squareWavePosition < SINE_SEGMENT_RELATIVE_LENGTH) {
00109                 phase = NEGATIVE_FALLING_SINE_SEGMENT;
00110                 return;
00111         }
00112         squareWavePosition -= SINE_SEGMENT_RELATIVE_LENGTH;
00113         if (squareWavePosition < lowLinearLength) {
00114                 phase = NEGATIVE_LINEAR_SEGMENT;
00115                 return;
00116         }
00117         squareWavePosition -= lowLinearLength;
00118         phase = NEGATIVE_RISING_SINE_SEGMENT;
00119 }
00120 
00121 void LA32WaveGenerator::advancePosition() {
00122         wavePosition += getSampleStep();
00123         wavePosition %= 4 * SINE_SEGMENT_RELATIVE_LENGTH;
00124 
00125         Bit32u effectiveCutoffValue = (cutoffVal > MIDDLE_CUTOFF_VALUE) ? (cutoffVal - MIDDLE_CUTOFF_VALUE) >> 10 : 0;
00126         Bit32u resonanceWaveLengthFactor = getResonanceWaveLengthFactor(effectiveCutoffValue);
00127         Bit32u highLinearLength = getHighLinearLength(effectiveCutoffValue);
00128         Bit32u lowLinearLength = (resonanceWaveLengthFactor << 8) - 4 * SINE_SEGMENT_RELATIVE_LENGTH - highLinearLength;
00129         computePositions(highLinearLength, lowLinearLength, resonanceWaveLengthFactor);
00130 
00131         // resonancePhase computation hack
00132         *(int*)&resonancePhase = ((resonanceSinePosition >> 18) + (phase > POSITIVE_FALLING_SINE_SEGMENT ? 2 : 0)) & 3;
00133 }
00134 
00135 void LA32WaveGenerator::generateNextSquareWaveLogSample() {
00136         Bit32u logSampleValue;
00137         switch (phase) {
00138                 case POSITIVE_RISING_SINE_SEGMENT:
00139                 case NEGATIVE_FALLING_SINE_SEGMENT:
00140                         logSampleValue = Tables::getInstance().logsin9[(squareWavePosition >> 9) & 511];
00141                         break;
00142                 case POSITIVE_FALLING_SINE_SEGMENT:
00143                 case NEGATIVE_RISING_SINE_SEGMENT:
00144                         logSampleValue = Tables::getInstance().logsin9[~(squareWavePosition >> 9) & 511];
00145                         break;
00146                 case POSITIVE_LINEAR_SEGMENT:
00147                 case NEGATIVE_LINEAR_SEGMENT:
00148                 default:
00149                         logSampleValue = 0;
00150                         break;
00151         }
00152         logSampleValue <<= 2;
00153         logSampleValue += amp >> 10;
00154         if (cutoffVal < MIDDLE_CUTOFF_VALUE) {
00155                 logSampleValue += (MIDDLE_CUTOFF_VALUE - cutoffVal) >> 9;
00156         }
00157 
00158         squareLogSample.logValue = logSampleValue < 65536 ? (Bit16u)logSampleValue : 65535;
00159         squareLogSample.sign = phase < NEGATIVE_FALLING_SINE_SEGMENT ? LogSample::POSITIVE : LogSample::NEGATIVE;
00160 }
00161 
00162 void LA32WaveGenerator::generateNextResonanceWaveLogSample() {
00163         Bit32u logSampleValue;
00164         if (resonancePhase == POSITIVE_FALLING_RESONANCE_SINE_SEGMENT || resonancePhase == NEGATIVE_RISING_RESONANCE_SINE_SEGMENT) {
00165                 logSampleValue = Tables::getInstance().logsin9[~(resonanceSinePosition >> 9) & 511];
00166         } else {
00167                 logSampleValue = Tables::getInstance().logsin9[(resonanceSinePosition >> 9) & 511];
00168         }
00169         logSampleValue <<= 2;
00170         logSampleValue += amp >> 10;
00171 
00172         // From the digital captures, the decaying speed of the resonance sine is found a bit different for the positive and the negative segments
00173         Bit32u decayFactor = phase < NEGATIVE_FALLING_SINE_SEGMENT ? resAmpDecayFactor : resAmpDecayFactor + 1;
00174         // Unsure about resonanceSinePosition here. It's possible that dedicated counter & decrement are used. Although, cutoff is finely ramped, so maybe not.
00175         logSampleValue += resonanceAmpSubtraction + (((resonanceSinePosition >> 4) * decayFactor) >> 8);
00176 
00177         // To ensure the output wave has no breaks, two different windows are appied to the beginning and the ending of the resonance sine segment
00178         if (phase == POSITIVE_RISING_SINE_SEGMENT || phase == NEGATIVE_FALLING_SINE_SEGMENT) {
00179                 // The window is synchronous sine here
00180                 logSampleValue += Tables::getInstance().logsin9[(squareWavePosition >> 9) & 511] << 2;
00181         } else if (phase == POSITIVE_FALLING_SINE_SEGMENT || phase == NEGATIVE_RISING_SINE_SEGMENT) {
00182                 // The window is synchronous square sine here
00183                 logSampleValue += Tables::getInstance().logsin9[~(squareWavePosition >> 9) & 511] << 3;
00184         }
00185 
00186         if (cutoffVal < MIDDLE_CUTOFF_VALUE) {
00187                 // For the cutoff values below the cutoff middle point, it seems the amp of the resonance wave is expotentially decayed
00188                 logSampleValue += 31743 + ((MIDDLE_CUTOFF_VALUE - cutoffVal) >> 9);
00189         } else if (cutoffVal < RESONANCE_DECAY_THRESHOLD_CUTOFF_VALUE) {
00190                 // For the cutoff values below this point, the amp of the resonance wave is sinusoidally decayed
00191                 Bit32u sineIx = (cutoffVal - MIDDLE_CUTOFF_VALUE) >> 13;
00192                 logSampleValue += Tables::getInstance().logsin9[sineIx] << 2;
00193         }
00194 
00195         // After all the amp decrements are added, it should be safe now to adjust the amp of the resonance wave to what we see on captures
00196         logSampleValue -= 1 << 12;
00197 
00198         resonanceLogSample.logValue = logSampleValue < 65536 ? (Bit16u)logSampleValue : 65535;
00199         resonanceLogSample.sign = resonancePhase < NEGATIVE_FALLING_RESONANCE_SINE_SEGMENT ? LogSample::POSITIVE : LogSample::NEGATIVE;
00200 }
00201 
00202 void LA32WaveGenerator::generateNextSawtoothCosineLogSample(LogSample &logSample) const {
00203         Bit32u sawtoothCosinePosition = wavePosition + (1 << 18);
00204         if ((sawtoothCosinePosition & (1 << 18)) > 0) {
00205                 logSample.logValue = Tables::getInstance().logsin9[~(sawtoothCosinePosition >> 9) & 511];
00206         } else {
00207                 logSample.logValue = Tables::getInstance().logsin9[(sawtoothCosinePosition >> 9) & 511];
00208         }
00209         logSample.logValue <<= 2;
00210         logSample.sign = ((sawtoothCosinePosition & (1 << 19)) == 0) ? LogSample::POSITIVE : LogSample::NEGATIVE;
00211 }
00212 
00213 void LA32WaveGenerator::pcmSampleToLogSample(LogSample &logSample, const Bit16s pcmSample) const {
00214         Bit32u logSampleValue = (32787 - (pcmSample & 32767)) << 1;
00215         logSampleValue += amp >> 10;
00216         logSample.logValue = logSampleValue < 65536 ? (Bit16u)logSampleValue : 65535;
00217         logSample.sign = pcmSample < 0 ? LogSample::NEGATIVE : LogSample::POSITIVE;
00218 }
00219 
00220 void LA32WaveGenerator::generateNextPCMWaveLogSamples() {
00221         // This should emulate the ladder we see in the PCM captures for pitches 01, 02, 07, etc.
00222         // The most probable cause is the factor in the interpolation formula is one bit less
00223         // accurate than the sample position counter
00224         pcmInterpolationFactor = (wavePosition & 255) >> 1;
00225         Bit32u pcmWaveTableIx = wavePosition >> 8;
00226         pcmSampleToLogSample(firstPCMLogSample, pcmWaveAddress[pcmWaveTableIx]);
00227         if (pcmWaveInterpolated) {
00228                 pcmWaveTableIx++;
00229                 if (pcmWaveTableIx < pcmWaveLength) {
00230                         pcmSampleToLogSample(secondPCMLogSample, pcmWaveAddress[pcmWaveTableIx]);
00231                 } else {
00232                         if (pcmWaveLooped) {
00233                                 pcmWaveTableIx -= pcmWaveLength;
00234                                 pcmSampleToLogSample(secondPCMLogSample, pcmWaveAddress[pcmWaveTableIx]);
00235                         } else {
00236                                 secondPCMLogSample = SILENCE;
00237                         }
00238                 }
00239         } else {
00240                 secondPCMLogSample = SILENCE;
00241         }
00242         // pcmSampleStep = (Bit32u)EXP2F(pitch / 4096.0f + 3.0f);
00243         Bit32u pcmSampleStep = LA32Utilites::interpolateExp(~pitch & 4095);
00244         pcmSampleStep <<= pitch >> 12;
00245         // Seeing the actual lengths of the PCM wave for pitches 00..12,
00246         // the pcmPosition counter can be assumed to have 8-bit fractions
00247         pcmSampleStep >>= 9;
00248         wavePosition += pcmSampleStep;
00249         if (wavePosition >= (pcmWaveLength << 8)) {
00250                 if (pcmWaveLooped) {
00251                         wavePosition -= pcmWaveLength << 8;
00252                 } else {
00253                         deactivate();
00254                 }
00255         }
00256 }
00257 
00258 void LA32WaveGenerator::initSynth(const bool useSawtoothWaveform, const Bit8u usePulseWidth, const Bit8u useResonance) {
00259         sawtoothWaveform = useSawtoothWaveform;
00260         pulseWidth = usePulseWidth;
00261         resonance = useResonance;
00262 
00263         wavePosition = 0;
00264 
00265         squareWavePosition = 0;
00266         phase = POSITIVE_RISING_SINE_SEGMENT;
00267 
00268         resonanceSinePosition = 0;
00269         resonancePhase = POSITIVE_RISING_RESONANCE_SINE_SEGMENT;
00270         resonanceAmpSubtraction = (32 - resonance) << 10;
00271         resAmpDecayFactor = Tables::getInstance().resAmpDecayFactor[resonance >> 2] << 2;
00272 
00273         pcmWaveAddress = NULL;
00274         active = true;
00275 }
00276 
00277 void LA32WaveGenerator::initPCM(const Bit16s * const usePCMWaveAddress, const Bit32u usePCMWaveLength, const bool usePCMWaveLooped, const bool usePCMWaveInterpolated) {
00278         pcmWaveAddress = usePCMWaveAddress;
00279         pcmWaveLength = usePCMWaveLength;
00280         pcmWaveLooped = usePCMWaveLooped;
00281         pcmWaveInterpolated = usePCMWaveInterpolated;
00282 
00283         wavePosition = 0;
00284         active = true;
00285 }
00286 
00287 void LA32WaveGenerator::generateNextSample(const Bit32u useAmp, const Bit16u usePitch, const Bit32u useCutoffVal) {
00288         if (!active) {
00289                 return;
00290         }
00291 
00292         amp = useAmp;
00293         pitch = usePitch;
00294 
00295         if (isPCMWave()) {
00296                 generateNextPCMWaveLogSamples();
00297                 return;
00298         }
00299 
00300         // The 240 cutoffVal limit was determined via sample analysis (internal Munt capture IDs: glop3, glop4).
00301         // More research is needed to be sure that this is correct, however.
00302         cutoffVal = (useCutoffVal > MAX_CUTOFF_VALUE) ? MAX_CUTOFF_VALUE : useCutoffVal;
00303 
00304         generateNextSquareWaveLogSample();
00305         generateNextResonanceWaveLogSample();
00306         if (sawtoothWaveform) {
00307                 LogSample cosineLogSample;
00308                 generateNextSawtoothCosineLogSample(cosineLogSample);
00309                 LA32Utilites::addLogSamples(squareLogSample, cosineLogSample);
00310                 LA32Utilites::addLogSamples(resonanceLogSample, cosineLogSample);
00311         }
00312         advancePosition();
00313 }
00314 
00315 LogSample LA32WaveGenerator::getOutputLogSample(const bool first) const {
00316         if (!isActive()) {
00317                 return SILENCE;
00318         }
00319         if (isPCMWave()) {
00320                 return first ? firstPCMLogSample : secondPCMLogSample;
00321         }
00322         return first ? squareLogSample : resonanceLogSample;
00323 }
00324 
00325 void LA32WaveGenerator::deactivate() {
00326         active = false;
00327 }
00328 
00329 bool LA32WaveGenerator::isActive() const {
00330         return active;
00331 }
00332 
00333 bool LA32WaveGenerator::isPCMWave() const {
00334         return pcmWaveAddress != NULL;
00335 }
00336 
00337 Bit32u LA32WaveGenerator::getPCMInterpolationFactor() const {
00338         return pcmInterpolationFactor;
00339 }
00340 
00341 void LA32PartialPair::init(const bool useRingModulated, const bool useMixed) {
00342         ringModulated = useRingModulated;
00343         mixed = useMixed;
00344 }
00345 
00346 void LA32PartialPair::initSynth(const PairType useMaster, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance) {
00347         if (useMaster == MASTER) {
00348                 master.initSynth(sawtoothWaveform, pulseWidth, resonance);
00349         } else {
00350                 slave.initSynth(sawtoothWaveform, pulseWidth, resonance);
00351         }
00352 }
00353 
00354 void LA32PartialPair::initPCM(const PairType useMaster, const Bit16s *pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped) {
00355         if (useMaster == MASTER) {
00356                 master.initPCM(pcmWaveAddress, pcmWaveLength, pcmWaveLooped, true);
00357         } else {
00358                 slave.initPCM(pcmWaveAddress, pcmWaveLength, pcmWaveLooped, !ringModulated);
00359         }
00360 }
00361 
00362 void LA32PartialPair::generateNextSample(const PairType useMaster, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff) {
00363         if (useMaster == MASTER) {
00364                 master.generateNextSample(amp, pitch, cutoff);
00365         } else {
00366                 slave.generateNextSample(amp, pitch, cutoff);
00367         }
00368 }
00369 
00370 Bit16s LA32PartialPair::unlogAndMixWGOutput(const LA32WaveGenerator &wg, const LogSample * const ringModulatingLogSample) {
00371         if (!wg.isActive() || ((ringModulatingLogSample != NULL) && (ringModulatingLogSample->logValue == SILENCE.logValue))) {
00372                 return 0;
00373         }
00374         LogSample firstLogSample = wg.getOutputLogSample(true);
00375         LogSample secondLogSample = wg.getOutputLogSample(false);
00376         if (ringModulatingLogSample != NULL) {
00377                 LA32Utilites::addLogSamples(firstLogSample, *ringModulatingLogSample);
00378                 LA32Utilites::addLogSamples(secondLogSample, *ringModulatingLogSample);
00379         }
00380         Bit16s firstSample = LA32Utilites::unlog(firstLogSample);
00381         Bit16s secondSample = LA32Utilites::unlog(secondLogSample);
00382         if (wg.isPCMWave()) {
00383                 return Bit16s(firstSample + ((Bit32s(secondSample - firstSample) * wg.getPCMInterpolationFactor()) >> 7));
00384         }
00385         return firstSample + secondSample;
00386 }
00387 
00388 Bit16s LA32PartialPair::nextOutSample() {
00389         if (ringModulated) {
00390                 LogSample slaveFirstLogSample = slave.getOutputLogSample(true);
00391                 LogSample slaveSecondLogSample = slave.getOutputLogSample(false);
00392                 Bit16s sample = unlogAndMixWGOutput(master, &slaveFirstLogSample);
00393                 if (!slave.isPCMWave()) {
00394                         sample += unlogAndMixWGOutput(master, &slaveSecondLogSample);
00395                 }
00396                 if (mixed) {
00397                         sample += unlogAndMixWGOutput(master, NULL);
00398                 }
00399                 return sample;
00400         }
00401         return unlogAndMixWGOutput(master, NULL) + unlogAndMixWGOutput(slave, NULL);
00402 }
00403 
00404 void LA32PartialPair::deactivate(const PairType useMaster) {
00405         if (useMaster == MASTER) {
00406                 master.deactivate();
00407         } else {
00408                 slave.deactivate();
00409         }
00410 }
00411 
00412 bool LA32PartialPair::isActive(const PairType useMaster) const {
00413         return useMaster == MASTER ? master.isActive() : slave.isActive();
00414 }
00415 
00416 }
00417 
00418 #endif // #if MT32EMU_ACCURATE_WG == 0