Пример #1
0
void TVA::recalcSustain() {
	// We get pinged periodically by the pitch code to recalculate our values when in sustain.
	// 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.

	// The check for envLevel[3] == 0 strikes me as slightly dumb. FIXME: Explain why
	if (phase != TVA_PHASE_SUSTAIN || partialParam->tva.envLevel[3] == 0) {
		return;
	}
	// We're sustaining. Recalculate all the values
	const Tables *tables = &Tables::getInstance();
	int newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression());
	newTarget += partialParam->tva.envLevel[3];
	// 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.
	int targetDelta = newTarget - target;

	// Calculate an increment to get to the new amp value in a short, more or less consistent amount of time
	Bit8u newIncrement;
	if (targetDelta >= 0) {
		newIncrement = tables->envLogarithmicTime[(Bit8u)targetDelta] - 2;
	} else {
		newIncrement = (tables->envLogarithmicTime[(Bit8u)-targetDelta] - 2) | 0x80;
	}
	// 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).
	startRamp(newTarget, newIncrement, TVA_PHASE_SUSTAIN - 1);
}
Пример #2
0
void TVA::recalcSustain() {
	// We get pinged periodically by the pitch code to recalculate our values when in sustain.
	// 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.

	// The check for envLevel[3] == 0 strikes me as slightly dumb. FIXME: Explain why
	if (targetPhase != TVA_PHASE_SUSTAIN || partialParam->tva.envLevel[3] == 0) {
		return;
	}
	// We're sustaining. Recalculate all the values
	Tables *tables = &partial->getSynth()->tables;
	int newTargetAmp = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression());
	newTargetAmp += partialParam->tva.envLevel[3];
	// FIXME: This whole concept seems flawed. We don't really know what the *actual* amp value is, right? It may well not be la32TargetAmp yet (unless I've missed something). So we could end up going in the wrong direction...
	int ampDelta = newTargetAmp - la32TargetAmp;

	// Calculate an increment to get to the new amp value in a short, more or less consistent amount of time
	if (ampDelta >= 0) {
		setAmpIncrement(tables->envLogarithmicTime[(Bit8u)ampDelta] - 2);
	} else {
		setAmpIncrement((tables->envLogarithmicTime[(Bit8u)-ampDelta] - 2) | 0x80);
	}
	la32TargetAmp = newTargetAmp;
	// 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).
	targetPhase = TVA_PHASE_SUSTAIN - 1;
}
Пример #3
0
void TVA::reset(const Part *newPart, const TimbreParam::PartialParam *newPartialParam, const MemParams::RhythmTemp *newRhythmTemp) {
	part = newPart;
	partialParam = newPartialParam;
	patchTemp = newPart->getPatchTemp();
	rhythmTemp = newRhythmTemp;

	playing = true;

	Tables *tables = &partial->getSynth()->tables;

	int key = partial->getPoly()->getKey();
	int velocity = partial->getPoly()->getVelocity();

	keyTimeSubtraction = calcKeyTimeSubtraction(partialParam->tva.envTimeKeyfollow, key);

	biasAmpSubtraction = calcBiasAmpSubtractions(partialParam, key);
	veloAmpSubtraction = calcVeloAmpSubtraction(partialParam->tva.veloSensitivity, velocity);

	int newTargetAmp = calcBasicAmp(tables, partial, system, partialParam, patchTemp, newRhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression());

	if (partialParam->tva.envTime[0] == 0) {
		// Initially go to the TVA_PHASE_ATTACK target amp, and spend the next phase going from there to the TVA_PHASE_2 target amp
		// Note that this means that velocity never affects time for this partial.
		newTargetAmp += partialParam->tva.envLevel[0];
		targetPhase = TVA_PHASE_2 - 1; // The first target used in nextPhase() will be TVA_PHASE_2
	} else {
		// 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.
		targetPhase = TVA_PHASE_ATTACK - 1; // The first target used in nextPhase() will be TVA_PHASE_ATTACK
	}

	// "Go downward as quickly as possible".
	// Since currentAmp is 0, nextAmp() will notice that we're already at or below the target and trying to go downward,
	// and therefore jump to the target immediately and call nextPhase().
	setAmpIncrement(0x80 | 127);
	la32TargetAmp = (Bit8u)newTargetAmp;

	currentAmp = 0;
}
Пример #4
0
Файл: TVA.cpp Проект: munt/munt
void TVA::reset(const Part *newPart, const TimbreParam::PartialParam *newPartialParam, const MemParams::RhythmTemp *newRhythmTemp) {
	part = newPart;
	partialParam = newPartialParam;
	patchTemp = newPart->getPatchTemp();
	rhythmTemp = newRhythmTemp;

	playing = true;

	const Tables *tables = &Tables::getInstance();

	int key = partial->getPoly()->getKey();
	int velocity = partial->getPoly()->getVelocity();

	keyTimeSubtraction = calcKeyTimeSubtraction(partialParam->tva.envTimeKeyfollow, key);

	biasAmpSubtraction = calcBiasAmpSubtractions(partialParam, key);
	veloAmpSubtraction = calcVeloAmpSubtraction(partialParam->tva.veloSensitivity, velocity);

	int newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, newRhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression(), partial->getSynth()->controlROMFeatures->quirkRingModulationNoMix);
	int newPhase;
	if (partialParam->tva.envTime[0] == 0) {
		// Initially go to the TVA_PHASE_ATTACK target amp, and spend the next phase going from there to the TVA_PHASE_2 target amp
		// Note that this means that velocity never affects time for this partial.
		newTarget += partialParam->tva.envLevel[0];
		newPhase = TVA_PHASE_ATTACK; // The first target used in nextPhase() will be TVA_PHASE_2
	} else {
		// 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.
		newPhase = TVA_PHASE_BASIC; // The first target used in nextPhase() will be TVA_PHASE_ATTACK
	}

	ampRamp->reset();//currentAmp = 0;

	// "Go downward as quickly as possible".
	// Since the current value is 0, the LA32Ramp will notice that we're already at or below the target and trying to go downward,
	// and therefore jump to the target immediately and raise an interrupt.
	startRamp(Bit8u(newTarget), 0x80 | 127, newPhase);
}
Пример #5
0
Файл: TVA.cpp Проект: munt/munt
void TVA::recalcSustain() {
	// We get pinged periodically by the pitch code to recalculate our values when in sustain.
	// 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.

	// The check for envLevel[3] == 0 strikes me as slightly dumb. FIXME: Explain why
	if (phase != TVA_PHASE_SUSTAIN || partialParam->tva.envLevel[3] == 0) {
		return;
	}
	// We're sustaining. Recalculate all the values
	const Tables *tables = &Tables::getInstance();
	int newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression(), partial->getSynth()->controlROMFeatures->quirkRingModulationNoMix);
	newTarget += partialParam->tva.envLevel[3];

	// Although we're in TVA_PHASE_SUSTAIN at this point, we cannot be sure that there is no active ramp at the moment.
	// In case the channel volume or the expression changes frequently, the previously started ramp may still be in progress.
	// Real hardware units ignore this possibility and rely on the assumption that the target is the current amp.
	// This is OK in most situations but when the ramp that is currently in progress needs to change direction
	// due to a volume/expression update, this leads to a jump in the amp that is audible as an unpleasant click.
	// To avoid that, we compare the newTarget with the the actual current ramp value and correct the direction if necessary.
	int targetDelta = newTarget - target;

	// Calculate an increment to get to the new amp value in a short, more or less consistent amount of time
	Bit8u newIncrement;
	bool descending = targetDelta < 0;
	if (!descending) {
		newIncrement = tables->envLogarithmicTime[Bit8u(targetDelta)] - 2;
	} else {
		newIncrement = (tables->envLogarithmicTime[Bit8u(-targetDelta)] - 2) | 0x80;
	}
	if (part->getSynth()->isNiceAmpRampEnabled() && (descending != ampRamp->isBelowCurrent(newTarget))) {
		newIncrement ^= 0x80;
	}

	// 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).
	startRamp(newTarget, newIncrement, TVA_PHASE_SUSTAIN - 1);
}
Пример #6
0
void TVA::nextPhase() {
	const Tables *tables = &Tables::getInstance();

	if (phase >= TVA_PHASE_DEAD || !playing) {
		partial->getSynth()->printDebug("TVA::nextPhase(): Shouldn't have got here with phase %d, playing=%s", phase, playing ? "true" : "false");
		return;
	}
	int newPhase = phase + 1;

	if (newPhase == TVA_PHASE_DEAD) {
		end(newPhase);
		return;
	}

	bool allLevelsZeroFromNowOn = false;
	if (partialParam->tva.envLevel[3] == 0) {
		if (newPhase == TVA_PHASE_4) {
			allLevelsZeroFromNowOn = true;
		} else if (partialParam->tva.envLevel[2] == 0) {
			if (newPhase == TVA_PHASE_3) {
				allLevelsZeroFromNowOn = true;
			} else if (partialParam->tva.envLevel[1] == 0) {
				if (newPhase == TVA_PHASE_2) {
					allLevelsZeroFromNowOn = true;
				} else if (partialParam->tva.envLevel[0] == 0) {
					if (newPhase == TVA_PHASE_ATTACK)  { // this line added, missing in ROM - FIXME: Add description of repercussions
						allLevelsZeroFromNowOn = true;
					}
				}
			}
		}
	}

	int newTarget;
	int newIncrement = 0; // Initialised to please compilers
	int envPointIndex = phase;

	if (!allLevelsZeroFromNowOn) {
		newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression());

		if (newPhase == TVA_PHASE_SUSTAIN || newPhase == TVA_PHASE_RELEASE) {
			if (partialParam->tva.envLevel[3] == 0) {
				end(newPhase);
				return;
			}
			if (!partial->getPoly()->canSustain()) {
				newPhase = TVA_PHASE_RELEASE;
				newTarget = 0;
				newIncrement = -partialParam->tva.envTime[4];
				if (newIncrement == 0) {
					// We can't let the increment be 0, or there would be no emulated interrupt.
					// So we do an "upward" increment, which should set the amp to 0 extremely quickly
					// and cause an "interrupt" to bring us back to nextPhase().
					newIncrement = 1;
				}
			} else {
				newTarget += partialParam->tva.envLevel[3];
				newIncrement = 0;
			}
		} else {
			newTarget += partialParam->tva.envLevel[envPointIndex];
		}
	} else {
		newTarget = 0;
	}

	if ((newPhase != TVA_PHASE_SUSTAIN && newPhase != TVA_PHASE_RELEASE) || allLevelsZeroFromNowOn) {
		int envTimeSetting = partialParam->tva.envTime[envPointIndex];

		if (newPhase == TVA_PHASE_ATTACK) {
			envTimeSetting -= ((signed)partial->getPoly()->getVelocity() - 64) >> (6 - partialParam->tva.envTimeVeloSensitivity); // PORTABILITY NOTE: Assumes arithmetic shift

			if (envTimeSetting <= 0 && partialParam->tva.envTime[envPointIndex] != 0) {
				envTimeSetting = 1;
			}
		} else {
Пример #7
0
void TVA::nextPhase() {
	Tables *tables = &partial->getSynth()->tables;

	if (targetPhase >= TVA_PHASE_DEAD || !playing) {
		partial->getSynth()->printDebug("TVA::nextPhase(): Shouldn't have got here with targetPhase %d, playing=%s", targetPhase, playing ? "true" : "false");
		return;
	}
	targetPhase++;

	if (targetPhase == TVA_PHASE_DEAD) {
		playing = false;
		return;
	}

	bool allLevelsZeroFromNowOn = false;
	if (partialParam->tva.envLevel[3] == 0) {
		if (targetPhase == TVA_PHASE_4) {
			allLevelsZeroFromNowOn = true;
		} else if (partialParam->tva.envLevel[2] == 0) {
			if (targetPhase == TVA_PHASE_3) {
				allLevelsZeroFromNowOn = true;
			} else if (partialParam->tva.envLevel[1] == 0) {
				if (targetPhase == TVA_PHASE_2) {
					allLevelsZeroFromNowOn = true;
				} else if (partialParam->tva.envLevel[0] == 0) {
					if (targetPhase == TVA_PHASE_ATTACK)  { // this line added, missing in ROM - FIXME: Add description of repercussions
						allLevelsZeroFromNowOn = true;
					}
				}
			}
		}
	}

	int newTargetAmp;
	int newAmpIncrement;
	int envPointIndex = targetPhase - 1;

	if (!allLevelsZeroFromNowOn) {
		newTargetAmp = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression());

		if (targetPhase == TVA_PHASE_SUSTAIN || targetPhase == TVA_PHASE_RELEASE) {
			if (partialParam->tva.envLevel[3] == 0) {
				playing = false;
				return;
			}
			if (!partial->getPoly()->canSustain()) {
				targetPhase = TVA_PHASE_RELEASE;
				newTargetAmp = 0;
				newAmpIncrement = -partialParam->tva.envTime[4];
				if (newAmpIncrement >= 0) {
					// FIXME: This must mean newAmpIncrement was 0, and we're now making it 1, which makes us go in the wrong direction. WTF?
					newAmpIncrement++;
				}
			} else {
				newTargetAmp += partialParam->tva.envLevel[3];
				newAmpIncrement = 0;
			}
		} else {
			newTargetAmp += partialParam->tva.envLevel[envPointIndex];
		}
	} else {
		newTargetAmp = 0;
	}

	if ((targetPhase != TVA_PHASE_SUSTAIN && targetPhase != TVA_PHASE_RELEASE) || allLevelsZeroFromNowOn) {
		int envTimeSetting = partialParam->tva.envTime[envPointIndex];

		if (targetPhase == TVA_PHASE_ATTACK) {
			envTimeSetting -= ((signed)partial->getPoly()->getVelocity() - 64) >> (6 - partialParam->tva.envTimeVeloSensitivity); // PORTABILITY NOTE: Assumes arithmetic shift

			if (envTimeSetting <= 0 && partialParam->tva.envTime[envPointIndex] != 0) {
				envTimeSetting = 1;
			}
		} else {