Make ADSREnvelope not a template
This commit is contained in:
parent
9629fcad63
commit
9cb0a457a5
10 changed files with 62 additions and 104 deletions
|
|
@ -36,7 +36,7 @@ public:
|
|||
|
||||
sfz::MidiState midiState;
|
||||
sfz::Region region{0, midiState};
|
||||
sfz::ADSREnvelope<float> envelope;
|
||||
sfz::ADSREnvelope envelope;
|
||||
std::vector<float> output;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ SFIZZ_SOURCES = \
|
|||
src/sfizz/FilterPool.cpp \
|
||||
src/sfizz/FlexEGDescription.cpp \
|
||||
src/sfizz/FlexEnvelope.cpp \
|
||||
src/sfizz/FloatEnvelopes.cpp \
|
||||
src/sfizz/Interpolators.cpp \
|
||||
src/sfizz/Logger.cpp \
|
||||
src/sfizz/LFO.cpp \
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ set(SFIZZ_SOURCES
|
|||
sfizz/MidiState.cpp
|
||||
sfizz/SfzHelpers.cpp
|
||||
sfizz/Oversampler.cpp
|
||||
sfizz/FloatEnvelopes.cpp
|
||||
sfizz/ADSREnvelope.cpp
|
||||
sfizz/Logger.cpp
|
||||
sfizz/SfzFilter.cpp
|
||||
sfizz/Curve.cpp
|
||||
|
|
|
|||
|
|
@ -11,33 +11,31 @@
|
|||
|
||||
namespace sfz {
|
||||
|
||||
template<class Type>
|
||||
Type ADSREnvelope<Type>::secondsToSamples (Type timeInSeconds) const noexcept
|
||||
using Float = ADSREnvelope::Float;
|
||||
|
||||
Float ADSREnvelope::secondsToSamples(Float timeInSeconds) const noexcept
|
||||
{
|
||||
return static_cast<int>(timeInSeconds * sampleRate);
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
Type ADSREnvelope<Type>::secondsToLinRate (Type timeInSeconds) const noexcept
|
||||
Float ADSREnvelope::secondsToLinRate(Float timeInSeconds) const noexcept
|
||||
{
|
||||
if (timeInSeconds == 0)
|
||||
return 1.0f;
|
||||
return Float(1);
|
||||
|
||||
return 1 / (sampleRate * timeInSeconds);
|
||||
};
|
||||
|
||||
template<class Type>
|
||||
Type ADSREnvelope<Type>::secondsToExpRate (Type timeInSeconds) const noexcept
|
||||
Float ADSREnvelope::secondsToExpRate(Float timeInSeconds) const noexcept
|
||||
{
|
||||
if (timeInSeconds == 0)
|
||||
return 0.0f;
|
||||
return Float(0.0);
|
||||
|
||||
timeInSeconds = std::max<Type>(25e-3, timeInSeconds);
|
||||
return std::exp(-9.0 / (timeInSeconds * sampleRate));
|
||||
timeInSeconds = std::max(Float(25e-3), timeInSeconds);
|
||||
return std::exp(Float(-9.0) / (timeInSeconds * sampleRate));
|
||||
};
|
||||
|
||||
template <class Type>
|
||||
void ADSREnvelope<Type>::reset(const EGDescription& desc, const Region& region, const MidiState& state, int delay, float velocity, float sampleRate) noexcept
|
||||
void ADSREnvelope::reset(const EGDescription& desc, const Region& region, const MidiState& state, int delay, float velocity, float sampleRate) noexcept
|
||||
{
|
||||
this->sampleRate = sampleRate;
|
||||
|
||||
|
|
@ -54,15 +52,14 @@ void ADSREnvelope<Type>::reset(const EGDescription& desc, const Region& region,
|
|||
sustainThreshold = this->sustain + config::virtuallyZero;
|
||||
shouldRelease = false;
|
||||
freeRunning = (
|
||||
(this->sustain == 0.0f)
|
||||
(this->sustain == Float(0.0))
|
||||
|| (region.loopMode == SfzLoopMode::one_shot && region.isOscillator())
|
||||
);
|
||||
currentValue = this->start;
|
||||
currentState = State::Delay;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
Type ADSREnvelope<Type>::getNextValue() noexcept
|
||||
Float ADSREnvelope::getNextValue() noexcept
|
||||
{
|
||||
if (shouldRelease && releaseDelay-- == 0)
|
||||
currentState = State::Release;
|
||||
|
|
@ -113,11 +110,10 @@ Type ADSREnvelope<Type>::getNextValue() noexcept
|
|||
}
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void ADSREnvelope<Type>::getBlock(absl::Span<Type> output) noexcept
|
||||
void ADSREnvelope::getBlock(absl::Span<Float> output) noexcept
|
||||
{
|
||||
State currentState = this->currentState;
|
||||
Type currentValue = this->currentValue;
|
||||
Float currentValue = this->currentValue;
|
||||
bool shouldRelease = this->shouldRelease;
|
||||
int releaseDelay = this->releaseDelay;
|
||||
|
||||
|
|
@ -203,33 +199,13 @@ void ADSREnvelope<Type>::getBlock(absl::Span<Type> output) noexcept
|
|||
ASSERT(!hasNanInf(output));
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
bool ADSREnvelope<Type>::isSmoothing() const noexcept
|
||||
{
|
||||
return (currentState != State::Done);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
bool ADSREnvelope<Type>::isReleased() const noexcept
|
||||
{
|
||||
return (currentState == State::Release) || shouldRelease;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
int ADSREnvelope<Type>::getRemainingDelay() const noexcept
|
||||
{
|
||||
return delay;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void ADSREnvelope<Type>::startRelease(int releaseDelay) noexcept
|
||||
void ADSREnvelope::startRelease(int releaseDelay) noexcept
|
||||
{
|
||||
shouldRelease = true;
|
||||
this->releaseDelay = releaseDelay;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
void ADSREnvelope<Type>::setReleaseTime(Type timeInSeconds) noexcept
|
||||
void ADSREnvelope::setReleaseTime(Float timeInSeconds) noexcept
|
||||
{
|
||||
releaseRate = secondsToExpRate(timeInSeconds);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,12 +13,11 @@ namespace sfz {
|
|||
/**
|
||||
* @brief Describe an attack/delay/sustain/release envelope that can
|
||||
* produce its coefficient in a blockwise manner for SIMD-type operations.
|
||||
*
|
||||
* @tparam Type the underlying type
|
||||
*/
|
||||
template <class Type>
|
||||
class ADSREnvelope {
|
||||
public:
|
||||
using Float = float;
|
||||
|
||||
ADSREnvelope() = default;
|
||||
/**
|
||||
* @brief Resets the ADSR envelope given a Region, the current midi state, and a delay and
|
||||
|
|
@ -34,22 +33,22 @@ public:
|
|||
/**
|
||||
* @brief Get the next value for the envelope
|
||||
*
|
||||
* @return Type
|
||||
* @return Float
|
||||
*/
|
||||
Type getNextValue() noexcept;
|
||||
Float getNextValue() noexcept;
|
||||
/**
|
||||
* @brief Get a block of values for the envelope. This method tries hard to be efficient
|
||||
* and hopefully it is.
|
||||
*
|
||||
* @param output
|
||||
*/
|
||||
void getBlock(absl::Span<Type> output) noexcept;
|
||||
void getBlock(absl::Span<Float> output) noexcept;
|
||||
/**
|
||||
* @brief Set the release time for the envelope
|
||||
*
|
||||
* @param timeInSeconds
|
||||
*/
|
||||
void setReleaseTime(Type timeInSeconds) noexcept;
|
||||
void setReleaseTime(Float timeInSeconds) noexcept;
|
||||
/**
|
||||
* @brief Start the envelope release after a delay.
|
||||
*
|
||||
|
|
@ -62,26 +61,26 @@ public:
|
|||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool isSmoothing() const noexcept;
|
||||
bool isSmoothing() const noexcept { return currentState != State::Done; }
|
||||
/**
|
||||
* @brief Is the envelope released?
|
||||
*
|
||||
* @return true
|
||||
* @return false
|
||||
*/
|
||||
bool isReleased() const noexcept;
|
||||
bool isReleased() const noexcept { return currentState == State::Release || shouldRelease; }
|
||||
/**
|
||||
* @brief Get the remaining delay samples
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int getRemainingDelay() const noexcept;
|
||||
int getRemainingDelay() const noexcept { return delay; }
|
||||
|
||||
private:
|
||||
float sampleRate { config::defaultSampleRate };
|
||||
Type secondsToSamples (Type timeInSeconds) const noexcept;
|
||||
Type secondsToLinRate (Type timeInSeconds) const noexcept;
|
||||
Type secondsToExpRate (Type timeInSeconds) const noexcept;
|
||||
Float secondsToSamples(Float timeInSeconds) const noexcept;
|
||||
Float secondsToLinRate(Float timeInSeconds) const noexcept;
|
||||
Float secondsToExpRate(Float timeInSeconds) const noexcept;
|
||||
|
||||
enum class State {
|
||||
Delay,
|
||||
|
|
@ -93,16 +92,16 @@ private:
|
|||
Done
|
||||
};
|
||||
State currentState { State::Done };
|
||||
Type currentValue { 0.0 };
|
||||
Float currentValue { 0.0 };
|
||||
int delay { 0 };
|
||||
Type attackStep { 0 };
|
||||
Type decayRate { 0 };
|
||||
Type releaseRate { 0 };
|
||||
Float attackStep { 0 };
|
||||
Float decayRate { 0 };
|
||||
Float releaseRate { 0 };
|
||||
int hold { 0 };
|
||||
Type start { 0 };
|
||||
Type peak { 0 };
|
||||
Type sustain { 0 };
|
||||
Type sustainThreshold { config::virtuallyZero };
|
||||
Float start { 0 };
|
||||
Float peak { 0 };
|
||||
Float sustain { 0 };
|
||||
Float sustainThreshold { config::virtuallyZero };
|
||||
int releaseDelay { 0 };
|
||||
bool shouldRelease { false };
|
||||
bool freeRunning { false };
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
||||
|
||||
// This code is part of the sfizz library and is licensed under a BSD 2-clause
|
||||
// license. You should have receive a LICENSE.md file along with the code.
|
||||
// If not, contact the sfizz maintainers at https://github.com/sfztools/sfizz
|
||||
|
||||
#include "ADSREnvelope.h"
|
||||
|
||||
// Include the generic implementations
|
||||
#include "ADSREnvelope.cpp"
|
||||
|
||||
// And explicitely instantiate the float version
|
||||
namespace sfz
|
||||
{
|
||||
template class ADSREnvelope<float>;
|
||||
}
|
||||
|
|
@ -213,9 +213,9 @@ struct Voice::Impl
|
|||
std::vector<std::unique_ptr<LFO>> lfos_;
|
||||
std::vector<std::unique_ptr<FlexEnvelope>> flexEGs_;
|
||||
|
||||
ADSREnvelope<float> egAmplitude_;
|
||||
std::unique_ptr<ADSREnvelope<float>> egPitch_;
|
||||
std::unique_ptr<ADSREnvelope<float>> egFilter_;
|
||||
ADSREnvelope egAmplitude_;
|
||||
std::unique_ptr<ADSREnvelope> egPitch_;
|
||||
std::unique_ptr<ADSREnvelope> egFilter_;
|
||||
float bendStepFactor_ { centsFactor(1) };
|
||||
|
||||
WavetableOscillator waveOscillators_[config::oscillatorsPerVoice];
|
||||
|
|
@ -1553,7 +1553,7 @@ void Voice::setPitchEGEnabledPerVoice(bool havePitchEG)
|
|||
{
|
||||
Impl& impl = *impl_;
|
||||
if (havePitchEG)
|
||||
impl.egPitch_.reset(new ADSREnvelope<float>);
|
||||
impl.egPitch_.reset(new ADSREnvelope);
|
||||
else
|
||||
impl.egPitch_.reset();
|
||||
}
|
||||
|
|
@ -1562,7 +1562,7 @@ void Voice::setFilterEGEnabledPerVoice(bool haveFilterEG)
|
|||
{
|
||||
Impl& impl = *impl_;
|
||||
if (haveFilterEG)
|
||||
impl.egFilter_.reset(new ADSREnvelope<float>);
|
||||
impl.egFilter_.reset(new ADSREnvelope);
|
||||
else
|
||||
impl.egFilter_.reset();
|
||||
}
|
||||
|
|
@ -1782,19 +1782,19 @@ Duration Voice::getLastPanningDuration() const noexcept
|
|||
return impl.panningDuration_;
|
||||
}
|
||||
|
||||
ADSREnvelope<float>* Voice::getAmplitudeEG()
|
||||
ADSREnvelope* Voice::getAmplitudeEG()
|
||||
{
|
||||
Impl& impl = *impl_;
|
||||
return &impl.egAmplitude_;
|
||||
}
|
||||
|
||||
ADSREnvelope<float>* Voice::getPitchEG()
|
||||
ADSREnvelope* Voice::getPitchEG()
|
||||
{
|
||||
Impl& impl = *impl_;
|
||||
return impl.egPitch_.get();
|
||||
}
|
||||
|
||||
ADSREnvelope<float>* Voice::getFilterEG()
|
||||
ADSREnvelope* Voice::getFilterEG()
|
||||
{
|
||||
Impl& impl = *impl_;
|
||||
return impl.egFilter_.get();
|
||||
|
|
|
|||
|
|
@ -337,15 +337,15 @@ public:
|
|||
/**
|
||||
* @brief Get the SFZv1 amplitude EG, if existing
|
||||
*/
|
||||
ADSREnvelope<float>* getAmplitudeEG();
|
||||
ADSREnvelope* getAmplitudeEG();
|
||||
/**
|
||||
* @brief Get the SFZv1 pitch EG, if existing
|
||||
*/
|
||||
ADSREnvelope<float>* getPitchEG();
|
||||
ADSREnvelope* getPitchEG();
|
||||
/**
|
||||
* @brief Get the SFZv1 filter EG, if existing
|
||||
*/
|
||||
ADSREnvelope<float>* getFilterEG();
|
||||
ADSREnvelope* getFilterEG();
|
||||
|
||||
/**
|
||||
* @brief Get the trigger event
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ void ADSREnvelopeSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId,
|
|||
}
|
||||
|
||||
const Region* region = voice->getRegion();
|
||||
ADSREnvelope<float>* eg = nullptr;
|
||||
ADSREnvelope* eg = nullptr;
|
||||
const EGDescription* desc = nullptr;
|
||||
|
||||
switch (sourceKey.id()) {
|
||||
|
|
@ -66,7 +66,7 @@ void ADSREnvelopeSource::release(const ModKey& sourceKey, NumericId<Voice> voice
|
|||
return;
|
||||
}
|
||||
|
||||
ADSREnvelope<float>* eg = nullptr;
|
||||
ADSREnvelope* eg = nullptr;
|
||||
|
||||
switch (sourceKey.id()) {
|
||||
case ModId::AmpEG:
|
||||
|
|
@ -97,7 +97,7 @@ void ADSREnvelopeSource::generate(const ModKey& sourceKey, NumericId<Voice> voic
|
|||
return;
|
||||
}
|
||||
|
||||
ADSREnvelope<float>* eg = nullptr;
|
||||
ADSREnvelope* eg = nullptr;
|
||||
|
||||
switch (sourceKey.id()) {
|
||||
case ModId::AmpEG:
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ using namespace Catch::literals;
|
|||
|
||||
TEST_CASE("[ADSREnvelope] Basic state")
|
||||
{
|
||||
sfz::ADSREnvelope<float> envelope;
|
||||
sfz::ADSREnvelope envelope;
|
||||
std::array<float, 5> output;
|
||||
std::array<float, 5> expected { 0.0, 0.0, 0.0, 0.0, 0.0 };
|
||||
envelope.getBlock(absl::MakeSpan(output));
|
||||
|
|
@ -29,7 +29,7 @@ TEST_CASE("[ADSREnvelope] Basic state")
|
|||
|
||||
TEST_CASE("[ADSREnvelope] Attack")
|
||||
{
|
||||
sfz::ADSREnvelope<float> envelope;
|
||||
sfz::ADSREnvelope envelope;
|
||||
sfz::MidiState state;
|
||||
sfz::Region region { state };
|
||||
region.amplitudeEG.attack = 0.02f;
|
||||
|
|
@ -48,7 +48,7 @@ TEST_CASE("[ADSREnvelope] Attack")
|
|||
|
||||
TEST_CASE("[ADSREnvelope] Attack again")
|
||||
{
|
||||
sfz::ADSREnvelope<float> envelope;
|
||||
sfz::ADSREnvelope envelope;
|
||||
sfz::MidiState state;
|
||||
sfz::Region region { state };
|
||||
region.amplitudeEG.attack = 0.03f;
|
||||
|
|
@ -67,7 +67,7 @@ TEST_CASE("[ADSREnvelope] Attack again")
|
|||
|
||||
TEST_CASE("[ADSREnvelope] Release")
|
||||
{
|
||||
sfz::ADSREnvelope<float> envelope;
|
||||
sfz::ADSREnvelope envelope;
|
||||
sfz::MidiState state;
|
||||
sfz::Region region { state };
|
||||
region.amplitudeEG.attack = 0.02f;
|
||||
|
|
@ -89,7 +89,7 @@ TEST_CASE("[ADSREnvelope] Release")
|
|||
|
||||
TEST_CASE("[ADSREnvelope] Delay")
|
||||
{
|
||||
sfz::ADSREnvelope<float> envelope;
|
||||
sfz::ADSREnvelope envelope;
|
||||
sfz::MidiState state;
|
||||
sfz::Region region { state };
|
||||
region.amplitudeEG.attack = 0.02f;
|
||||
|
|
@ -111,7 +111,7 @@ TEST_CASE("[ADSREnvelope] Delay")
|
|||
|
||||
TEST_CASE("[ADSREnvelope] Lower sustain")
|
||||
{
|
||||
sfz::ADSREnvelope<float> envelope;
|
||||
sfz::ADSREnvelope envelope;
|
||||
sfz::MidiState state;
|
||||
sfz::Region region { state };
|
||||
region.amplitudeEG.attack = 0.02f;
|
||||
|
|
@ -132,7 +132,7 @@ TEST_CASE("[ADSREnvelope] Lower sustain")
|
|||
|
||||
TEST_CASE("[ADSREnvelope] Decay")
|
||||
{
|
||||
sfz::ADSREnvelope<float> envelope;
|
||||
sfz::ADSREnvelope envelope;
|
||||
sfz::MidiState state;
|
||||
sfz::Region region { state };
|
||||
region.amplitudeEG.attack = 0.02f;
|
||||
|
|
@ -154,7 +154,7 @@ TEST_CASE("[ADSREnvelope] Decay")
|
|||
|
||||
TEST_CASE("[ADSREnvelope] Hold")
|
||||
{
|
||||
sfz::ADSREnvelope<float> envelope;
|
||||
sfz::ADSREnvelope envelope;
|
||||
sfz::MidiState state;
|
||||
sfz::Region region { state };
|
||||
region.amplitudeEG.attack = 0.02f;
|
||||
|
|
@ -177,7 +177,7 @@ TEST_CASE("[ADSREnvelope] Hold")
|
|||
|
||||
TEST_CASE("[ADSREnvelope] Hold with release")
|
||||
{
|
||||
sfz::ADSREnvelope<float> envelope;
|
||||
sfz::ADSREnvelope envelope;
|
||||
sfz::MidiState state;
|
||||
sfz::Region region { state };
|
||||
region.amplitudeEG.attack = 0.02f;
|
||||
|
|
@ -202,7 +202,7 @@ TEST_CASE("[ADSREnvelope] Hold with release")
|
|||
|
||||
TEST_CASE("[ADSREnvelope] Hold with release 2")
|
||||
{
|
||||
sfz::ADSREnvelope<float> envelope;
|
||||
sfz::ADSREnvelope envelope;
|
||||
sfz::MidiState state;
|
||||
sfz::Region region { state };
|
||||
region.amplitudeEG.attack = 0.02f;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue