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 00020 #include "mt32emu.h" 00021 #include "mmath.h" 00022 00023 namespace MT32Emu { 00024 00025 // Note that when entering nextPhase(), newPhase is set to phase + 1, and the descriptions/names below refer to 00026 // newPhase's value. 00027 enum { 00028 // When this is the target phase, level[0] is targeted within time[0] 00029 // Note that this phase is always set up in reset(), not nextPhase() 00030 PHASE_ATTACK = 1, 00031 00032 // When this is the target phase, level[1] is targeted within time[1] 00033 PHASE_2 = 2, 00034 00035 // When this is the target phase, level[2] is targeted within time[2] 00036 PHASE_3 = 3, 00037 00038 // When this is the target phase, level[3] is targeted within time[3] 00039 PHASE_4 = 4, 00040 00041 // When this is the target phase, immediately goes to PHASE_RELEASE unless the poly is set to sustain. 00042 // Otherwise level[3] is continued with increment 0 - no phase change will occur until some external influence (like pedal release) 00043 PHASE_SUSTAIN = 5, 00044 00045 // 0 is targeted within time[4] (the time calculation is quite different from the other phases) 00046 PHASE_RELEASE = 6, 00047 00048 // 0 is targeted with increment 0 (thus theoretically staying that way forever) 00049 PHASE_DONE = 7 00050 }; 00051 00052 static int calcBaseCutoff(const TimbreParam::PartialParam *partialParam, Bit32u basePitch, unsigned int key) { 00053 // This table matches the values used by a real LAPC-I. 00054 static const Bit8s biasLevelToBiasMult[] = {85, 42, 21, 16, 10, 5, 2, 0, -2, -5, -10, -16, -21, -74, -85}; 00055 // These values represent unique options with no consistent pattern, so we have to use something like a table in any case. 00056 // The table entries, when divided by 21, match approximately what the manual claims: 00057 // -1, -1/2, -1/4, 0, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, 1, 5/4, 3/2, 2, s1, s2 00058 // Note that the entry for 1/8 is rounded to 2 (from 1/8 * 21 = 2.625), which seems strangely inaccurate compared to the others. 00059 static const Bit8s keyfollowMult21[] = {-21, -10, -5, 0, 2, 5, 8, 10, 13, 16, 18, 21, 26, 32, 42, 21, 21}; 00060 int baseCutoff = keyfollowMult21[partialParam->tvf.keyfollow] - keyfollowMult21[partialParam->wg.pitchKeyfollow]; 00061 // baseCutoff range now: -63 to 63 00062 baseCutoff *= (int)key - 60; 00063 // baseCutoff range now: -3024 to 3024 00064 int biasPoint = partialParam->tvf.biasPoint; 00065 if ((biasPoint & 0x40) == 0) { 00066 // biasPoint range here: 0 to 63 00067 int bias = biasPoint + 33 - key; // bias range here: -75 to 84 00068 if (bias > 0) { 00069 bias = -bias; // bias range here: -1 to -84 00070 baseCutoff += bias * biasLevelToBiasMult[partialParam->tvf.biasLevel]; // Calculation range: -7140 to 7140 00071 // baseCutoff range now: -10164 to 10164 00072 } 00073 } else { 00074 // biasPoint range here: 64 to 127 00075 int bias = biasPoint - 31 - key; // bias range here: -75 to 84 00076 if (bias < 0) { 00077 baseCutoff += bias * biasLevelToBiasMult[partialParam->tvf.biasLevel]; // Calculation range: -6375 to 6375 00078 // baseCutoff range now: -9399 to 9399 00079 } 00080 } 00081 // baseCutoff range now: -10164 to 10164 00082 baseCutoff += ((partialParam->tvf.cutoff << 4) - 800); 00083 // baseCutoff range now: -10964 to 10964 00084 if (baseCutoff >= 0) { 00085 // FIXME: Potentially bad if baseCutoff ends up below -2056? 00086 int pitchDeltaThing = (basePitch >> 4) + baseCutoff - 3584; 00087 if (pitchDeltaThing > 0) { 00088 baseCutoff -= pitchDeltaThing; 00089 } 00090 } else if (baseCutoff < -2048) { 00091 baseCutoff = -2048; 00092 } 00093 baseCutoff += 2056; 00094 baseCutoff >>= 4; // PORTABILITY NOTE: Hmm... Depends whether it could've been below -2056, but maybe arithmetic shift assumed? 00095 if (baseCutoff > 255) { 00096 baseCutoff = 255; 00097 } 00098 return (Bit8u)baseCutoff; 00099 } 00100 00101 TVF::TVF(const Partial *usePartial, LA32Ramp *useCutoffModifierRamp) : 00102 partial(usePartial), cutoffModifierRamp(useCutoffModifierRamp) { 00103 00104 00105 // init ptr warnings (load state crashes) 00106 partialParam = NULL; 00107 } 00108 00109 void TVF::startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase) { 00110 target = newTarget; 00111 phase = newPhase; 00112 cutoffModifierRamp->startRamp(newTarget, newIncrement); 00113 #if MT32EMU_MONITOR_TVF >= 1 00114 partial->getSynth()->printDebug("[+%lu] [Partial %d] TVF,ramp,%d,%d,%d,%d", partial->debugGetSampleNum(), partial->debugGetPartialNum(), newTarget, (newIncrement & 0x80) ? -1 : 1, (newIncrement & 0x7F), newPhase); 00115 #endif 00116 } 00117 00118 void TVF::reset(const TimbreParam::PartialParam *newPartialParam, unsigned int basePitch) { 00119 partialParam = newPartialParam; 00120 00121 unsigned int key = partial->getPoly()->getKey(); 00122 unsigned int velocity = partial->getPoly()->getVelocity(); 00123 00124 const Tables *tables = &Tables::getInstance(); 00125 00126 baseCutoff = calcBaseCutoff(newPartialParam, basePitch, key); 00127 #if MT32EMU_MONITOR_TVF >= 1 00128 partial->getSynth()->printDebug("[+%lu] [Partial %d] TVF,base,%d", partial->debugGetSampleNum(), partial->debugGetPartialNum(), baseCutoff); 00129 #endif 00130 00131 int newLevelMult = velocity * newPartialParam->tvf.envVeloSensitivity; 00132 newLevelMult >>= 6; 00133 newLevelMult += 109 - newPartialParam->tvf.envVeloSensitivity; 00134 newLevelMult += ((signed)key - 60) >> (4 - newPartialParam->tvf.envDepthKeyfollow); 00135 if (newLevelMult < 0) { 00136 newLevelMult = 0; 00137 } 00138 newLevelMult *= newPartialParam->tvf.envDepth; 00139 newLevelMult >>= 6; 00140 if (newLevelMult > 255) { 00141 newLevelMult = 255; 00142 } 00143 levelMult = newLevelMult; 00144 00145 if (newPartialParam->tvf.envTimeKeyfollow != 0) { 00146 keyTimeSubtraction = ((signed)key - 60) >> (5 - newPartialParam->tvf.envTimeKeyfollow); 00147 } else { 00148 keyTimeSubtraction = 0; 00149 } 00150 00151 int newTarget = (newLevelMult * newPartialParam->tvf.envLevel[0]) >> 8; 00152 int envTimeSetting = newPartialParam->tvf.envTime[0] - keyTimeSubtraction; 00153 int newIncrement; 00154 if (envTimeSetting <= 0) { 00155 newIncrement = (0x80 | 127); 00156 } else { 00157 newIncrement = tables->envLogarithmicTime[newTarget] - envTimeSetting; 00158 if (newIncrement <= 0) { 00159 newIncrement = 1; 00160 } 00161 } 00162 cutoffModifierRamp->reset(); 00163 startRamp(newTarget, newIncrement, PHASE_2 - 1); 00164 } 00165 00166 Bit8u TVF::getBaseCutoff() const { 00167 return baseCutoff; 00168 } 00169 00170 void TVF::handleInterrupt() { 00171 nextPhase(); 00172 } 00173 00174 void TVF::startDecay() { 00175 if (phase >= PHASE_RELEASE) { 00176 return; 00177 } 00178 if (partialParam->tvf.envTime[4] == 0) { 00179 startRamp(0, 1, PHASE_DONE - 1); 00180 } else { 00181 startRamp(0, -partialParam->tvf.envTime[4], PHASE_DONE - 1); 00182 } 00183 } 00184 00185 void TVF::nextPhase() { 00186 const Tables *tables = &Tables::getInstance(); 00187 int newPhase = phase + 1; 00188 00189 switch (newPhase) { 00190 case PHASE_DONE: 00191 startRamp(0, 0, newPhase); 00192 return; 00193 case PHASE_SUSTAIN: 00194 case PHASE_RELEASE: 00195 // FIXME: Afaict newPhase should never be PHASE_RELEASE here. And if it were, this is an odd way to handle it. 00196 if (!partial->getPoly()->canSustain()) { 00197 phase = newPhase; // FIXME: Correct? 00198 startDecay(); // FIXME: This should actually start decay even if phase is already 6. Does that matter? 00199 return; 00200 } 00201 startRamp((levelMult * partialParam->tvf.envLevel[3]) >> 8, 0, newPhase); 00202 return; 00203 } 00204 00205 int envPointIndex = phase; 00206 int envTimeSetting = partialParam->tvf.envTime[envPointIndex] - keyTimeSubtraction; 00207 00208 int newTarget = (levelMult * partialParam->tvf.envLevel[envPointIndex]) >> 8; 00209 int newIncrement; 00210 if (envTimeSetting > 0) { 00211 int targetDelta = newTarget - target; 00212 if (targetDelta == 0) { 00213 if (newTarget == 0) { 00214 targetDelta = 1; 00215 newTarget = 1; 00216 } else { 00217 targetDelta = -1; 00218 newTarget--; 00219 } 00220 } 00221 newIncrement = tables->envLogarithmicTime[targetDelta < 0 ? -targetDelta : targetDelta] - envTimeSetting; 00222 if (newIncrement <= 0) { 00223 newIncrement = 1; 00224 } 00225 if (targetDelta < 0) { 00226 newIncrement |= 0x80; 00227 } 00228 } else { 00229 newIncrement = newTarget >= target ? (0x80 | 127) : 127; 00230 } 00231 startRamp(newTarget, newIncrement, newPhase); 00232 } 00233 00234 00235 #ifdef WIN32_DEBUG 00236 void TVF::rawVerifyState( char *name, Synth *useSynth ) 00237 { 00238 TVF *ptr1, *ptr2; 00239 TVF tvf_temp(partial,cutoffModifierRamp); 00240 00241 00242 #ifndef WIN32_DUMP 00243 return; 00244 #endif 00245 00246 ptr1 = this; 00247 ptr2 = &tvf_temp; 00248 useSynth->rawLoadState( name, ptr2, sizeof(*this) ); 00249 00250 00251 if( ptr1->partial != ptr2->partial ) __asm int 3 00252 if( ptr1->cutoffModifierRamp != ptr2->cutoffModifierRamp ) __asm int 3 00253 if( ptr1->partialParam != ptr2->partialParam ) __asm int 3 00254 if( ptr1->baseCutoff != ptr2->baseCutoff ) __asm int 3 00255 if( ptr1->keyTimeSubtraction != ptr2->keyTimeSubtraction ) __asm int 3 00256 if( ptr1->levelMult != ptr2->levelMult ) __asm int 3 00257 if( ptr1->target != ptr2->target ) __asm int 3 00258 if( ptr1->phase != ptr2->phase ) __asm int 3 00259 00260 00261 00262 // avoid destructor problems 00263 memset( ptr2, 0, sizeof(*ptr2) ); 00264 } 00265 #endif 00266 00267 00268 void TVF::saveState( std::ostream &stream ) 00269 { 00270 Bit16u partialParam_idx1, partialParam_idx2; 00271 00272 // - static fastptr 00273 //const Partial * const partial; 00274 //LA32Ramp *cutoffModifierRamp; 00275 00276 00277 // - reloc fastptr (!!) 00278 //const TimbreParam::PartialParam *partialParam; 00279 partial->getSynth()->findPartialParam( partialParam, &partialParam_idx1, &partialParam_idx2 ); 00280 00281 stream.write(reinterpret_cast<const char*>(&partialParam_idx1), sizeof(partialParam_idx1) ); 00282 stream.write(reinterpret_cast<const char*>(&partialParam_idx2), sizeof(partialParam_idx2) ); 00283 00284 00285 stream.write(reinterpret_cast<const char*>(&baseCutoff), sizeof(baseCutoff) ); 00286 stream.write(reinterpret_cast<const char*>(&keyTimeSubtraction), sizeof(keyTimeSubtraction) ); 00287 stream.write(reinterpret_cast<const char*>(&levelMult), sizeof(levelMult) ); 00288 stream.write(reinterpret_cast<const char*>(&target), sizeof(target) ); 00289 stream.write(reinterpret_cast<const char*>(&phase), sizeof(phase) ); 00290 00291 00292 #ifdef WIN32_DEBUG 00293 // DEBUG 00294 partial->getSynth()->rawDumpState( "temp-save", this, sizeof(*this) ); 00295 partial->getSynth()->rawDumpNo++; 00296 #endif 00297 } 00298 00299 00300 void TVF::loadState( std::istream &stream ) 00301 { 00302 Bit16u partialParam_idx1, partialParam_idx2; 00303 00304 // - static fastptr 00305 //const Partial * const partial; 00306 //LA32Ramp *cutoffModifierRamp; 00307 00308 00309 // - reloc fastptr (!!) 00310 //const TimbreParam::PartialParam *partialParam; 00311 stream.read(reinterpret_cast<char*>(&partialParam_idx1), sizeof(partialParam_idx1) ); 00312 stream.read(reinterpret_cast<char*>(&partialParam_idx2), sizeof(partialParam_idx2) ); 00313 partialParam = partial->getSynth()->indexPartialParam(partialParam_idx1, partialParam_idx2); 00314 00315 00316 stream.read(reinterpret_cast<char*>(&baseCutoff), sizeof(baseCutoff) ); 00317 stream.read(reinterpret_cast<char*>(&keyTimeSubtraction), sizeof(keyTimeSubtraction) ); 00318 stream.read(reinterpret_cast<char*>(&levelMult), sizeof(levelMult) ); 00319 stream.read(reinterpret_cast<char*>(&target), sizeof(target) ); 00320 stream.read(reinterpret_cast<char*>(&phase), sizeof(phase) ); 00321 00322 00323 #ifdef WIN32_DEBUG 00324 // DEBUG 00325 partial->getSynth()->rawDumpState( "temp-load", this, sizeof(*this) ); 00326 this->rawVerifyState( "temp-save", partial->getSynth() ); 00327 partial->getSynth()->rawDumpNo++; 00328 #endif 00329 } 00330 00331 }