Merge pull request #528 from paulfd/free-running-flex-ampeg
Let the flex eg free-run when set as the ampeg
This commit is contained in:
commit
a654458c55
4 changed files with 89 additions and 8 deletions
|
|
@ -45,6 +45,7 @@ struct FlexEnvelope::Impl {
|
|||
float currentTime_ { 0.0 };
|
||||
absl::optional<size_t> currentFramesUntilRelease_ { absl::nullopt };
|
||||
bool isReleased_ { false };
|
||||
bool freeRunning_ { false };
|
||||
|
||||
//
|
||||
void process(absl::Span<float> out);
|
||||
|
|
@ -70,6 +71,15 @@ void FlexEnvelope::configure(const FlexEGDescription* desc)
|
|||
{
|
||||
Impl& impl = *impl_;
|
||||
impl.desc_ = desc;
|
||||
|
||||
//
|
||||
impl.freeRunning_ = false;
|
||||
impl.isReleased_ = false;
|
||||
|
||||
//
|
||||
impl.currentStageNumber_ = 0;
|
||||
impl.currentLevel_ = 0.0;
|
||||
impl.currentTime_ = 0.0;
|
||||
}
|
||||
|
||||
void FlexEnvelope::start(unsigned triggerDelay)
|
||||
|
|
@ -90,12 +100,12 @@ void FlexEnvelope::start(unsigned triggerDelay)
|
|||
impl.stageSustained_ = desc.sustain == 0;
|
||||
impl.stageCurve_ = &point.curve();
|
||||
impl.currentFramesUntilRelease_ = absl::nullopt;
|
||||
impl.isReleased_ = false;
|
||||
}
|
||||
|
||||
//
|
||||
impl.currentStageNumber_ = 0;
|
||||
impl.currentLevel_ = 0.0;
|
||||
impl.currentTime_ = 0.0;
|
||||
void FlexEnvelope::setFreeRunning(bool freeRunning)
|
||||
{
|
||||
Impl& impl = *impl_;
|
||||
impl.freeRunning_ = freeRunning;
|
||||
}
|
||||
|
||||
void FlexEnvelope::release(unsigned releaseDelay)
|
||||
|
|
@ -134,7 +144,6 @@ void FlexEnvelope::Impl::process(absl::Span<float> out)
|
|||
const FlexEGDescription& desc = *desc_;
|
||||
size_t numFrames = out.size();
|
||||
const float samplePeriod = samplePeriod_;
|
||||
|
||||
// Skip the initial delay, for frame-accurate trigger
|
||||
size_t skipFrames = std::min(numFrames, delayFramesLeft_);
|
||||
if (skipFrames > 0) {
|
||||
|
|
@ -171,9 +180,9 @@ void FlexEnvelope::Impl::process(absl::Span<float> out)
|
|||
}
|
||||
}
|
||||
}
|
||||
while (!stageSustained_ && currentTime_ >= stageTime_) {
|
||||
while ((!stageSustained_ || freeRunning_) && currentTime_ >= stageTime_) {
|
||||
// advance through completed timed stages
|
||||
ASSERT(isReleased_ || !stageSustained_);
|
||||
ASSERT(isReleased_ || !stageSustained_ || freeRunning_);
|
||||
if (stageTime_ == 0) {
|
||||
// if stage is of zero duration, immediate transition to level
|
||||
currentLevel_ = stageTargetLevel_;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,13 @@ public:
|
|||
*/
|
||||
void configure(const FlexEGDescription* desc);
|
||||
|
||||
/**
|
||||
* @brief Set the EG to be freeRunning or not
|
||||
*
|
||||
* @param freeRunning
|
||||
*/
|
||||
void setFreeRunning(bool freeRunning);
|
||||
|
||||
/**
|
||||
Start processing an EG as a region is triggered.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -38,6 +38,12 @@ void FlexEnvelopeSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId,
|
|||
|
||||
FlexEnvelope* eg = voice->getFlexEG(egIndex);
|
||||
eg->configure(®ion->flexEGs[egIndex]);
|
||||
bool freeRunning = (
|
||||
(region->loopMode == SfzLoopMode::one_shot && region->isOscillator())
|
||||
);
|
||||
if (freeRunning && region->flexAmpEG && egIndex == *region->flexAmpEG)
|
||||
eg->setFreeRunning(true);
|
||||
|
||||
eg->start(delay);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
|
||||
#include "sfizz/Synth.h"
|
||||
#include "sfizz/AudioBuffer.h"
|
||||
#include "sfizz/FlexEnvelope.h"
|
||||
#include "catch2/catch.hpp"
|
||||
#include "TestHelpers.h"
|
||||
|
|
@ -357,3 +358,61 @@ TEST_CASE("[FlexEG] Early release")
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("[FlexEG] Free-running flex AmpEG (no sustain)")
|
||||
{
|
||||
sfz::Synth synth;
|
||||
|
||||
synth.loadSfzString(fs::current_path(), R"(
|
||||
<region> sample=*noise
|
||||
key=60
|
||||
loop_mode=one_shot
|
||||
eg1_ampeg=1
|
||||
eg1_time1=0 eg1_level1=1
|
||||
eg1_time2=0.03 eg1_level2=0.6
|
||||
eg1_time3=0.06 eg1_level3=0.3
|
||||
eg1_time4=0.12 eg1_level4=0.1
|
||||
eg1_time5=0.3 eg1_level5=0
|
||||
<region> sample=*noise
|
||||
key=62
|
||||
loop_mode=one_shot
|
||||
eg1_ampeg=1
|
||||
eg1_time1=0 eg1_level1=1
|
||||
eg1_time2=0.03 eg1_level2=0.6
|
||||
eg1_time3=0.06 eg1_level3=0.3
|
||||
eg1_time4=0.12 eg1_level4=0.1
|
||||
eg1_time5=0.3 eg1_level5=0 eg1_sustain=5
|
||||
<region> sample=*noise
|
||||
key=64
|
||||
eg1_ampeg=1
|
||||
eg1_time1=0 eg1_level1=1
|
||||
eg1_time2=0.03 eg1_level2=0.6
|
||||
eg1_time3=0.06 eg1_level3=0.3
|
||||
eg1_time4=0.12 eg1_level4=0.1
|
||||
eg1_time5=0.3 eg1_level5=0 eg1_sustain=5
|
||||
)");
|
||||
synth.noteOn(0, 60, 0);
|
||||
sfz::AudioBuffer<float> buffer { 2, 256 };
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
for (unsigned i = 0; i < 100; ++i)
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
|
||||
synth.noteOn(0, 62, 0);
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
for (unsigned i = 0; i < 100; ++i)
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
|
||||
synth.noteOn(0, 64, 0);
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
for (unsigned i = 0; i < 100; ++i)
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 1 );
|
||||
synth.noteOff(0, 64, 0); // the release stage is 0 duration
|
||||
synth.renderBlock(buffer);
|
||||
REQUIRE( synth.getNumActiveVoices(true) == 0 );
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue