DOSBox-X
|
00001 /* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher 00002 * Copyright (C) 2011, 2012, 2013 Dean Beeler, Jerome Fisher, Sergey V. Mikayev 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU Lesser General Public License as published by 00006 * the Free Software Foundation, either version 2.1 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU Lesser General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU Lesser General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00016 */ 00017 00018 #include <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