Add a way to change the release rate after the envelope started and separate this from the release() method in the Voice

This commit is contained in:
Paul Ferrand 2020-08-10 16:14:55 +02:00
parent d3cc4281d9
commit 5ef6141c4b
4 changed files with 64 additions and 25 deletions

View file

@ -11,22 +11,30 @@
namespace sfz {
template<class Type>
Type ADSREnvelope<Type>::secondsToSamples (Type timeInSeconds) const noexcept
{
return static_cast<int>(timeInSeconds * sampleRate);
};
template<class Type>
Type ADSREnvelope<Type>::secondsToLinRate (Type timeInSeconds) const noexcept
{
timeInSeconds = std::max<Type>(timeInSeconds, config::virtuallyZero);
return 1 / (sampleRate * timeInSeconds);
};
template<class Type>
Type ADSREnvelope<Type>::secondsToExpRate (Type timeInSeconds) const noexcept
{
timeInSeconds = std::max<Type>(25e-3, timeInSeconds);
return std::exp(-8.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
{
auto secondsToSamples = [sampleRate](Type timeInSeconds) {
return static_cast<int>(timeInSeconds * sampleRate);
};
auto secondsToLinRate = [sampleRate](Type timeInSeconds) {
timeInSeconds = std::max<Type>(timeInSeconds, config::virtuallyZero);
return 1 / (sampleRate * timeInSeconds);
};
auto secondsToExpRate = [sampleRate](Type timeInSeconds) {
timeInSeconds = std::max<Type>(25e-3, timeInSeconds);
return std::exp(-8.0 / (timeInSeconds * sampleRate));
};
this->sampleRate = sampleRate;
this->delay = delay + secondsToSamples(desc.getDelay(state, velocity));
this->attackStep = secondsToLinRate(desc.getAttack(state, velocity));
@ -208,13 +216,16 @@ int ADSREnvelope<Type>::getRemainingDelay() const noexcept
}
template <class Type>
void ADSREnvelope<Type>::startRelease(int releaseDelay, bool fastRelease) noexcept
void ADSREnvelope<Type>::startRelease(int releaseDelay) noexcept
{
shouldRelease = true;
this->releaseDelay = releaseDelay;
}
if (fastRelease)
this->releaseRate = 0;
template <class Type>
void ADSREnvelope<Type>::setReleaseTime(Type timeInSeconds) noexcept
{
releaseRate = secondsToExpRate(timeInSeconds);
}
}

View file

@ -44,15 +44,18 @@ public:
* @param output
*/
void getBlock(absl::Span<Type> output) noexcept;
/**
* @brief Set the release time for the envelope
*
* @param timeInSeconds
*/
void setReleaseTime(Type timeInSeconds) noexcept;
/**
* @brief Start the envelope release after a delay.
*
* @param releaseDelay the delay before releasing in samples
* @param fastRelease whether the release should be fast (i.e. 0 or so) or
* follow the release duration that was set when
* initializing the envelope
*/
void startRelease(int releaseDelay, bool fastRelease = false) noexcept;
void startRelease(int releaseDelay) noexcept;
/**
* @brief Is the envelope smoothing?
*
@ -75,6 +78,11 @@ public:
int getRemainingDelay() const noexcept;
private:
float sampleRate { config::defaultSampleRate };
Type secondsToSamples (Type timeInSeconds) const noexcept;
Type secondsToLinRate (Type timeInSeconds) const noexcept;
Type secondsToExpRate (Type timeInSeconds) const noexcept;
enum class State {
Delay,
Attack,

View file

@ -155,7 +155,7 @@ bool sfz::Voice::isFree() const noexcept
return (state == State::idle);
}
void sfz::Voice::release(int delay, bool fastRelease) noexcept
void sfz::Voice::release(int delay) noexcept
{
if (state != State::playing)
return;
@ -163,10 +163,21 @@ void sfz::Voice::release(int delay, bool fastRelease) noexcept
if (egEnvelope.getRemainingDelay() > delay) {
switchState(State::cleanMeUp);
} else {
egEnvelope.startRelease(delay, fastRelease);
egEnvelope.startRelease(delay);
}
}
void sfz::Voice::off(int delay) noexcept
{
if (region->offMode == SfzOffMode::fast) {
egEnvelope.setReleaseTime( Default::offTime );
} else if (region->offMode == SfzOffMode::time) {
egEnvelope.setReleaseTime(region->offTime);
}
release(delay);
}
void sfz::Voice::registerNoteOff(int delay, int noteNumber, float velocity) noexcept
{
ASSERT(velocity >= 0.0 && velocity <= 1.0);
@ -561,7 +572,8 @@ void sfz::Voice::fillWithData(AudioSpan<float> buffer) noexcept
<< " for sample " << region->sampleId);
}
#endif
egEnvelope.startRelease(i, true);
egEnvelope.setReleaseTime(0.0f);
egEnvelope.startRelease(i);
fill<int>(indices->subspan(i), sampleEnd);
fill<float>(coeffs->subspan(i), 1.0f);
break;
@ -695,7 +707,7 @@ bool sfz::Voice::checkOffGroup(int delay, uint32_t group) noexcept
return false;
if (triggerType == TriggerType::NoteOn && region->offBy == group) {
release(delay, region->offMode == SfzOffMode::fast);
off(delay);
return true;
}

View file

@ -288,7 +288,15 @@ public:
* @param delay
* @param fastRelease whether to do a normal release or cut the voice abruptly
*/
void release(int delay, bool fastRelease = false) noexcept;
void release(int delay) noexcept;
/**
* @brief Off the voice (steal). This will respect the off mode of the region
* and set the envelopes if necessary.
*
* @param delay
*/
void off(int delay) noexcept;
/**
* @brief gets the age of the Voice