1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

LinearSmoothedValue: Added some helpful member functions and deprecated setValue

This commit is contained in:
reuk 2019-02-11 15:16:37 +00:00 committed by Tom Poole
parent 097525ba5b
commit b8278cec0e
11 changed files with 105 additions and 79 deletions

View file

@ -722,9 +722,9 @@ public:
jassert (currentlyPlayingNote.keyState == MPENote::keyDown jassert (currentlyPlayingNote.keyState == MPENote::keyDown
|| currentlyPlayingNote.keyState == MPENote::keyDownAndSustained); || currentlyPlayingNote.keyState == MPENote::keyDownAndSustained);
level.setValue (currentlyPlayingNote.pressure.asUnsignedFloat()); level .setTargetValue (currentlyPlayingNote.pressure.asUnsignedFloat());
frequency.setValue (currentlyPlayingNote.getFrequencyInHertz()); frequency.setTargetValue (currentlyPlayingNote.getFrequencyInHertz());
timbre.setValue (currentlyPlayingNote.timbre.asUnsignedFloat()); timbre .setTargetValue (currentlyPlayingNote.timbre.asUnsignedFloat());
phase = 0.0; phase = 0.0;
auto cyclesPerSample = frequency.getNextValue() / currentSampleRate; auto cyclesPerSample = frequency.getNextValue() / currentSampleRate;
@ -756,17 +756,17 @@ public:
void notePressureChanged() override void notePressureChanged() override
{ {
level.setValue (currentlyPlayingNote.pressure.asUnsignedFloat()); level.setTargetValue (currentlyPlayingNote.pressure.asUnsignedFloat());
} }
void notePitchbendChanged() override void notePitchbendChanged() override
{ {
frequency.setValue (currentlyPlayingNote.getFrequencyInHertz()); frequency.setTargetValue (currentlyPlayingNote.getFrequencyInHertz());
} }
void noteTimbreChanged() override void noteTimbreChanged() override
{ {
timbre.setValue (currentlyPlayingNote.timbre.asUnsignedFloat()); timbre.setTargetValue (currentlyPlayingNote.timbre.asUnsignedFloat());
} }
void noteKeyStateChanged() override {} void noteKeyStateChanged() override {}

View file

@ -65,8 +65,8 @@ public:
void startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int) override void startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int) override
{ {
frequency = MidiMessage::getMidiNoteInHertz (midiNoteNumber); frequency = MidiMessage::getMidiNoteInHertz (midiNoteNumber);
phaseIncrement.setValue (((MathConstants<double>::twoPi) * frequency) / sampleRate); phaseIncrement.setTargetValue (((MathConstants<double>::twoPi) * frequency) / sampleRate);
amplitude.setValue (velocity); amplitude.setTargetValue (velocity);
// Store the initial note and work out the maximum frequency deviations for pitch bend // Store the initial note and work out the maximum frequency deviations for pitch bend
initialNote = midiNoteNumber; initialNote = midiNoteNumber;
@ -77,14 +77,14 @@ public:
void stopNote (float, bool) override void stopNote (float, bool) override
{ {
clearCurrentNote(); clearCurrentNote();
amplitude.setValue (0.0); amplitude.setTargetValue (0.0);
} }
void pitchWheelMoved (int newValue) override void pitchWheelMoved (int newValue) override
{ {
// Change the phase increment based on pitch bend amount // Change the phase increment based on pitch bend amount
auto frequencyOffset = ((newValue > 0 ? maxFreq : minFreq) * (newValue / 127.0)); auto frequencyOffset = ((newValue > 0 ? maxFreq : minFreq) * (newValue / 127.0));
phaseIncrement.setValue (((MathConstants<double>::twoPi) * (frequency + frequencyOffset)) / sampleRate); phaseIncrement.setTargetValue (((MathConstants<double>::twoPi) * (frequency + frequencyOffset)) / sampleRate);
} }
void controllerMoved (int, int) override {} void controllerMoved (int, int) override {}
@ -92,7 +92,7 @@ public:
void channelPressureChanged (int newChannelPressureValue) override void channelPressureChanged (int newChannelPressureValue) override
{ {
// Set the amplitude based on pressure value // Set the amplitude based on pressure value
amplitude.setValue (newChannelPressureValue / 127.0); amplitude.setTargetValue (newChannelPressureValue / 127.0);
} }
void renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples) override void renderNextBlock (AudioBuffer<float>& outputBuffer, int startSample, int numSamples) override

View file

@ -250,12 +250,12 @@ public:
jassert (currentlyPlayingNote.keyState == MPENote::keyDown jassert (currentlyPlayingNote.keyState == MPENote::keyDown
|| currentlyPlayingNote.keyState == MPENote::keyDownAndSustained); || currentlyPlayingNote.keyState == MPENote::keyDownAndSustained);
level .setValue (currentlyPlayingNote.pressure.asUnsignedFloat()); level .setTargetValue (currentlyPlayingNote.pressure.asUnsignedFloat());
frequency.setValue (currentlyPlayingNote.getFrequencyInHertz()); frequency.setTargetValue (currentlyPlayingNote.getFrequencyInHertz());
auto loopPoints = samplerSound->getLoopPointsInSeconds(); auto loopPoints = samplerSound->getLoopPointsInSeconds();
loopBegin.setValue (loopPoints.getStart() * samplerSound->getSample()->getSampleRate()); loopBegin.setTargetValue (loopPoints.getStart() * samplerSound->getSample()->getSampleRate());
loopEnd .setValue (loopPoints.getEnd() * samplerSound->getSample()->getSampleRate()); loopEnd .setTargetValue (loopPoints.getEnd() * samplerSound->getSample()->getSampleRate());
for (auto smoothed : { &level, &frequency, &loopBegin, &loopEnd }) for (auto smoothed : { &level, &frequency, &loopBegin, &loopEnd })
smoothed->reset (currentSampleRate, smoothingLengthInSeconds); smoothed->reset (currentSampleRate, smoothingLengthInSeconds);
@ -276,12 +276,12 @@ public:
void notePressureChanged() override void notePressureChanged() override
{ {
level.setValue (currentlyPlayingNote.pressure.asUnsignedFloat()); level.setTargetValue (currentlyPlayingNote.pressure.asUnsignedFloat());
} }
void notePitchbendChanged() override void notePitchbendChanged() override
{ {
frequency.setValue (currentlyPlayingNote.getFrequencyInHertz()); frequency.setTargetValue (currentlyPlayingNote.getFrequencyInHertz());
} }
void noteTimbreChanged() override {} void noteTimbreChanged() override {}
@ -294,8 +294,8 @@ public:
jassert (samplerSound->getSample() != nullptr); jassert (samplerSound->getSample() != nullptr);
auto loopPoints = samplerSound->getLoopPointsInSeconds(); auto loopPoints = samplerSound->getLoopPointsInSeconds();
loopBegin.setValue (loopPoints.getStart() * samplerSound->getSample()->getSampleRate()); loopBegin.setTargetValue (loopPoints.getStart() * samplerSound->getSample()->getSampleRate());
loopEnd .setValue (loopPoints.getEnd() * samplerSound->getSample()->getSampleRate()); loopEnd .setTargetValue (loopPoints.getEnd() * samplerSound->getSample()->getSampleRate());
auto& data = samplerSound->getSample()->getBuffer(); auto& data = samplerSound->getSample()->getBuffer();

View file

@ -26,7 +26,7 @@ namespace juce
//============================================================================== //==============================================================================
/** /**
Utility class for linearly smoothed values like volume etc. that should Utility class for linearly smoothed values like volume etc. that should
not change abruptly but as a linear ramp, to avoid audio glitches. not change abruptly but as a linear ramp to avoid audio glitches.
@tags{Audio} @tags{Audio}
*/ */
@ -44,43 +44,50 @@ public:
} }
//============================================================================== //==============================================================================
/** Reset to a new sample rate and ramp length. /** Set a new sample rate and ramp length in seconds.
@param sampleRate The sampling rate @param sampleRate The sampling rate
@param rampLengthInSeconds The duration of the ramp in seconds @param rampLengthInSeconds The duration of the ramp in seconds
*/ */
void reset (double sampleRate, double rampLengthInSeconds) noexcept void reset (double sampleRate, double rampLengthInSeconds) noexcept
{ {
jassert (sampleRate > 0 && rampLengthInSeconds >= 0); jassert (sampleRate > 0 && rampLengthInSeconds >= 0);
stepsToTarget = (int) std::floor (rampLengthInSeconds * sampleRate); reset ((int) std::floor (rampLengthInSeconds * sampleRate));
currentValue = target;
countdown = 0;
} }
//============================================================================== /** Set a new ramp length directly in samples.
/** Set a new target value. @param numSteps The number of samples over which the ramp should be active
@param newValue The new target value
@param force If true, the value will be set immediately, bypassing the ramp
*/ */
void setValue (FloatType newValue, bool force = false) noexcept void reset (int numSteps) noexcept
{ {
if (force) stepsToTarget = numSteps;
setCurrentValueToTargetValue();
}
/** Set the next value to ramp towards.
@param newValue The new target value
*/
void setTargetValue (FloatType newValue) noexcept
{
if (target == newValue)
return;
target = newValue;
if (stepsToTarget <= 0)
{ {
target = currentValue = newValue; setCurrentValueToTargetValue();
countdown = 0;
return; return;
} }
if (target != newValue) countdown = stepsToTarget;
{ step = (target - currentValue) / static_cast<FloatType> (countdown);
target = newValue; }
countdown = stepsToTarget;
if (countdown <= 0) /** Sets the current value to the target value. */
currentValue = target; void setCurrentValueToTargetValue() noexcept
else {
step = (target - currentValue) / (FloatType) countdown; currentValue = target;
} countdown = 0;
} }
//============================================================================== //==============================================================================
@ -89,7 +96,7 @@ public:
*/ */
FloatType getNextValue() noexcept FloatType getNextValue() noexcept
{ {
if (countdown <= 0) if (! isSmoothing())
return target; return target;
--countdown; --countdown;
@ -98,16 +105,13 @@ public:
} }
/** Returns true if the current value is currently being interpolated. */ /** Returns true if the current value is currently being interpolated. */
bool isSmoothing() const noexcept bool isSmoothing() const noexcept { return countdown > 0; }
{
return countdown > 0; /** Returns the current value of the ramp. */
} FloatType getCurrentValue() const noexcept { return currentValue; }
/** Returns the target value towards which the smoothed value is currently moving. */ /** Returns the target value towards which the smoothed value is currently moving. */
FloatType getTargetValue() const noexcept FloatType getTargetValue() const noexcept { return target; }
{
return target;
}
//============================================================================== //==============================================================================
/** Applies a linear smoothed gain to a stream of samples /** Applies a linear smoothed gain to a stream of samples
@ -194,8 +198,7 @@ public:
{ {
if (numSamples >= countdown) if (numSamples >= countdown)
{ {
currentValue = target; setCurrentValueToTargetValue();
countdown = 0;
return target; return target;
} }
@ -204,6 +207,25 @@ public:
return currentValue; return currentValue;
} }
//==============================================================================
/** THIS FUNCTION IS DEPRECATED.
Use `setTargetValue (float)` and `setCurrentValueToTargetValue()` instead:
lsv.setValue (x, false); -> lsv.setTargetValue (x);
lsv.setValue (x, true); -> lsv.setTargetValue (x); lsv.setCurrentValueToTargetValue();
@param newValue The new target value
@param force If true, the value will be set immediately, bypassing the ramp
*/
JUCE_DEPRECATED_WITH_BODY (void setValue (FloatType newValue, bool force = false) noexcept,
{
setTargetValue (newValue);
if (force)
setCurrentValueToTargetValue();
})
private: private:
//============================================================================== //==============================================================================
FloatType currentValue = 0, target = 0, step = 0; FloatType currentValue = 0, target = 0, step = 0;

View file

@ -72,9 +72,9 @@ public:
const float dryScaleFactor = 2.0f; const float dryScaleFactor = 2.0f;
const float wet = newParams.wetLevel * wetScaleFactor; const float wet = newParams.wetLevel * wetScaleFactor;
dryGain.setValue (newParams.dryLevel * dryScaleFactor); dryGain.setTargetValue (newParams.dryLevel * dryScaleFactor);
wetGain1.setValue (0.5f * wet * (1.0f + newParams.width)); wetGain1.setTargetValue (0.5f * wet * (1.0f + newParams.width));
wetGain2.setValue (0.5f * wet * (1.0f - newParams.width)); wetGain2.setTargetValue (0.5f * wet * (1.0f - newParams.width));
gain = isFrozen (newParams.freezeMode) ? 0.0f : 0.015f; gain = isFrozen (newParams.freezeMode) ? 0.0f : 0.015f;
parameters = newParams; parameters = newParams;
@ -207,8 +207,8 @@ private:
void setDamping (const float dampingToUse, const float roomSizeToUse) noexcept void setDamping (const float dampingToUse, const float roomSizeToUse) noexcept
{ {
damping.setValue (dampingToUse); damping.setTargetValue (dampingToUse);
feedback.setValue (roomSizeToUse); feedback.setTargetValue (roomSizeToUse);
} }
//============================================================================== //==============================================================================

View file

@ -1006,13 +1006,13 @@ private:
for (auto i = 0; i < 2; ++i) for (auto i = 0; i < 2; ++i)
{ {
changeVolumes[i].setValue (1.0f); changeVolumes[i].setTargetValue (1.0f);
changeVolumes[i].reset (currentInfo.sampleRate, 0.05); changeVolumes[i].reset (currentInfo.sampleRate, 0.05);
changeVolumes[i].setValue (0.0f); changeVolumes[i].setTargetValue (0.0f);
changeVolumes[i + 2].setValue (0.0f); changeVolumes[i + 2].setTargetValue (0.0f);
changeVolumes[i + 2].reset (currentInfo.sampleRate, 0.05); changeVolumes[i + 2].reset (currentInfo.sampleRate, 0.05);
changeVolumes[i + 2].setValue (1.0f); changeVolumes[i + 2].setTargetValue (1.0f);
} }
@ -1235,13 +1235,13 @@ void Convolution::processSamples (const AudioBlock<float>& input, AudioBlock<flo
for (size_t channel = 0; channel < numChannels; ++channel) for (size_t channel = 0; channel < numChannels; ++channel)
{ {
volumeDry[channel].setValue (isBypassed ? 0.0f : 1.0f); volumeDry[channel].setTargetValue (isBypassed ? 0.0f : 1.0f);
volumeDry[channel].reset (sampleRate, 0.05); volumeDry[channel].reset (sampleRate, 0.05);
volumeDry[channel].setValue (isBypassed ? 1.0f : 0.0f); volumeDry[channel].setTargetValue (isBypassed ? 1.0f : 0.0f);
volumeWet[channel].setValue (isBypassed ? 1.0f : 0.0f); volumeWet[channel].setTargetValue (isBypassed ? 1.0f : 0.0f);
volumeWet[channel].reset (sampleRate, 0.05); volumeWet[channel].reset (sampleRate, 0.05);
volumeWet[channel].setValue (isBypassed ? 0.0f : 1.0f); volumeWet[channel].setTargetValue (isBypassed ? 0.0f : 1.0f);
} }
} }
} }

View file

@ -53,7 +53,7 @@ public:
void setBias (FloatType newBias) noexcept void setBias (FloatType newBias) noexcept
{ {
jassert (newBias >= static_cast<FloatType> (-1) && newBias <= static_cast<FloatType> (1)); jassert (newBias >= static_cast<FloatType> (-1) && newBias <= static_cast<FloatType> (1));
bias.setValue(newBias); bias.setTargetValue (newBias);
} }
//============================================================================== //==============================================================================

View file

@ -42,7 +42,7 @@ public:
//============================================================================== //==============================================================================
/** Applies a new gain as a linear value. */ /** Applies a new gain as a linear value. */
void setGainLinear (FloatType newGain) noexcept { gain.setValue (newGain); } void setGainLinear (FloatType newGain) noexcept { gain.setTargetValue (newGain); }
/** Applies a new gain as a decibel value. */ /** Applies a new gain as a decibel value. */
void setGainDecibels (FloatType newGainDecibels) noexcept { setGainLinear (Decibels::decibelsToGain<FloatType> (newGainDecibels)); } void setGainDecibels (FloatType newGainDecibels) noexcept { setGainLinear (Decibels::decibelsToGain<FloatType> (newGainDecibels)); }

View file

@ -78,8 +78,8 @@ void LadderFilter<Type>::reset() noexcept
for (auto& s : state) for (auto& s : state)
s.fill (Type (0)); s.fill (Type (0));
cutoffTransformSmoother.setValue (cutoffTransformSmoother.getTargetValue(), true); cutoffTransformSmoother.setCurrentValueToTargetValue();
scaledResonanceSmoother.setValue (scaledResonanceSmoother.getTargetValue(), true); scaledResonanceSmoother.setCurrentValueToTargetValue();
} }
//============================================================================== //==============================================================================

View file

@ -118,10 +118,8 @@ private:
std::vector<std::array<Type, numStates>> state; std::vector<std::array<Type, numStates>> state;
std::array<Type, numStates> A; std::array<Type, numStates> A;
LinearSmoothedValue<Type> cutoffTransformSmoother; LinearSmoothedValue<Type> cutoffTransformSmoother, scaledResonanceSmoother;
LinearSmoothedValue<Type> scaledResonanceSmoother; Type cutoffTransformValue, scaledResonanceValue;
Type cutoffTransformValue;
Type scaledResonanceValue;
LookupTableTransform<Type> saturationLUT { [] (Type x) { return std::tanh (x); }, Type (-5), Type (5), 128 }; LookupTableTransform<Type> saturationLUT { [] (Type x) { return std::tanh (x); }, Type (-5), Type (5), 128 };
@ -136,8 +134,8 @@ private:
//============================================================================== //==============================================================================
void setSampleRate (Type newValue) noexcept; void setSampleRate (Type newValue) noexcept;
void setNumChannels (size_t newValue) { state.resize (newValue); } void setNumChannels (size_t newValue) { state.resize (newValue); }
void updateCutoffFreq() noexcept { cutoffTransformSmoother.setValue (std::exp (cutoffFreqHz * cutoffFreqScaler)); } void updateCutoffFreq() noexcept { cutoffTransformSmoother.setTargetValue (std::exp (cutoffFreqHz * cutoffFreqScaler)); }
void updateResonance() noexcept { scaledResonanceSmoother.setValue (jmap (resonance, Type (0.1), Type (1.0))); } void updateResonance() noexcept { scaledResonanceSmoother.setTargetValue (jmap (resonance, Type (0.1), Type (1.0))); }
}; };
} // namespace dsp } // namespace dsp

View file

@ -82,7 +82,13 @@ public:
//============================================================================== //==============================================================================
/** Sets the frequency of the oscillator. */ /** Sets the frequency of the oscillator. */
void setFrequency (NumericType newFrequency, bool force = false) noexcept { frequency.setValue (newFrequency, force); } void setFrequency (NumericType newFrequency, bool force = false) noexcept
{
frequency.setTargetValue (newFrequency);
if (force)
frequency.setCurrentValueToTargetValue();
}
/** Returns the current frequency of the oscillator. */ /** Returns the current frequency of the oscillator. */
NumericType getFrequency() const noexcept { return frequency.getTargetValue(); } NumericType getFrequency() const noexcept { return frequency.getTargetValue(); }