Add the ability to cancel the release on the basic ADSR Envelope
This commit is contained in:
parent
f8c498b227
commit
13be8c9ac1
12 changed files with 114 additions and 75 deletions
|
|
@ -122,7 +122,8 @@ void ADSREnvelope::getBlock(absl::Span<Float> output) noexcept
|
|||
break;
|
||||
}
|
||||
while (count < size) {
|
||||
currentValue = std::max(sustain, currentValue + transitionDelta);
|
||||
if (currentValue > sustain)
|
||||
currentValue = std::max(sustain, currentValue + transitionDelta);
|
||||
output[count++] = currentValue;
|
||||
}
|
||||
break;
|
||||
|
|
@ -173,6 +174,14 @@ void ADSREnvelope::startRelease(int releaseDelay) noexcept
|
|||
this->releaseDelay = releaseDelay;
|
||||
}
|
||||
|
||||
void ADSREnvelope::cancelRelease(int delay) noexcept
|
||||
{
|
||||
(void)delay;
|
||||
currentState = State::Sustain;
|
||||
shouldRelease = false;
|
||||
this->releaseDelay = -1;
|
||||
}
|
||||
|
||||
void ADSREnvelope::setReleaseTime(Float timeInSeconds) noexcept
|
||||
{
|
||||
releaseRate = secondsToExpRate(timeInSeconds);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,12 @@ public:
|
|||
* @param releaseDelay the delay before releasing in samples
|
||||
*/
|
||||
void startRelease(int releaseDelay) noexcept;
|
||||
/**
|
||||
* @brief Cancel a release and get back into sustain.
|
||||
*
|
||||
* @param delay
|
||||
*/
|
||||
void cancelRelease(int delay) noexcept;
|
||||
/**
|
||||
* @brief Is the envelope smoothing?
|
||||
*
|
||||
|
|
|
|||
|
|
@ -676,6 +676,12 @@ void Voice::registerCC(int delay, int ccNumber, float ccValue) noexcept
|
|||
if (impl.noteIsOff_ && region.loopMode != LoopMode::one_shot
|
||||
&& sostenutoPedalReleaseCondition && sustainPedalReleaseCondition)
|
||||
release(delay);
|
||||
|
||||
if (region.checkSustain && (impl.sustainState_ == Impl::SustainState::Sustaining)
|
||||
&& impl.released() && (region.trigger != Trigger::release && region.trigger != Trigger::release_key) ) {
|
||||
ModMatrix& modMatrix = impl.resources_.getModMatrix();
|
||||
modMatrix.cancelRelease(impl.id_, impl.region_->getId(), delay);
|
||||
}
|
||||
}
|
||||
|
||||
void Voice::registerPitchWheel(int delay, float pitch) noexcept
|
||||
|
|
|
|||
|
|
@ -49,6 +49,15 @@ public:
|
|||
*/
|
||||
virtual void release(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) { (void)sourceKey; (void)voiceId; (void)delay; }
|
||||
|
||||
/**
|
||||
* @brief Cancel the release and get back into sustain
|
||||
*
|
||||
* @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 cancelRelease(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) { (void)sourceKey; (void)voiceId; (void)delay; }
|
||||
|
||||
/**
|
||||
* @brief Generate a cycle of the modulator
|
||||
*
|
||||
|
|
|
|||
|
|
@ -281,6 +281,19 @@ void ModMatrix::releaseVoice(NumericId<Voice> voiceId, NumericId<Region> regionI
|
|||
}
|
||||
}
|
||||
|
||||
void ModMatrix::cancelRelease(NumericId<Voice> voiceId, NumericId<Region> regionId, unsigned delay)
|
||||
{
|
||||
Impl& impl = *impl_;
|
||||
|
||||
ASSERT(regionId);
|
||||
|
||||
const auto idNumber = static_cast<size_t>(regionId.number());
|
||||
for (auto idx: impl.sourceIndicesForRegion_[idNumber]) {
|
||||
const Impl::Source& source = impl.sources_[idx];
|
||||
source.gen->cancelRelease(source.key, voiceId, delay);
|
||||
}
|
||||
}
|
||||
|
||||
void ModMatrix::beginCycle(unsigned numFrames)
|
||||
{
|
||||
Impl& impl = *impl_;
|
||||
|
|
|
|||
|
|
@ -116,6 +116,11 @@ public:
|
|||
*/
|
||||
void releaseVoice(NumericId<Voice> voiceId, NumericId<Region> regionId, unsigned delay);
|
||||
|
||||
/**
|
||||
* @brief Cancel release for a given voice.
|
||||
*/
|
||||
void cancelRelease(NumericId<Voice> voiceId, NumericId<Region> regionId, unsigned delay);
|
||||
|
||||
/**
|
||||
* @brief Start modulation processing for the entire cycle.
|
||||
* This clears all the buffers.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,52 @@ ADSREnvelopeSource::ADSREnvelopeSource(VoiceManager& manager, MidiState& state)
|
|||
{
|
||||
}
|
||||
|
||||
ADSREnvelope* getEG(Voice* voice, const ModKey& key)
|
||||
{
|
||||
ADSREnvelope* eg = nullptr;
|
||||
if (!voice)
|
||||
return eg;
|
||||
|
||||
switch (key.id()) {
|
||||
case ModId::AmpEG:
|
||||
eg = voice->getAmplitudeEG();
|
||||
break;
|
||||
case ModId::PitchEG:
|
||||
eg = voice->getPitchEG();
|
||||
break;
|
||||
case ModId::FilEG:
|
||||
eg = voice->getFilterEG();
|
||||
break;
|
||||
default:
|
||||
return eg;
|
||||
}
|
||||
|
||||
return eg;
|
||||
}
|
||||
|
||||
const EGDescription* getEGDescription(const Region* region, const ModKey& key)
|
||||
{
|
||||
const EGDescription* desc = nullptr;
|
||||
if (!region)
|
||||
return desc;
|
||||
|
||||
switch (key.id()) {
|
||||
case ModId::AmpEG:
|
||||
desc = ®ion->amplitudeEG;
|
||||
break;
|
||||
case ModId::PitchEG:
|
||||
desc = &*region->pitchEG;
|
||||
break;
|
||||
case ModId::FilEG:
|
||||
desc = &*region->filterEG;
|
||||
break;
|
||||
default:
|
||||
return desc;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
void ADSREnvelopeSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay)
|
||||
{
|
||||
Voice* voice = voiceManager_.getVoiceById(voiceId);
|
||||
|
|
@ -27,29 +73,9 @@ void ADSREnvelopeSource::init(const ModKey& sourceKey, NumericId<Voice> voiceId,
|
|||
}
|
||||
|
||||
const Region* region = voice->getRegion();
|
||||
ADSREnvelope* eg = nullptr;
|
||||
const EGDescription* desc = nullptr;
|
||||
|
||||
switch (sourceKey.id()) {
|
||||
case ModId::AmpEG:
|
||||
eg = voice->getAmplitudeEG();
|
||||
ASSERT(eg);
|
||||
desc = ®ion->amplitudeEG;
|
||||
break;
|
||||
case ModId::PitchEG:
|
||||
eg = voice->getPitchEG();
|
||||
ASSERT(eg);
|
||||
desc = &*region->pitchEG;
|
||||
break;
|
||||
case ModId::FilEG:
|
||||
eg = voice->getFilterEG();
|
||||
ASSERT(eg);
|
||||
desc = &*region->filterEG;
|
||||
break;
|
||||
default:
|
||||
ASSERTFALSE;
|
||||
return;
|
||||
}
|
||||
ADSREnvelope* eg = getEG(voice, sourceKey);
|
||||
const EGDescription* desc = getEGDescription(region, sourceKey);
|
||||
ASSERT(eg);
|
||||
|
||||
const TriggerEvent& triggerEvent = voice->getTriggerEvent();
|
||||
const float sampleRate = voice->getSampleRate();
|
||||
|
|
@ -64,27 +90,24 @@ void ADSREnvelopeSource::release(const ModKey& sourceKey, NumericId<Voice> voice
|
|||
return;
|
||||
}
|
||||
|
||||
ADSREnvelope* eg = nullptr;
|
||||
ADSREnvelope* eg = getEG(voice, sourceKey);
|
||||
ASSERT(eg);
|
||||
|
||||
switch (sourceKey.id()) {
|
||||
case ModId::AmpEG:
|
||||
eg = voice->getAmplitudeEG();
|
||||
ASSERT(eg);
|
||||
break;
|
||||
case ModId::PitchEG:
|
||||
eg = voice->getPitchEG();
|
||||
ASSERT(eg);
|
||||
break;
|
||||
case ModId::FilEG:
|
||||
eg = voice->getFilterEG();
|
||||
ASSERT(eg);
|
||||
break;
|
||||
default:
|
||||
eg->startRelease(delay);
|
||||
}
|
||||
|
||||
void ADSREnvelopeSource::cancelRelease(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay)
|
||||
{
|
||||
Voice* voice = voiceManager_.getVoiceById(voiceId);
|
||||
if (!voice) {
|
||||
ASSERTFALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
eg->startRelease(delay);
|
||||
ADSREnvelope* eg = getEG(voice, sourceKey);
|
||||
ASSERT(eg);
|
||||
|
||||
eg->cancelRelease(delay);
|
||||
}
|
||||
|
||||
void ADSREnvelopeSource::generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer)
|
||||
|
|
@ -95,25 +118,8 @@ void ADSREnvelopeSource::generate(const ModKey& sourceKey, NumericId<Voice> voic
|
|||
return;
|
||||
}
|
||||
|
||||
ADSREnvelope* eg = nullptr;
|
||||
|
||||
switch (sourceKey.id()) {
|
||||
case ModId::AmpEG:
|
||||
eg = voice->getAmplitudeEG();
|
||||
ASSERT(eg);
|
||||
break;
|
||||
case ModId::PitchEG:
|
||||
eg = voice->getPitchEG();
|
||||
ASSERT(eg);
|
||||
break;
|
||||
case ModId::FilEG:
|
||||
eg = voice->getFilterEG();
|
||||
ASSERT(eg);
|
||||
break;
|
||||
default:
|
||||
ASSERTFALSE;
|
||||
return;
|
||||
}
|
||||
ADSREnvelope* eg = getEG(voice, sourceKey);
|
||||
ASSERT(eg);
|
||||
|
||||
eg->getBlock(buffer);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ public:
|
|||
explicit ADSREnvelopeSource(VoiceManager &manager, MidiState& state);
|
||||
void init(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) override;
|
||||
void release(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) override;
|
||||
void cancelRelease(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) override;
|
||||
void generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer) override;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -23,13 +23,6 @@ void ChannelAftertouchSource::init(const ModKey& sourceKey, NumericId<Voice> voi
|
|||
UNUSED(delay);
|
||||
}
|
||||
|
||||
void ChannelAftertouchSource::release(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay)
|
||||
{
|
||||
UNUSED(sourceKey);
|
||||
UNUSED(voiceId);
|
||||
UNUSED(delay);
|
||||
}
|
||||
|
||||
void ChannelAftertouchSource::generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer)
|
||||
{
|
||||
UNUSED(sourceKey);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ class ChannelAftertouchSource : public ModGenerator {
|
|||
public:
|
||||
explicit ChannelAftertouchSource(VoiceManager &manager, MidiState& state);
|
||||
void init(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) override;
|
||||
void release(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) override;
|
||||
void generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer) override;
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -23,13 +23,6 @@ void PolyAftertouchSource::init(const ModKey& sourceKey, NumericId<Voice> voiceI
|
|||
UNUSED(delay);
|
||||
}
|
||||
|
||||
void PolyAftertouchSource::release(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay)
|
||||
{
|
||||
UNUSED(sourceKey);
|
||||
UNUSED(voiceId);
|
||||
UNUSED(delay);
|
||||
}
|
||||
|
||||
void PolyAftertouchSource::generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer)
|
||||
{
|
||||
UNUSED(sourceKey);
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ class PolyAftertouchSource : public ModGenerator {
|
|||
public:
|
||||
explicit PolyAftertouchSource(VoiceManager &manager, MidiState& state);
|
||||
void init(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) override;
|
||||
void release(const ModKey& sourceKey, NumericId<Voice> voiceId, unsigned delay) override;
|
||||
void generate(const ModKey& sourceKey, NumericId<Voice> voiceId, absl::Span<float> buffer) override;
|
||||
|
||||
private:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue