Merge pull request #386 from jpcima/mm-trigger-release

Modulations trigger and release
This commit is contained in:
JP Cimalando 2020-08-22 00:53:31 +02:00 committed by GitHub
commit 2e65a367e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 47 additions and 16 deletions

View file

@ -49,7 +49,7 @@ void LFO::configure(const LFODescription* desc)
impl_->desc_ = desc ? desc : &LFODescription::getDefault(); impl_->desc_ = desc ? desc : &LFODescription::getDefault();
} }
void LFO::start() void LFO::start(unsigned triggerDelay)
{ {
Impl& impl = *impl_; Impl& impl = *impl_;
const LFODescription& desc = *impl.desc_; const LFODescription& desc = *impl.desc_;
@ -59,7 +59,8 @@ void LFO::start()
impl.sampleHoldMem_.fill(0.0f); impl.sampleHoldMem_.fill(0.0f);
const float delay = desc.delay; const float delay = desc.delay;
impl.delayFramesLeft_ = (delay > 0) ? static_cast<size_t>(std::ceil(sampleRate * delay)) : 0u; size_t delayFrames = (delay > 0) ? static_cast<size_t>(std::ceil(sampleRate * delay)) : 0u;
impl.delayFramesLeft_ = triggerDelay + delayFrames;
impl.fadePosition_ = (desc.fade > 0) ? 0.0f : 1.0f; impl.fadePosition_ = (desc.fade > 0) ? 0.0f : 1.0f;
} }

View file

@ -67,7 +67,7 @@ public:
Start processing a LFO as a region is triggered. Start processing a LFO as a region is triggered.
Prepares the delay, phases, fade-in, etc.. Prepares the delay, phases, fade-in, etc..
*/ */
void start(); void start(unsigned triggerDelay);
/** /**
Process a cycle of the oscillator. Process a cycle of the oscillator.

View file

@ -150,7 +150,7 @@ void sfz::Voice::startVoice(Region* region, int delay, int number, float value,
bendSmoother.reset(centsFactor(region->getBendInCents(resources.midiState.getPitchBend()))); bendSmoother.reset(centsFactor(region->getBendInCents(resources.midiState.getPitchBend())));
egEnvelope.reset(region->amplitudeEG, *region, resources.midiState, delay, value, sampleRate); egEnvelope.reset(region->amplitudeEG, *region, resources.midiState, delay, value, sampleRate);
resources.modMatrix.initVoice(id, region->getId()); resources.modMatrix.initVoice(id, region->getId(), delay);
} }
int sfz::Voice::getCurrentSampleQuality() const noexcept int sfz::Voice::getCurrentSampleQuality() const noexcept
@ -174,6 +174,8 @@ void sfz::Voice::release(int delay) noexcept
} else { } else {
egEnvelope.startRelease(delay); egEnvelope.startRelease(delay);
} }
resources.modMatrix.releaseVoice(id, region->getId(), delay);
} }
void sfz::Voice::off(int delay) noexcept void sfz::Voice::off(int delay) noexcept

View file

@ -36,8 +36,18 @@ public:
* *
* @param sourceKey identifier of the source to initialize * @param sourceKey identifier of the source to initialize
* @param voiceId the particular voice to initialize, if per-voice * @param voiceId the particular voice to initialize, if per-voice
* @param delay the frame time when it happens
*/ */
virtual void init(const ModKey& sourceKey, NumericId<Voice> voiceId) = 0; virtual void init(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) = 0;
/**
* @brief Send the generator a release notification.
*
* @param sourceKey identifier of the source to release
* @param voiceId the particular voice to initialize, if per-voice
* @param delay the frame time when it happens
*/
virtual void release(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) { (void)sourceKey; (void)voiceId; (void)delay; }
/** /**
* @brief Generate a cycle of the modulator * @brief Generate a cycle of the modulator

View file

@ -196,18 +196,29 @@ void ModMatrix::init()
for (Impl::Source &source : impl.sources_) { for (Impl::Source &source : impl.sources_) {
const int flags = source.key.flags(); const int flags = source.key.flags();
if (flags & kModIsPerCycle) if (flags & kModIsPerCycle)
source.gen->init(source.key, {}); source.gen->init(source.key, {}, 0);
} }
} }
void ModMatrix::initVoice(NumericId<Voice> voiceId, NumericId<Region> regionId) void ModMatrix::initVoice(NumericId<Voice> voiceId, NumericId<Region> regionId, unsigned delay)
{ {
Impl& impl = *impl_; Impl& impl = *impl_;
for (Impl::Source &source : impl.sources_) { for (Impl::Source &source : impl.sources_) {
const int flags = source.key.flags(); const int flags = source.key.flags();
if ((flags & kModIsPerVoice) && source.key.region() == regionId) if ((flags & kModIsPerVoice) && source.key.region() == regionId)
source.gen->init(source.key, voiceId); source.gen->init(source.key, voiceId, delay);
}
}
void ModMatrix::releaseVoice(NumericId<Voice> voiceId, NumericId<Region> regionId, unsigned delay)
{
Impl& impl = *impl_;
for (Impl::Source &source : impl.sources_) {
const int flags = source.key.flags();
if ((flags & kModIsPerVoice) && source.key.region() == regionId)
source.gen->release(source.key, voiceId, delay);
} }
} }

View file

@ -106,7 +106,13 @@ public:
* @brief Reinitialize modulation source for a given voice. * @brief Reinitialize modulation source for a given voice.
* This must be called first after a voice enters active state. * This must be called first after a voice enters active state.
*/ */
void initVoice(NumericId<Voice> voiceId, NumericId<Region> regionId); void initVoice(NumericId<Voice> voiceId, NumericId<Region> regionId, unsigned delay);
/**
* @brief Release modulation source for a given voice.
* This must be called when a voice enters released state.
*/
void releaseVoice(NumericId<Voice> voiceId, NumericId<Region> regionId, unsigned delay);
/** /**
* @brief Start modulation processing for the entire cycle. * @brief Start modulation processing for the entire cycle.

View file

@ -49,9 +49,10 @@ void ControllerSource::setSamplesPerBlock(unsigned count)
(void)count; (void)count;
} }
void ControllerSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId) void ControllerSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay)
{ {
(void)voiceId; (void)voiceId;
(void)delay;
const ModKey::Parameters p = sourceKey.parameters(); const ModKey::Parameters p = sourceKey.parameters();
if (p.smooth > 0) { if (p.smooth > 0) {

View file

@ -18,7 +18,7 @@ public:
~ControllerSource(); ~ControllerSource();
void setSampleRate(double sampleRate) override; void setSampleRate(double sampleRate) override;
void setSamplesPerBlock(unsigned count) override; void setSamplesPerBlock(unsigned count) override;
void init(const ModKey& sourceKey, NumericId<Voice> voiceId) override; void init(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) override;
void generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer) override; void generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer) override;
private: private:

View file

@ -19,7 +19,7 @@ LFOSource::LFOSource(Synth &synth)
{ {
} }
void LFOSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId) void LFOSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay)
{ {
Synth& synth = *synth_; Synth& synth = *synth_;
unsigned lfoIndex = sourceKey.parameters().N; unsigned lfoIndex = sourceKey.parameters().N;
@ -38,7 +38,7 @@ void LFOSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId)
LFO* lfo = voice->getLFO(lfoIndex); LFO* lfo = voice->getLFO(lfoIndex);
lfo->configure(&region->lfos[lfoIndex]); lfo->configure(&region->lfos[lfoIndex]);
lfo->start(); lfo->start(delay);
} }
void LFOSource::generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer) void LFOSource::generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer)

View file

@ -13,7 +13,7 @@ class Synth;
class LFOSource : public ModGenerator { class LFOSource : public ModGenerator {
public: public:
explicit LFOSource(Synth &synth); explicit LFOSource(Synth &synth);
void init(const ModKey& sourceKey, NumericId<Voice> voiceId) override; void init(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) override;
void generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer) override; void generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer) override;
private: private:

View file

@ -31,7 +31,7 @@ static bool computeLFO(DataPoints& dp, const fs::path& sfzPath, double sampleRat
std::vector<float> outputMemory(numLfos * numFrames); std::vector<float> outputMemory(numLfos * numFrames);
for (size_t l = 0; l < numLfos; ++l) { for (size_t l = 0; l < numLfos; ++l) {
lfos[l].start(); lfos[l].start(0);
} }
std::vector<absl::Span<float>> lfoOutputs(numLfos); std::vector<absl::Span<float>> lfoOutputs(numLfos);

View file

@ -119,7 +119,7 @@ int main(int argc, char* argv[])
std::vector<float> outputMemory(numLfos * numFrames); std::vector<float> outputMemory(numLfos * numFrames);
for (size_t l = 0; l < numLfos; ++l) { for (size_t l = 0; l < numLfos; ++l) {
lfos[l].start(); lfos[l].start(0);
} }
std::vector<absl::Span<float>> lfoOutputs(numLfos); std::vector<absl::Span<float>> lfoOutputs(numLfos);