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:
parent
d3cc4281d9
commit
5ef6141c4b
4 changed files with 64 additions and 25 deletions
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue