Browse Source

LinearSmoothedValue: Added some helpful member functions and deprecated setValue

tags/2021-05-28
reuk Tom Poole 6 years ago
parent
commit
b8278cec0e
11 changed files with 103 additions and 77 deletions
  1. +6
    -6
      examples/Audio/MPEDemo.h
  2. +5
    -5
      examples/BLOCKS/BlocksSynthDemo.h
  3. +8
    -8
      examples/Plugins/SamplerPluginDemo.h
  4. +56
    -34
      modules/juce_audio_basics/utilities/juce_LinearSmoothedValue.h
  5. +5
    -5
      modules/juce_audio_basics/utilities/juce_Reverb.h
  6. +8
    -8
      modules/juce_dsp/frequency/juce_Convolution.cpp
  7. +1
    -1
      modules/juce_dsp/processors/juce_Bias.h
  8. +1
    -1
      modules/juce_dsp/processors/juce_Gain.h
  9. +2
    -2
      modules/juce_dsp/processors/juce_LadderFilter.cpp
  10. +4
    -6
      modules/juce_dsp/processors/juce_LadderFilter.h
  11. +7
    -1
      modules/juce_dsp/processors/juce_Oscillator.h

+ 6
- 6
examples/Audio/MPEDemo.h View File

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


+ 5
- 5
examples/BLOCKS/BlocksSynthDemo.h View File

@@ -65,8 +65,8 @@ public:
void startNote (int midiNoteNumber, float velocity, SynthesiserSound*, int) override
{
frequency = MidiMessage::getMidiNoteInHertz (midiNoteNumber);
phaseIncrement.setValue (((MathConstants<double>::twoPi) * frequency) / sampleRate);
amplitude.setValue (velocity);
phaseIncrement.setTargetValue (((MathConstants<double>::twoPi) * frequency) / sampleRate);
amplitude.setTargetValue (velocity);
// Store the initial note and work out the maximum frequency deviations for pitch bend
initialNote = midiNoteNumber;
@@ -77,14 +77,14 @@ public:
void stopNote (float, bool) override
{
clearCurrentNote();
amplitude.setValue (0.0);
amplitude.setTargetValue (0.0);
}
void pitchWheelMoved (int newValue) override
{
// Change the phase increment based on pitch bend amount
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 {}
@@ -92,7 +92,7 @@ public:
void channelPressureChanged (int newChannelPressureValue) override
{
// 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


+ 8
- 8
examples/Plugins/SamplerPluginDemo.h View File

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


+ 56
- 34
modules/juce_audio_basics/utilities/juce_LinearSmoothedValue.h View File

@@ -26,7 +26,7 @@ namespace juce
//==============================================================================
/**
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}
*/
@@ -44,43 +44,50 @@ public:
}
//==============================================================================
/** Reset to a new sample rate and ramp length.
@param sampleRate The sampling rate
@param rampLengthInSeconds The duration of the ramp in seconds
/** Set a new sample rate and ramp length in seconds.
@param sampleRate The sampling rate
@param rampLengthInSeconds The duration of the ramp in seconds
*/
void reset (double sampleRate, double rampLengthInSeconds) noexcept
{
jassert (sampleRate > 0 && rampLengthInSeconds >= 0);
stepsToTarget = (int) std::floor (rampLengthInSeconds * sampleRate);
currentValue = target;
countdown = 0;
reset ((int) std::floor (rampLengthInSeconds * sampleRate));
}
//==============================================================================
/** Set a new target value.
/** Set a new ramp length directly in samples.
@param numSteps The number of samples over which the ramp should be active
*/
void reset (int numSteps) noexcept
{
stepsToTarget = numSteps;
setCurrentValueToTargetValue();
}
/** Set the next value to ramp towards.
@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 setTargetValue (FloatType newValue) noexcept
{
if (force)
if (target == newValue)
return;
target = newValue;
if (stepsToTarget <= 0)
{
target = currentValue = newValue;
countdown = 0;
setCurrentValueToTargetValue();
return;
}
if (target != newValue)
{
target = newValue;
countdown = stepsToTarget;
countdown = stepsToTarget;
step = (target - currentValue) / static_cast<FloatType> (countdown);
}
if (countdown <= 0)
currentValue = target;
else
step = (target - currentValue) / (FloatType) countdown;
}
/** Sets the current value to the target value. */
void setCurrentValueToTargetValue() noexcept
{
currentValue = target;
countdown = 0;
}
//==============================================================================
@@ -89,7 +96,7 @@ public:
*/
FloatType getNextValue() noexcept
{
if (countdown <= 0)
if (! isSmoothing())
return target;
--countdown;
@@ -98,16 +105,13 @@ public:
}
/** Returns true if the current value is currently being interpolated. */
bool isSmoothing() const noexcept
{
return countdown > 0;
}
bool isSmoothing() const noexcept { 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. */
FloatType getTargetValue() const noexcept
{
return target;
}
FloatType getTargetValue() const noexcept { return target; }
//==============================================================================
/** Applies a linear smoothed gain to a stream of samples
@@ -194,8 +198,7 @@ public:
{
if (numSamples >= countdown)
{
currentValue = target;
countdown = 0;
setCurrentValueToTargetValue();
return target;
}
@@ -204,6 +207,25 @@ public:
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:
//==============================================================================
FloatType currentValue = 0, target = 0, step = 0;


+ 5
- 5
modules/juce_audio_basics/utilities/juce_Reverb.h View File

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


+ 8
- 8
modules/juce_dsp/frequency/juce_Convolution.cpp View File

@@ -1006,13 +1006,13 @@ private:
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].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].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)
{
volumeDry[channel].setValue (isBypassed ? 0.0f : 1.0f);
volumeDry[channel].setTargetValue (isBypassed ? 0.0f : 1.0f);
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].setValue (isBypassed ? 0.0f : 1.0f);
volumeWet[channel].setTargetValue (isBypassed ? 0.0f : 1.0f);
}
}
}


+ 1
- 1
modules/juce_dsp/processors/juce_Bias.h View File

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


+ 1
- 1
modules/juce_dsp/processors/juce_Gain.h View File

@@ -42,7 +42,7 @@ public:
//==============================================================================
/** 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. */
void setGainDecibels (FloatType newGainDecibels) noexcept { setGainLinear (Decibels::decibelsToGain<FloatType> (newGainDecibels)); }


+ 2
- 2
modules/juce_dsp/processors/juce_LadderFilter.cpp View File

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


+ 4
- 6
modules/juce_dsp/processors/juce_LadderFilter.h View File

@@ -118,10 +118,8 @@ private:
std::vector<std::array<Type, numStates>> state;
std::array<Type, numStates> A;
LinearSmoothedValue<Type> cutoffTransformSmoother;
LinearSmoothedValue<Type> scaledResonanceSmoother;
Type cutoffTransformValue;
Type scaledResonanceValue;
LinearSmoothedValue<Type> cutoffTransformSmoother, scaledResonanceSmoother;
Type cutoffTransformValue, scaledResonanceValue;
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 setNumChannels (size_t newValue) { state.resize (newValue); }
void updateCutoffFreq() noexcept { cutoffTransformSmoother.setValue (std::exp (cutoffFreqHz * cutoffFreqScaler)); }
void updateResonance() noexcept { scaledResonanceSmoother.setValue (jmap (resonance, Type (0.1), Type (1.0))); }
void updateCutoffFreq() noexcept { cutoffTransformSmoother.setTargetValue (std::exp (cutoffFreqHz * cutoffFreqScaler)); }
void updateResonance() noexcept { scaledResonanceSmoother.setTargetValue (jmap (resonance, Type (0.1), Type (1.0))); }
};
} // namespace dsp


+ 7
- 1
modules/juce_dsp/processors/juce_Oscillator.h View File

@@ -82,7 +82,13 @@ public:
//==============================================================================
/** 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. */
NumericType getFrequency() const noexcept { return frequency.getTargetValue(); }


Loading…
Cancel
Save