Skip to content

Instantly share code, notes, and snippets.

@astellon
Created May 19, 2019 10:12
Show Gist options
  • Save astellon/bf8414117a064e7e4ca3da5308bdd140 to your computer and use it in GitHub Desktop.
Save astellon/bf8414117a064e7e4ca3da5308bdd140 to your computer and use it in GitHub Desktop.
#include "envelope.h"
#include "common.h"
namespace synth {
/*==============================================================================
Envelope class
==============================================================================*/
Envelope::Envelope()
: Module(env_num_inputs, env_num_outputs, env_num_params) {
state_ = EnvelopeState::killed;
gain_ = 0;
sample_ = 0;
createParameter(env_attack, "env_attack", 0.01f, 1.0f, 0.2f);
createParameter(env_decay, "env_decay", 0.01f, 1.0f, 0.3f);
createParameter(env_sustain, "env_sustain", 0.0f, 1.0f, 0.8f);
createParameter(env_release, "env_release", 0.01f, 1.0f, 0.1f);
resetBuffer();
}
Envelope* Envelope::clone() const {
Envelope* env = new Envelope();
for (int i = 0; i < env_num_params; i++) {
env->registerParameter(params_[i], i);
}
return env;
}
bool Envelope::isKilled() {
return state_ == EnvelopeState::killed;
}
bool Envelope::isReleased() {
return state_ == EnvelopeState::release ||
state_ == EnvelopeState::killed;
}
void Envelope::noteOn(int sample_ofset) {
duration_ = sample_ofset;
state_ = EnvelopeState::triggered;
next_state_ = EnvelopeState::attack;
sample_ = 0;
gain_ = 0;
slope_ = 0;
}
void Envelope::noteOff(int sample_ofset) {
duration_ = sample_ofset;
state_ = EnvelopeState::released;
next_state_ = EnvelopeState::release;
sample_ = 0;
}
void Envelope::process() {
resetBuffer();
for (int i = 0; i < buffer_size_; i++) {
float gain = tick();
outputs_[0]->at(i) = gain;
outputs_[1]->at(i) = gain;
}
}
float Envelope::tick() {
if (sample_ == duration_) {
sample_ = 0;
state_ = next_state_;
switch (state_) {
case EnvelopeState::attack:
next_state_ = EnvelopeState::decay;
duration_ = secondToSample(get(env_attack)*ATTACK_TIME, sample_rate_) + 1;
slope_ = 1.0f / duration_;
break;
case EnvelopeState::decay:
next_state_ = EnvelopeState::sustain;
duration_ = secondToSample(get(env_decay)*DECAY_TIME, sample_rate_) + 1;
slope_ = (get(env_sustain) - 1.0) / duration_;
break;
case EnvelopeState::sustain:
duration_ = 1;
slope_ = 0.0f;
break;
case EnvelopeState::release:
next_state_ = EnvelopeState::killed;
duration_ = secondToSample(get(env_release)*RELEASE_TIME,
sample_rate_) + 1;
slope_ = - gain_ / duration_;
break;
case EnvelopeState::killed:
sample_ = 0;
gain_ = 0.0f;
duration_ = 1;
slope_ = 0.0f;
break;
}
}
if (state_ != EnvelopeState::sustain
&& state_ != EnvelopeState::killed) sample_++;
return gain_ += slope_;
}
// ============================================================================
} // namespace synth
#pragma once
#include "module.h"
namespace synth {
/*==============================================================================
Envelope class
==============================================================================*/
class Envelope : public Module {
public:
enum EnvInputs {
env_num_inputs,
};
enum EnvOutputs {
env_output_L,
env_output_R,
env_num_outputs,
};
enum EnvParams {
env_attack,
env_decay,
env_sustain,
env_release,
env_num_params,
};
enum class EnvelopeState {
triggered, attack, decay, sustain, released, release, killed,
};
Envelope();
Envelope* clone() const;
bool isKilled();
bool isReleased();
void noteOn(int sample_ofset);
void noteOff(int sample_ofset);
void process();
private:
EnvelopeState state_;
EnvelopeState next_state_;
int duration_, sample_;
float gain_;
float slope_;
float tick();
};
// ==============================================================================
} // namespace synth
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment