DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator
src/mt32/TVP.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 
00021 #include "mt32emu.h"
00022 
00023 namespace MT32Emu {
00024 
00025 // FIXME: Add Explanation
00026 static Bit16u lowerDurationToDivisor[] = {34078, 37162, 40526, 44194, 48194, 52556, 57312, 62499};
00027 
00028 // These values represent unique options with no consistent pattern, so we have to use something like a table in any case.
00029 // The table matches exactly what the manual claims (when divided by 8192):
00030 // -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
00031 // ...except for the last two entries, which are supposed to be "1 cent above 1" and "2 cents above 1", respectively. They can only be roughly approximated with this integer math.
00032 static Bit16s pitchKeyfollowMult[] = {-8192, -4096, -2048, 0, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192, 10240, 12288, 16384, 8198, 8226};
00033 
00034 // Note: Keys < 60 use keyToPitchTable[60 - key], keys >= 60 use keyToPitchTable[key - 60].
00035 // FIXME: This table could really be shorter, since we never use e.g. key 127.
00036 static Bit16u keyToPitchTable[] = {
00037             0,   341,   683,  1024,  1365,  1707,  2048,  2389,
00038          2731,  3072,  3413,  3755,  4096,  4437,  4779,  5120,
00039          5461,  5803,  6144,  6485,  6827,  7168,  7509,  7851,
00040          8192,  8533,  8875,  9216,  9557,  9899, 10240, 10581,
00041         10923, 11264, 11605, 11947, 12288, 12629, 12971, 13312,
00042         13653, 13995, 14336, 14677, 15019, 15360, 15701, 16043,
00043         16384, 16725, 17067, 17408, 17749, 18091, 18432, 18773,
00044         19115, 19456, 19797, 20139, 20480, 20821, 21163, 21504,
00045         21845, 22187, 22528, 22869
00046 };
00047 
00048 TVP::TVP(const Partial *usePartial) :
00049         partial(usePartial), system(&usePartial->getSynth()->mt32ram.system) {
00050         // We want to do processing 4000 times per second. FIXME: This is pretty arbitrary.
00051         maxCounter = SAMPLE_RATE / 4000;
00052         // The timer runs at 500kHz. We only need to bother updating it every maxCounter samples, before we do processing.
00053         // This is how much to increment it by every maxCounter samples.
00054         processTimerIncrement = 500000 * maxCounter / SAMPLE_RATE;
00055 
00056 
00057         // init ptr warnings (load state crashes)
00058         part = NULL;
00059         partialParam = NULL;
00060         patchTemp = NULL;
00061 }
00062 
00063 static Bit16s keyToPitch(unsigned int key) {
00064         // We're using a table to do: return round_to_nearest_or_even((key - 60) * (4096.0 / 12.0))
00065         // Banker's rounding is just slightly annoying to do in C++
00066         int k = (int)key;
00067         Bit16s pitch = keyToPitchTable[abs(k - 60)];
00068         return key < 60 ? -pitch : pitch;
00069 }
00070 
00071 static inline Bit32s coarseToPitch(Bit8u coarse) {
00072         return (coarse - 36) * 4096 / 12; // One semitone per coarse offset
00073 }
00074 
00075 static inline Bit32s fineToPitch(Bit8u fine) {
00076         return (fine - 50) * 4096 / 1200; // One cent per fine offset
00077 }
00078 
00079 static Bit32u calcBasePitch(const Partial *partial, const TimbreParam::PartialParam *partialParam, const MemParams::PatchTemp *patchTemp, unsigned int key) {
00080         Bit32s basePitch = keyToPitch(key);
00081         basePitch = (basePitch * pitchKeyfollowMult[partialParam->wg.pitchKeyfollow]) >> 13; // PORTABILITY NOTE: Assumes arithmetic shift
00082         basePitch += coarseToPitch(partialParam->wg.pitchCoarse);
00083         basePitch += fineToPitch(partialParam->wg.pitchFine);
00084         // NOTE:Mok: This is done on MT-32, but not LAPC-I:
00085         //pitch += coarseToPitch(patchTemp->patch.keyShift + 12);
00086         basePitch += fineToPitch(patchTemp->patch.fineTune);
00087 
00088         const ControlROMPCMStruct *controlROMPCMStruct = partial->getControlROMPCMStruct();
00089         if (controlROMPCMStruct != NULL) {
00090                 basePitch += (Bit32s)((((Bit32s)controlROMPCMStruct->pitchMSB) << 8) | (Bit32s)controlROMPCMStruct->pitchLSB);
00091         } else {
00092                 if ((partialParam->wg.waveform & 1) == 0) {
00093                         basePitch += 37133; // This puts Middle C at around 261.64Hz (assuming no other modifications, masterTune of 64, etc.)
00094                 } else {
00095                         // Sawtooth waves are effectively double the frequency of square waves.
00096                         // Thus we add 4096 less than for square waves here, which results in halving the frequency.
00097                         basePitch += 33037;
00098                 }
00099         }
00100         if (basePitch < 0) {
00101                 basePitch = 0;
00102         }
00103         if (basePitch > 59392) {
00104                 basePitch = 59392;
00105         }
00106         return (Bit32u)basePitch;
00107 }
00108 
00109 static Bit32u calcVeloMult(Bit8u veloSensitivity, unsigned int velocity) {
00110         if (veloSensitivity == 0 || veloSensitivity > 3) {
00111                 // Note that on CM-32L/LAPC-I veloSensitivity is never > 3, since it's clipped to 3 by the max tables.
00112                 return 21845; // aka floor(4096 / 12 * 64), aka ~64 semitones
00113         }
00114         // When velocity is 127, the multiplier is 21845, aka ~64 semitones (regardless of veloSensitivity).
00115         // The lower the velocity, the lower the multiplier. The veloSensitivity determines the amount decreased per velocity value.
00116         // The minimum multiplier (with velocity 0, veloSensitivity 3) is 170 (~half a semitone).
00117         Bit32u veloMult = 32768;
00118         veloMult -= (127 - velocity) << (5 + veloSensitivity);
00119         veloMult *= 21845;
00120         veloMult >>= 15;
00121         return veloMult;
00122 }
00123 
00124 static Bit32s calcTargetPitchOffsetWithoutLFO(const TimbreParam::PartialParam *partialParam, int levelIndex, unsigned int velocity) {
00125         int veloMult = calcVeloMult(partialParam->pitchEnv.veloSensitivity, velocity);
00126         int targetPitchOffsetWithoutLFO = partialParam->pitchEnv.level[levelIndex] - 50;
00127         targetPitchOffsetWithoutLFO = (Bit32s)(targetPitchOffsetWithoutLFO * veloMult) >> (16 - partialParam->pitchEnv.depth); // PORTABILITY NOTE: Assumes arithmetic shift
00128         return targetPitchOffsetWithoutLFO;
00129 }
00130 
00131 void TVP::reset(const Part *usePart, const TimbreParam::PartialParam *usePartialParam) {
00132         part = usePart;
00133         partialParam = usePartialParam;
00134         patchTemp = part->getPatchTemp();
00135 
00136         unsigned int key = partial->getPoly()->getKey();
00137         unsigned int velocity = partial->getPoly()->getVelocity();
00138 
00139         // FIXME: We're using a per-TVP timer instead of a system-wide one for convenience.
00140         timeElapsed = 0;
00141 
00142         basePitch = calcBasePitch(partial, partialParam, patchTemp, key);
00143         currentPitchOffset = calcTargetPitchOffsetWithoutLFO(partialParam, 0, velocity);
00144         targetPitchOffsetWithoutLFO = currentPitchOffset;
00145         phase = 0;
00146 
00147         if (partialParam->pitchEnv.timeKeyfollow) {
00148                 timeKeyfollowSubtraction = (key - 60) >> (5 - partialParam->pitchEnv.timeKeyfollow); // PORTABILITY NOTE: Assumes arithmetic shift
00149         } else {
00150                 timeKeyfollowSubtraction = 0;
00151         }
00152         lfoPitchOffset = 0;
00153         counter = 0;
00154         pitch = basePitch;
00155 
00156         // These don't really need to be initialised, but it aids debugging.
00157         pitchOffsetChangePerBigTick = 0;
00158         targetPitchOffsetReachedBigTick = 0;
00159         shifts = 0;
00160 }
00161 
00162 Bit32u TVP::getBasePitch() const {
00163         return basePitch;
00164 }
00165 
00166 void TVP::updatePitch() {
00167         Bit32s newPitch = basePitch + currentPitchOffset;
00168         if (!partial->isPCM() || (partial->getControlROMPCMStruct()->len & 0x01) == 0) { // FIXME: Use !partial->pcmWaveEntry->unaffectedByMasterTune instead
00169                 // FIXME: masterTune recalculation doesn't really happen here, and there are various bugs not yet emulated
00170                 // 171 is ~half a semitone.
00171                 newPitch += ((system->masterTune - 64) * 171) >> 6; // PORTABILITY NOTE: Assumes arithmetic shift.
00172         }
00173         if ((partialParam->wg.pitchBenderEnabled & 1) != 0) {
00174                 newPitch += part->getPitchBend();
00175         }
00176         if (newPitch < 0) {
00177                 newPitch = 0;
00178         }
00179 
00180 // Note: Temporary #ifdef until we have proper "quirk" configuration
00181 // This is about right emulation of MT-32 GEN0 quirk exploited in Colonel's Bequest timbre "Lightning"
00182 #ifndef MT32EMU_QUIRK_PITCH_ENVELOPE_OVERFLOW_MT32
00183         if (newPitch > 59392) {
00184                 newPitch = 59392;
00185         }
00186 #endif
00187         pitch = (Bit16u)newPitch;
00188 
00189         // FIXME: We're doing this here because that's what the CM-32L does - we should probably move this somewhere more appropriate in future.
00190         partial->tva->recalcSustain();
00191 }
00192 
00193 void TVP::targetPitchOffsetReached() {
00194         currentPitchOffset = targetPitchOffsetWithoutLFO + lfoPitchOffset;
00195 
00196         switch (phase) {
00197         case 3:
00198         case 4:
00199         {
00200                 int newLFOPitchOffset = (part->getModulation() * partialParam->pitchLFO.modSensitivity) >> 7;
00201                 newLFOPitchOffset = (newLFOPitchOffset + partialParam->pitchLFO.depth) << 1;
00202                 if (pitchOffsetChangePerBigTick > 0) {
00203                         // Go in the opposite direction to last time
00204                         newLFOPitchOffset = -newLFOPitchOffset;
00205                 }
00206                 lfoPitchOffset = newLFOPitchOffset;
00207                 int targetPitchOffset = targetPitchOffsetWithoutLFO + lfoPitchOffset;
00208                 setupPitchChange(targetPitchOffset, 101 - partialParam->pitchLFO.rate);
00209                 updatePitch();
00210                 break;
00211         }
00212         case 6:
00213                 updatePitch();
00214                 break;
00215         default:
00216                 nextPhase();
00217         }
00218 }
00219 
00220 void TVP::nextPhase() {
00221         phase++;
00222         int envIndex = phase == 6 ? 4 : phase;
00223 
00224         targetPitchOffsetWithoutLFO = calcTargetPitchOffsetWithoutLFO(partialParam, envIndex, partial->getPoly()->getVelocity()); // pitch we'll reach at the end
00225 
00226         int changeDuration = partialParam->pitchEnv.time[envIndex - 1];
00227         changeDuration -= timeKeyfollowSubtraction;
00228         if (changeDuration > 0) {
00229                 setupPitchChange(targetPitchOffsetWithoutLFO, changeDuration); // changeDuration between 0 and 112 now
00230                 updatePitch();
00231         } else {
00232                 targetPitchOffsetReached();
00233         }
00234 }
00235 
00236 // Shifts val to the left until bit 31 is 1 and returns the number of shifts
00237 static Bit8u normalise(Bit32u &val) {
00238         Bit8u leftShifts;
00239         for (leftShifts = 0; leftShifts < 31; leftShifts++) {
00240                 if ((val & 0x80000000) != 0) {
00241                         break;
00242                 }
00243                 val = val << 1;
00244         }
00245         return leftShifts;
00246 }
00247 
00248 void TVP::setupPitchChange(int targetPitchOffset, Bit8u changeDuration) {
00249         bool negativeDelta = targetPitchOffset < currentPitchOffset;
00250         Bit32s pitchOffsetDelta = targetPitchOffset - currentPitchOffset;
00251         if (pitchOffsetDelta > 32767 || pitchOffsetDelta < -32768) {
00252                 pitchOffsetDelta = 32767;
00253         }
00254         if (negativeDelta) {
00255                 pitchOffsetDelta = -pitchOffsetDelta;
00256         }
00257         // We want to maximise the number of bits of the Bit16s "pitchOffsetChangePerBigTick" we use in order to get the best possible precision later
00258         Bit32u absPitchOffsetDelta = pitchOffsetDelta << 16;
00259         Bit8u normalisationShifts = normalise(absPitchOffsetDelta); // FIXME: Double-check: normalisationShifts is usually between 0 and 15 here, unless the delta is 0, in which case it's 31
00260         absPitchOffsetDelta = absPitchOffsetDelta >> 1; // Make room for the sign bit
00261 
00262         changeDuration--; // changeDuration's now between 0 and 111
00263         unsigned int upperDuration = changeDuration >> 3; // upperDuration's now between 0 and 13
00264         shifts = normalisationShifts + upperDuration + 2;
00265         Bit16u divisor = lowerDurationToDivisor[changeDuration & 7];
00266         Bit16s newPitchOffsetChangePerBigTick = ((absPitchOffsetDelta & 0xFFFF0000) / divisor) >> 1; // Result now fits within 15 bits. FIXME: Check nothing's getting sign-extended incorrectly
00267         if (negativeDelta) {
00268                 newPitchOffsetChangePerBigTick = -newPitchOffsetChangePerBigTick;
00269         }
00270         pitchOffsetChangePerBigTick = newPitchOffsetChangePerBigTick;
00271 
00272         int currentBigTick = timeElapsed >> 8;
00273         int durationInBigTicks = divisor >> (12 - upperDuration);
00274         if (durationInBigTicks > 32767) {
00275                 durationInBigTicks = 32767;
00276         }
00277         // The result of the addition may exceed 16 bits, but wrapping is fine and intended here.
00278         targetPitchOffsetReachedBigTick = currentBigTick + durationInBigTicks;
00279 }
00280 
00281 void TVP::startDecay() {
00282         phase = 5;
00283         lfoPitchOffset = 0;
00284         targetPitchOffsetReachedBigTick = timeElapsed >> 8; // FIXME: Afaict there's no good reason for this - check
00285 }
00286 
00287 Bit16u TVP::nextPitch() {
00288         // FIXME: Write explanation of counter and time increment
00289         if (counter == 0) {
00290                 timeElapsed += processTimerIncrement;
00291                 timeElapsed = timeElapsed & 0x00FFFFFF;
00292                 process();
00293         }
00294         counter = (counter + 1) % maxCounter;
00295         return pitch;
00296 }
00297 
00298 void TVP::process() {
00299         if (phase == 0) {
00300                 targetPitchOffsetReached();
00301                 return;
00302         }
00303         if (phase == 5) {
00304                 nextPhase();
00305                 return;
00306         }
00307         if (phase > 7) {
00308                 updatePitch();
00309                 return;
00310         }
00311 
00312         Bit16s negativeBigTicksRemaining = (timeElapsed >> 8) - targetPitchOffsetReachedBigTick;
00313         if (negativeBigTicksRemaining >= 0) {
00314                 // We've reached the time for a phase change
00315                 targetPitchOffsetReached();
00316                 return;
00317         }
00318         // FIXME: Write explanation for this stuff
00319         int rightShifts = shifts;
00320         if (rightShifts > 13) {
00321                 rightShifts -= 13;
00322                 negativeBigTicksRemaining = negativeBigTicksRemaining >> rightShifts; // PORTABILITY NOTE: Assumes arithmetic shift
00323                 rightShifts = 13;
00324         }
00325         int newResult = ((Bit32s)(negativeBigTicksRemaining * pitchOffsetChangePerBigTick)) >> rightShifts; // PORTABILITY NOTE: Assumes arithmetic shift
00326         newResult += targetPitchOffsetWithoutLFO + lfoPitchOffset;
00327         currentPitchOffset = newResult;
00328         updatePitch();
00329 }
00330 
00331 
00332 #ifdef WIN32_DEBUG
00333 void TVP::rawVerifyState( char *name, Synth *useSynth )
00334 {
00335         TVP *ptr1, *ptr2;
00336         TVP tvp_temp(partial);
00337 
00338 
00339 #ifndef WIN32_DUMP
00340         return;
00341 #endif
00342 
00343         ptr1 = this;
00344         ptr2 = &tvp_temp;
00345         useSynth->rawLoadState( name, ptr2, sizeof(*this) );
00346 
00347 
00348         if( ptr1->partial != ptr2->partial ) __asm int 3
00349         if( ptr1->system != ptr2->system ) __asm int 3
00350         if( ptr1->part != ptr2->part ) __asm int 3
00351         if( ptr1->partialParam != ptr2->partialParam ) __asm int 3
00352         if( ptr1->patchTemp != ptr2->patchTemp ) __asm int 3
00353         if( ptr1->maxCounter != ptr2->maxCounter ) __asm int 3
00354         if( ptr1->processTimerIncrement != ptr2->processTimerIncrement ) __asm int 3
00355         if( ptr1->counter != ptr2->counter ) __asm int 3
00356         if( ptr1->timeElapsed != ptr2->timeElapsed ) __asm int 3
00357         if( ptr1->phase != ptr2->phase ) __asm int 3
00358         if( ptr1->basePitch != ptr2->basePitch ) __asm int 3
00359         if( ptr1->targetPitchOffsetWithoutLFO != ptr2->targetPitchOffsetWithoutLFO ) __asm int 3
00360         if( ptr1->currentPitchOffset != ptr2->currentPitchOffset ) __asm int 3
00361         if( ptr1->lfoPitchOffset != ptr2->lfoPitchOffset ) __asm int 3
00362         if( ptr1->timeKeyfollowSubtraction != ptr2->timeKeyfollowSubtraction ) __asm int 3
00363         if( ptr1->pitchOffsetChangePerBigTick != ptr2->pitchOffsetChangePerBigTick ) __asm int 3
00364         if( ptr1->targetPitchOffsetReachedBigTick != ptr2->targetPitchOffsetReachedBigTick ) __asm int 3
00365         if( ptr1->shifts != ptr2->shifts ) __asm int 3
00366         if( ptr1->pitch != ptr2->pitch ) __asm int 3
00367 
00368                 
00369                 
00370         // avoid destructor problems
00371         memset( ptr2, 0, sizeof(*ptr2) );
00372 }
00373 #endif
00374 
00375 
00376 void TVP::saveState( std::ostream &stream )
00377 {
00378         Bit16u partialParam_idx1, partialParam_idx2;
00379         Bit8u part_idx;
00380         Bit8u patchTemp_idx;
00381 
00382 
00383         // - static fastptr
00384         //const Partial * const partial;
00385         //const MemParams::System * const system; // FIXME: Only necessary because masterTune calculation is done in the wrong place atm.
00386 
00387 
00388         // - reloc fastptr (!!)
00389         //const Part *part;
00390         partial->getSynth()->findPart( part, &part_idx );
00391         stream.write(reinterpret_cast<const char*>(&part_idx), sizeof(part_idx) );
00392 
00393 
00394         // - reloc fastptr (!!)
00395         //const TimbreParam::PartialParam *partialParam;
00396         partial->getSynth()->findPartialParam( partialParam, &partialParam_idx1, &partialParam_idx2 );
00397         stream.write(reinterpret_cast<const char*>(&partialParam_idx1), sizeof(partialParam_idx1) );
00398         stream.write(reinterpret_cast<const char*>(&partialParam_idx2), sizeof(partialParam_idx2) );
00399 
00400 
00401         // - reloc fastptr (!!)
00402         //const MemParams::PatchTemp *patchTemp;
00403         partial->getSynth()->findPatchTemp( patchTemp, &patchTemp_idx );
00404         stream.write(reinterpret_cast<const char*>(&patchTemp_idx), sizeof(patchTemp_idx) );
00405 
00406 
00407         stream.write(reinterpret_cast<const char*>(&maxCounter), sizeof(maxCounter) );
00408         stream.write(reinterpret_cast<const char*>(&processTimerIncrement), sizeof(processTimerIncrement) );
00409         stream.write(reinterpret_cast<const char*>(&counter), sizeof(counter) );
00410         stream.write(reinterpret_cast<const char*>(&timeElapsed), sizeof(timeElapsed) );
00411         stream.write(reinterpret_cast<const char*>(&phase), sizeof(phase) );
00412         stream.write(reinterpret_cast<const char*>(&basePitch), sizeof(basePitch) );
00413         stream.write(reinterpret_cast<const char*>(&targetPitchOffsetWithoutLFO), sizeof(targetPitchOffsetWithoutLFO) );
00414         stream.write(reinterpret_cast<const char*>(&currentPitchOffset), sizeof(currentPitchOffset) );
00415         stream.write(reinterpret_cast<const char*>(&lfoPitchOffset), sizeof(lfoPitchOffset) );
00416         stream.write(reinterpret_cast<const char*>(&timeKeyfollowSubtraction), sizeof(timeKeyfollowSubtraction) );
00417         stream.write(reinterpret_cast<const char*>(&pitchOffsetChangePerBigTick), sizeof(pitchOffsetChangePerBigTick) );
00418         stream.write(reinterpret_cast<const char*>(&targetPitchOffsetReachedBigTick), sizeof(targetPitchOffsetReachedBigTick) );
00419         stream.write(reinterpret_cast<const char*>(&shifts), sizeof(shifts) );
00420         stream.write(reinterpret_cast<const char*>(&pitch), sizeof(pitch) );
00421 
00422 
00423 #ifdef WIN32_DEBUG
00424         // DEBUG
00425         partial->getSynth()->rawDumpState( "temp-save", this, sizeof(*this) );
00426         partial->getSynth()->rawDumpNo++;
00427 #endif
00428 }
00429 
00430 
00431 void TVP::loadState( std::istream &stream )
00432 {
00433         Bit16u partialParam_idx1, partialParam_idx2;
00434         Bit8u part_idx;
00435         Bit8u patchTemp_idx;
00436 
00437 
00438         // - static fastptr
00439         //const Partial * const partial;
00440         //const MemParams::System * const system; // FIXME: Only necessary because masterTune calculation is done in the wrong place atm.
00441 
00442 
00443         // - reloc fastptr (!!)
00444         //const Part *part;
00445         stream.read(reinterpret_cast<char*>(&part_idx), sizeof(part_idx) );
00446         part = partial->getSynth()->indexPart(part_idx);
00447 
00448 
00449         // - reloc fastptr (!!)
00450         //const TimbreParam::PartialParam *partialParam;
00451         stream.read(reinterpret_cast<char*>(&partialParam_idx1), sizeof(partialParam_idx1) );
00452         stream.read(reinterpret_cast<char*>(&partialParam_idx2), sizeof(partialParam_idx2) );
00453         partialParam = partial->getSynth()->indexPartialParam(partialParam_idx1, partialParam_idx2);
00454 
00455 
00456         // - reloc fastptr (!!)
00457         //const MemParams::PatchTemp *patchTemp;
00458         stream.read(reinterpret_cast<char*>(&patchTemp_idx), sizeof(patchTemp_idx) );
00459         patchTemp = partial->getSynth()->indexPatchTemp(patchTemp_idx);
00460 
00461 
00462         stream.read(reinterpret_cast<char*>(&maxCounter), sizeof(maxCounter) );
00463         stream.read(reinterpret_cast<char*>(&processTimerIncrement), sizeof(processTimerIncrement) );
00464         stream.read(reinterpret_cast<char*>(&counter), sizeof(counter) );
00465         stream.read(reinterpret_cast<char*>(&timeElapsed), sizeof(timeElapsed) );
00466         stream.read(reinterpret_cast<char*>(&phase), sizeof(phase) );
00467         stream.read(reinterpret_cast<char*>(&basePitch), sizeof(basePitch) );
00468         stream.read(reinterpret_cast<char*>(&targetPitchOffsetWithoutLFO), sizeof(targetPitchOffsetWithoutLFO) );
00469         stream.read(reinterpret_cast<char*>(&currentPitchOffset), sizeof(currentPitchOffset) );
00470         stream.read(reinterpret_cast<char*>(&lfoPitchOffset), sizeof(lfoPitchOffset) );
00471         stream.read(reinterpret_cast<char*>(&timeKeyfollowSubtraction), sizeof(timeKeyfollowSubtraction) );
00472         stream.read(reinterpret_cast<char*>(&pitchOffsetChangePerBigTick), sizeof(pitchOffsetChangePerBigTick) );
00473         stream.read(reinterpret_cast<char*>(&targetPitchOffsetReachedBigTick), sizeof(targetPitchOffsetReachedBigTick) );
00474         stream.read(reinterpret_cast<char*>(&shifts), sizeof(shifts) );
00475         stream.read(reinterpret_cast<char*>(&pitch), sizeof(pitch) );
00476 
00477 
00478 #ifdef WIN32_DEBUG
00479         // DEBUG
00480         partial->getSynth()->rawDumpState( "temp-load", this, sizeof(*this) );
00481         this->rawVerifyState( "temp-save", partial->getSynth() );
00482         partial->getSynth()->rawDumpNo++;
00483 #endif
00484 }
00485 
00486 }