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 /* 00019 * This class emulates the calculations performed by the 8095 microcontroller in order to configure the LA-32's amplitude ramp for a single partial at each stage of its TVA envelope. 00020 * Unless we introduced bugs, it should be pretty much 100% accurate according to Mok's specifications. 00021 */ 00022 #include <cmath> 00023 00024 #include "mt32emu.h" 00025 #include "mmath.h" 00026 #include "PartialManager.h" 00027 00028 namespace MT32Emu { 00029 00030 // CONFIRMED: Matches a table in ROM - haven't got around to coming up with a formula for it yet. 00031 static Bit8u biasLevelToAmpSubtractionCoeff[13] = {255, 187, 137, 100, 74, 54, 40, 29, 21, 15, 10, 5, 0}; 00032 00033 TVA::TVA(const Partial *usePartial, LA32Ramp *useAmpRamp) : 00034 partial(usePartial), ampRamp(useAmpRamp), system(&usePartial->getSynth()->mt32ram.system), phase(TVA_PHASE_DEAD) { 00035 00036 00037 // init ptr warnings (load state crashes) 00038 part = NULL; 00039 partialParam = NULL; 00040 patchTemp = NULL; 00041 rhythmTemp = NULL; 00042 } 00043 00044 void TVA::startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase) { 00045 if (newPhase != phase) { 00046 partial->getSynth()->partialStateChanged(partial, phase, newPhase); 00047 } 00048 target = newTarget; 00049 phase = newPhase; 00050 ampRamp->startRamp(newTarget, newIncrement); 00051 #if MT32EMU_MONITOR_TVA >= 1 00052 partial->getSynth()->printDebug("[+%lu] [Partial %d] TVA,ramp,%d,%d,%d,%d", partial->debugGetSampleNum(), partial->debugGetPartialNum(), (newIncrement & 0x80) ? -1 : 1, (newIncrement & 0x7F), newPhase); 00053 #endif 00054 } 00055 00056 void TVA::end(int newPhase) { 00057 if (newPhase != phase) { 00058 partial->getSynth()->partialStateChanged(partial, phase, newPhase); 00059 } 00060 phase = newPhase; 00061 playing = false; 00062 #if MT32EMU_MONITOR_TVA >= 1 00063 partial->getSynth()->printDebug("[+%lu] [Partial %d] TVA,end,%d", partial->debugGetSampleNum(), partial->debugGetPartialNum(), newPhase); 00064 #endif 00065 } 00066 00067 static int multBias(Bit8u biasLevel, int bias) { 00068 return (bias * biasLevelToAmpSubtractionCoeff[biasLevel]) >> 5; 00069 } 00070 00071 static int calcBiasAmpSubtraction(Bit8u biasPoint, Bit8u biasLevel, int key) { 00072 if ((biasPoint & 0x40) == 0) { 00073 int bias = biasPoint + 33 - key; 00074 if (bias > 0) { 00075 return multBias(biasLevel, bias); 00076 } 00077 } else { 00078 int bias = biasPoint - 31 - key; 00079 if (bias < 0) { 00080 bias = -bias; 00081 return multBias(biasLevel, bias); 00082 } 00083 } 00084 return 0; 00085 } 00086 00087 static int calcBiasAmpSubtractions(const TimbreParam::PartialParam *partialParam, int key) { 00088 int biasAmpSubtraction1 = calcBiasAmpSubtraction(partialParam->tva.biasPoint1, partialParam->tva.biasLevel1, key); 00089 if (biasAmpSubtraction1 > 255) { 00090 return 255; 00091 } 00092 int biasAmpSubtraction2 = calcBiasAmpSubtraction(partialParam->tva.biasPoint2, partialParam->tva.biasLevel2, key); 00093 if (biasAmpSubtraction2 > 255) { 00094 return 255; 00095 } 00096 int biasAmpSubtraction = biasAmpSubtraction1 + biasAmpSubtraction2; 00097 if (biasAmpSubtraction > 255) { 00098 return 255; 00099 } 00100 return biasAmpSubtraction; 00101 } 00102 00103 static int calcVeloAmpSubtraction(Bit8u veloSensitivity, unsigned int velocity) { 00104 // FIXME:KG: Better variable names 00105 int velocityMult = veloSensitivity - 50; 00106 int absVelocityMult = velocityMult < 0 ? -velocityMult : velocityMult; 00107 velocityMult = (signed)((unsigned)(velocityMult * ((signed)velocity - 64)) << 2); 00108 return absVelocityMult - (velocityMult >> 8); // PORTABILITY NOTE: Assumes arithmetic shift 00109 } 00110 00111 static int calcBasicAmp(const Tables *tables, const Partial *partial, const MemParams::System *system, const TimbreParam::PartialParam *partialParam, const MemParams::PatchTemp *patchTemp, const MemParams::RhythmTemp *rhythmTemp, int biasAmpSubtraction, int veloAmpSubtraction, Bit8u expression) { 00112 int amp = 155; 00113 00114 if (!partial->isRingModulatingSlave()) { 00115 amp -= tables->masterVolToAmpSubtraction[system->masterVol]; 00116 if (amp < 0) { 00117 return 0; 00118 } 00119 amp -= tables->levelToAmpSubtraction[patchTemp->outputLevel]; 00120 if (amp < 0) { 00121 return 0; 00122 } 00123 amp -= tables->levelToAmpSubtraction[expression]; 00124 if (amp < 0) { 00125 return 0; 00126 } 00127 if (rhythmTemp != NULL) { 00128 amp -= tables->levelToAmpSubtraction[rhythmTemp->outputLevel]; 00129 if (amp < 0) { 00130 return 0; 00131 } 00132 } 00133 } 00134 amp -= biasAmpSubtraction; 00135 if (amp < 0) { 00136 return 0; 00137 } 00138 amp -= tables->levelToAmpSubtraction[partialParam->tva.level]; 00139 if (amp < 0) { 00140 return 0; 00141 } 00142 amp -= veloAmpSubtraction; 00143 if (amp < 0) { 00144 return 0; 00145 } 00146 if (amp > 155) { 00147 amp = 155; 00148 } 00149 amp -= partialParam->tvf.resonance >> 1; 00150 if (amp < 0) { 00151 return 0; 00152 } 00153 return amp; 00154 } 00155 00156 int calcKeyTimeSubtraction(Bit8u envTimeKeyfollow, int key) { 00157 if (envTimeKeyfollow == 0) { 00158 return 0; 00159 } 00160 return (key - 60) >> (5 - envTimeKeyfollow); // PORTABILITY NOTE: Assumes arithmetic shift 00161 } 00162 00163 void TVA::reset(const Part *newPart, const TimbreParam::PartialParam *newPartialParam, const MemParams::RhythmTemp *newRhythmTemp) { 00164 part = newPart; 00165 partialParam = newPartialParam; 00166 patchTemp = newPart->getPatchTemp(); 00167 rhythmTemp = newRhythmTemp; 00168 00169 playing = true; 00170 00171 const Tables *tables = &Tables::getInstance(); 00172 00173 int key = partial->getPoly()->getKey(); 00174 int velocity = partial->getPoly()->getVelocity(); 00175 00176 keyTimeSubtraction = calcKeyTimeSubtraction(partialParam->tva.envTimeKeyfollow, key); 00177 00178 biasAmpSubtraction = calcBiasAmpSubtractions(partialParam, key); 00179 veloAmpSubtraction = calcVeloAmpSubtraction(partialParam->tva.veloSensitivity, velocity); 00180 00181 int newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, newRhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression()); 00182 int newPhase; 00183 if (partialParam->tva.envTime[0] == 0) { 00184 // Initially go to the TVA_PHASE_ATTACK target amp, and spend the next phase going from there to the TVA_PHASE_2 target amp 00185 // Note that this means that velocity never affects time for this partial. 00186 newTarget += partialParam->tva.envLevel[0]; 00187 newPhase = TVA_PHASE_ATTACK; // The first target used in nextPhase() will be TVA_PHASE_2 00188 } else { 00189 // Initially go to the base amp determined by TVA level, part volume, etc., and spend the next phase going from there to the full TVA_PHASE_ATTACK target amp. 00190 newPhase = TVA_PHASE_BASIC; // The first target used in nextPhase() will be TVA_PHASE_ATTACK 00191 } 00192 00193 ampRamp->reset();//currentAmp = 0; 00194 00195 // "Go downward as quickly as possible". 00196 // Since the current value is 0, the LA32Ramp will notice that we're already at or below the target and trying to go downward, 00197 // and therefore jump to the target immediately and raise an interrupt. 00198 startRamp((Bit8u)newTarget, 0x80 | 127, newPhase); 00199 } 00200 00201 void TVA::startAbort() { 00202 startRamp(64, 0x80 | 127, TVA_PHASE_RELEASE); 00203 } 00204 00205 void TVA::startDecay() { 00206 if (phase >= TVA_PHASE_RELEASE) { 00207 return; 00208 } 00209 Bit8u newIncrement; 00210 if (partialParam->tva.envTime[4] == 0) { 00211 newIncrement = 1; 00212 } else { 00213 newIncrement = -partialParam->tva.envTime[4]; 00214 } 00215 // The next time nextPhase() is called, it will think TVA_PHASE_RELEASE has finished and the partial will be aborted 00216 startRamp(0, newIncrement, TVA_PHASE_RELEASE); 00217 } 00218 00219 void TVA::handleInterrupt() { 00220 nextPhase(); 00221 } 00222 00223 void TVA::recalcSustain() { 00224 // We get pinged periodically by the pitch code to recalculate our values when in sustain. 00225 // This is done so that the TVA will respond to things like MIDI expression and volume changes while it's sustaining, which it otherwise wouldn't do. 00226 00227 // The check for envLevel[3] == 0 strikes me as slightly dumb. FIXME: Explain why 00228 if (phase != TVA_PHASE_SUSTAIN || partialParam->tva.envLevel[3] == 0) { 00229 return; 00230 } 00231 // We're sustaining. Recalculate all the values 00232 const Tables *tables = &Tables::getInstance(); 00233 int newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression()); 00234 newTarget += partialParam->tva.envLevel[3]; 00235 // Since we're in TVA_PHASE_SUSTAIN at this point, we know that target has been reached and an interrupt fired, so we can rely on it being the current amp. 00236 int targetDelta = newTarget - target; 00237 00238 // Calculate an increment to get to the new amp value in a short, more or less consistent amount of time 00239 Bit8u newIncrement; 00240 if (targetDelta >= 0) { 00241 newIncrement = tables->envLogarithmicTime[(Bit8u)targetDelta] - 2; 00242 } else { 00243 newIncrement = (tables->envLogarithmicTime[(Bit8u)-targetDelta] - 2) | 0x80; 00244 } 00245 // Configure so that once the transition's complete and nextPhase() is called, we'll just re-enter sustain phase (or decay phase, depending on parameters at the time). 00246 startRamp(newTarget, newIncrement, TVA_PHASE_SUSTAIN - 1); 00247 } 00248 00249 bool TVA::isPlaying() const { 00250 return playing; 00251 } 00252 00253 int TVA::getPhase() const { 00254 return phase; 00255 } 00256 00257 void TVA::nextPhase() { 00258 const Tables *tables = &Tables::getInstance(); 00259 00260 if (phase >= TVA_PHASE_DEAD || !playing) { 00261 partial->getSynth()->printDebug("TVA::nextPhase(): Shouldn't have got here with phase %d, playing=%s", phase, playing ? "true" : "false"); 00262 return; 00263 } 00264 int newPhase = phase + 1; 00265 00266 if (newPhase == TVA_PHASE_DEAD) { 00267 end(newPhase); 00268 return; 00269 } 00270 00271 bool allLevelsZeroFromNowOn = false; 00272 if (partialParam->tva.envLevel[3] == 0) { 00273 if (newPhase == TVA_PHASE_4) { 00274 allLevelsZeroFromNowOn = true; 00275 } else if (partialParam->tva.envLevel[2] == 0) { 00276 if (newPhase == TVA_PHASE_3) { 00277 allLevelsZeroFromNowOn = true; 00278 } else if (partialParam->tva.envLevel[1] == 0) { 00279 if (newPhase == TVA_PHASE_2) { 00280 allLevelsZeroFromNowOn = true; 00281 } else if (partialParam->tva.envLevel[0] == 0) { 00282 if (newPhase == TVA_PHASE_ATTACK) { // this line added, missing in ROM - FIXME: Add description of repercussions 00283 allLevelsZeroFromNowOn = true; 00284 } 00285 } 00286 } 00287 } 00288 } 00289 00290 int newTarget; 00291 int newIncrement = 0; // Initialised to please compilers 00292 int envPointIndex = phase; 00293 00294 if (!allLevelsZeroFromNowOn) { 00295 newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression()); 00296 00297 if (newPhase == TVA_PHASE_SUSTAIN || newPhase == TVA_PHASE_RELEASE) { 00298 if (partialParam->tva.envLevel[3] == 0) { 00299 end(newPhase); 00300 return; 00301 } 00302 if (!partial->getPoly()->canSustain()) { 00303 newPhase = TVA_PHASE_RELEASE; 00304 newTarget = 0; 00305 newIncrement = -partialParam->tva.envTime[4]; 00306 if (newIncrement == 0) { 00307 // We can't let the increment be 0, or there would be no emulated interrupt. 00308 // So we do an "upward" increment, which should set the amp to 0 extremely quickly 00309 // and cause an "interrupt" to bring us back to nextPhase(). 00310 newIncrement = 1; 00311 } 00312 } else { 00313 newTarget += partialParam->tva.envLevel[3]; 00314 newIncrement = 0; 00315 } 00316 } else { 00317 newTarget += partialParam->tva.envLevel[envPointIndex]; 00318 } 00319 } else { 00320 newTarget = 0; 00321 } 00322 00323 if ((newPhase != TVA_PHASE_SUSTAIN && newPhase != TVA_PHASE_RELEASE) || allLevelsZeroFromNowOn) { 00324 int envTimeSetting = partialParam->tva.envTime[envPointIndex]; 00325 00326 if (newPhase == TVA_PHASE_ATTACK) { 00327 envTimeSetting -= ((signed)partial->getPoly()->getVelocity() - 64) >> (6 - partialParam->tva.envTimeVeloSensitivity); // PORTABILITY NOTE: Assumes arithmetic shift 00328 00329 if (envTimeSetting <= 0 && partialParam->tva.envTime[envPointIndex] != 0) { 00330 envTimeSetting = 1; 00331 } 00332 } else { 00333 envTimeSetting -= keyTimeSubtraction; 00334 } 00335 if (envTimeSetting > 0) { 00336 int targetDelta = newTarget - target; 00337 if (targetDelta <= 0) { 00338 if (targetDelta == 0) { 00339 // target and newTarget are the same. 00340 // We can't have an increment of 0 or we wouldn't get an emulated interrupt. 00341 // So instead make the target one less than it really should be and set targetDelta accordingly. 00342 targetDelta = -1; 00343 newTarget--; 00344 if (newTarget < 0) { 00345 // Oops, newTarget is less than zero now, so let's do it the other way: 00346 // Make newTarget one more than it really should've been and set targetDelta accordingly. 00347 // FIXME (apparent bug in real firmware): 00348 // This means targetDelta will be positive just below here where it's inverted, and we'll end up using envLogarithmicTime[-1], and we'll be setting newIncrement to be descending later on, etc.. 00349 targetDelta = 1; 00350 newTarget = -newTarget; 00351 } 00352 } 00353 targetDelta = -targetDelta; 00354 newIncrement = tables->envLogarithmicTime[(Bit8u)targetDelta] - envTimeSetting; 00355 if (newIncrement <= 0) { 00356 newIncrement = 1; 00357 } 00358 newIncrement = newIncrement | 0x80; 00359 } else { 00360 // FIXME: The last 22 or so entries in this table are 128 - surely that fucks things up, since that ends up being -128 signed? 00361 newIncrement = tables->envLogarithmicTime[(Bit8u)targetDelta] - envTimeSetting; 00362 if (newIncrement <= 0) { 00363 newIncrement = 1; 00364 } 00365 } 00366 } else { 00367 newIncrement = newTarget >= target ? (0x80 | 127) : 127; 00368 } 00369 00370 // FIXME: What's the point of this? It's checked or set to non-zero everywhere above 00371 if (newIncrement == 0) { 00372 newIncrement = 1; 00373 } 00374 } 00375 00376 startRamp((Bit8u)newTarget, (Bit8u)newIncrement, newPhase); 00377 } 00378 00379 00380 #ifdef WIN32_DEBUG 00381 void TVA::rawVerifyState( char *name, Synth *useSynth ) 00382 { 00383 TVA *ptr1, *ptr2; 00384 TVA tva_temp(partial,ampRamp); 00385 00386 00387 #ifndef WIN32_DUMP 00388 return; 00389 #endif 00390 00391 ptr1 = this; 00392 ptr2 = &tva_temp; 00393 useSynth->rawLoadState( name, ptr2, sizeof(*this) ); 00394 00395 00396 if( ptr1->partial != ptr2->partial ) __asm int 3 00397 if( ptr1->ampRamp != ptr2->ampRamp ) __asm int 3 00398 if( ptr1->system != ptr2->system ) __asm int 3 00399 if( ptr1->part != ptr2->part ) __asm int 3 00400 if( ptr1->partialParam != ptr2->partialParam ) __asm int 3 00401 if( ptr1->patchTemp != ptr2->patchTemp ) __asm int 3 00402 if( ptr1->rhythmTemp != ptr2->rhythmTemp ) __asm int 3 00403 if( ptr1->playing != ptr2->playing ) __asm int 3 00404 if( ptr1->biasAmpSubtraction != ptr2->biasAmpSubtraction ) __asm int 3 00405 if( ptr1->veloAmpSubtraction != ptr2->veloAmpSubtraction ) __asm int 3 00406 if( ptr1->keyTimeSubtraction != ptr2->keyTimeSubtraction ) __asm int 3 00407 if( ptr1->target != ptr2->target ) __asm int 3 00408 if( ptr1->phase != ptr2->phase ) __asm int 3 00409 00410 00411 00412 // avoid destructor problems 00413 memset( ptr2, 0, sizeof(*ptr2) ); 00414 } 00415 #endif 00416 00417 00418 void TVA::saveState( std::ostream &stream ) 00419 { 00420 Bit16u partialParam_idx1, partialParam_idx2; 00421 Bit8u part_idx; 00422 Bit8u patchTemp_idx; 00423 Bit8u rhythmTemp_idx; 00424 00425 00426 // - static fastptr 00427 //const Partial * const partial; 00428 //LA32Ramp *ampRamp; 00429 //const MemParams::System * const system; 00430 00431 00432 // - reloc fastptr (!!) 00433 //const Part *part; 00434 partial->getSynth()->findPart( part, &part_idx ); 00435 stream.write(reinterpret_cast<const char*>(&part_idx), sizeof(part_idx) ); 00436 00437 00438 // - reloc fastptr (!!) 00439 //const TimbreParam::PartialParam *partialParam; 00440 partial->getSynth()->findPartialParam( partialParam, &partialParam_idx1, &partialParam_idx2 ); 00441 stream.write(reinterpret_cast<const char*>(&partialParam_idx1), sizeof(partialParam_idx1) ); 00442 stream.write(reinterpret_cast<const char*>(&partialParam_idx2), sizeof(partialParam_idx2) ); 00443 00444 00445 // - reloc fastptr (!!) 00446 //const MemParams::PatchTemp *patchTemp; 00447 partial->getSynth()->findPatchTemp( patchTemp, &patchTemp_idx ); 00448 stream.write(reinterpret_cast<const char*>(&patchTemp_idx), sizeof(patchTemp_idx) ); 00449 00450 00451 // - reloc fastptr (!!) 00452 //const MemParams::RhythmTemp *rhythmTemp; 00453 partial->getSynth()->findRhythmTemp( rhythmTemp, &rhythmTemp_idx ); 00454 stream.write(reinterpret_cast<const char*>(&rhythmTemp_idx), sizeof(rhythmTemp_idx) ); 00455 00456 00457 stream.write(reinterpret_cast<const char*>(&playing), sizeof(playing) ); 00458 stream.write(reinterpret_cast<const char*>(&biasAmpSubtraction), sizeof(biasAmpSubtraction) ); 00459 stream.write(reinterpret_cast<const char*>(&veloAmpSubtraction), sizeof(veloAmpSubtraction) ); 00460 stream.write(reinterpret_cast<const char*>(&keyTimeSubtraction), sizeof(keyTimeSubtraction) ); 00461 stream.write(reinterpret_cast<const char*>(&target), sizeof(target) ); 00462 stream.write(reinterpret_cast<const char*>(&phase), sizeof(phase) ); 00463 00464 00465 #ifdef WIN32_DEBUG 00466 // DEBUG 00467 partial->getSynth()->rawDumpState( "temp-save", this, sizeof(*this) ); 00468 partial->getSynth()->rawDumpNo++; 00469 #endif 00470 } 00471 00472 00473 void TVA::loadState( std::istream &stream ) 00474 { 00475 Bit16u partialParam_idx1, partialParam_idx2; 00476 Bit8u part_idx; 00477 Bit8u patchTemp_idx; 00478 Bit8u rhythmTemp_idx; 00479 00480 00481 // - static fastptr 00482 //const Partial * const partial; 00483 //LA32Ramp *ampRamp; 00484 //const MemParams::System * const system; 00485 00486 00487 // - reloc fastptr (!!) 00488 //const Part *part; 00489 stream.read(reinterpret_cast<char*>(&part_idx), sizeof(part_idx) ); 00490 part = partial->getSynth()->indexPart(part_idx); 00491 00492 00493 // - reloc fastptr (!!) 00494 //const TimbreParam::PartialParam *partialParam; 00495 stream.read(reinterpret_cast<char*>(&partialParam_idx1), sizeof(partialParam_idx1) ); 00496 stream.read(reinterpret_cast<char*>(&partialParam_idx2), sizeof(partialParam_idx2) ); 00497 partialParam = partial->getSynth()->indexPartialParam(partialParam_idx1, partialParam_idx2); 00498 00499 00500 // - reloc fastptr (!!) 00501 //const MemParams::PatchTemp *patchTemp; 00502 stream.read(reinterpret_cast<char*>(&patchTemp_idx), sizeof(patchTemp_idx) ); 00503 patchTemp = partial->getSynth()->indexPatchTemp(patchTemp_idx); 00504 00505 00506 // - reloc fastptr (!!) 00507 //const MemParams::RhythmTemp *rhythmTemp; 00508 stream.read(reinterpret_cast<char*>(&rhythmTemp_idx), sizeof(rhythmTemp_idx) ); 00509 rhythmTemp = partial->getSynth()->indexRhythmTemp(rhythmTemp_idx); 00510 00511 00512 stream.read(reinterpret_cast<char*>(&playing), sizeof(playing) ); 00513 stream.read(reinterpret_cast<char*>(&biasAmpSubtraction), sizeof(biasAmpSubtraction) ); 00514 stream.read(reinterpret_cast<char*>(&veloAmpSubtraction), sizeof(veloAmpSubtraction) ); 00515 stream.read(reinterpret_cast<char*>(&keyTimeSubtraction), sizeof(keyTimeSubtraction) ); 00516 stream.read(reinterpret_cast<char*>(&target), sizeof(target) ); 00517 stream.read(reinterpret_cast<char*>(&phase), sizeof(phase) ); 00518 00519 00520 #ifdef WIN32_DEBUG 00521 // DEBUG 00522 partial->getSynth()->rawDumpState( "temp-load", this, sizeof(*this) ); 00523 this->rawVerifyState( "temp-save", partial->getSynth() ); 00524 partial->getSynth()->rawDumpNo++; 00525 #endif 00526 } 00527 00528 }