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 { 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> 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<Type>::reset(const EGDescription& desc, const Region& region, const MidiState& state, int delay, float velocity, float sampleRate) noexcept
{ {
auto secondsToSamples = [sampleRate](Type timeInSeconds) { this->sampleRate = sampleRate;
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->delay = delay + secondsToSamples(desc.getDelay(state, velocity)); this->delay = delay + secondsToSamples(desc.getDelay(state, velocity));
this->attackStep = secondsToLinRate(desc.getAttack(state, velocity)); this->attackStep = secondsToLinRate(desc.getAttack(state, velocity));
@ -208,13 +216,16 @@ int ADSREnvelope<Type>::getRemainingDelay() const noexcept
} }
template <class Type> template <class Type>
void ADSREnvelope<Type>::startRelease(int releaseDelay, bool fastRelease) noexcept void ADSREnvelope<Type>::startRelease(int releaseDelay) noexcept
{ {
shouldRelease = true; shouldRelease = true;
this->releaseDelay = releaseDelay; this->releaseDelay = releaseDelay;
}
if (fastRelease) template <class Type>
this->releaseRate = 0; void ADSREnvelope<Type>::setReleaseTime(Type timeInSeconds) noexcept
{
releaseRate = secondsToExpRate(timeInSeconds);
} }
} }

View file

@ -44,15 +44,18 @@ public:
* @param output * @param output
*/ */
void getBlock(absl::Span<Type> output) noexcept; 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. * @brief Start the envelope release after a delay.
* *
* @param releaseDelay the delay before releasing in samples * @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? * @brief Is the envelope smoothing?
* *
@ -75,6 +78,11 @@ public:
int getRemainingDelay() const noexcept; int getRemainingDelay() const noexcept;
private: 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 { enum class State {
Delay, Delay,
Attack, Attack,

View file

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

View file

@ -288,7 +288,15 @@ public:
* @param delay * @param delay
* @param fastRelease whether to do a normal release or cut the voice abruptly * @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 * @brief gets the age of the Voice