Browse Source

Moving to generalised envelope class.

tags/v1.1.0^2
hemmer 4 years ago
parent
commit
f11ecc29cc
4 changed files with 71 additions and 80 deletions
  1. +47
    -1
      src/Common.hpp
  2. +5
    -5
      src/HexmixVCA.cpp
  3. +0
    -37
      src/Kickall.cpp
  4. +19
    -37
      src/Percall.cpp

+ 47
- 1
src/Common.hpp View File

@@ -57,4 +57,50 @@ T tanh_pade(T x) {
T x2 = x * x; T x2 = x * x;
T q = 12.f + x2; T q = 12.f + x2;
return 12.f * x * q / (36.f * x2 + q * q); return 12.f * x * q / (36.f * x2 + q * q);
}
}


struct ADEnvelope {

enum Stage {
STAGE_OFF,
STAGE_ATTACK,
STAGE_DECAY
};

Stage stage = STAGE_OFF;
float env = 0.f;
float attackTime = 0.1, decayTime = 0.1;
float attackShape = 1.0, decayShape = 1.0;
ADEnvelope() { };

void process(const float& sampleTime) {

if (stage == STAGE_OFF) {
env = envLinear = 0.0f;
}
else if (stage == STAGE_ATTACK) {
envLinear += sampleTime / attackTime;
env = std::pow(envLinear, attackShape);
}
else if (stage == STAGE_DECAY) {
envLinear -= sampleTime / decayTime;
env = std::pow(envLinear, decayShape);
}

if (env >= 1.0f) {
stage = STAGE_DECAY;
env = envLinear = 1.0f;
}
else if (env <= 0.0f) {
stage = STAGE_OFF;
env = envLinear = 0.0f;
}

}

private:
float envLinear = 0.f;

};

+ 5
- 5
src/HexmixVCA.cpp View File

@@ -70,15 +70,15 @@ struct HexmixVCA : Module {
maxChannels = std::max(maxChannels, channels); maxChannels = std::max(maxChannels, channels);
float cvGain = clamp(inputs[CV_INPUT + row].getNormalVoltage(10.f) / 10.f, 0.f, 1.f); float cvGain = clamp(inputs[CV_INPUT + row].getNormalVoltage(10.f) / 10.f, 0.f, 1.f);
float gain = gainFunction(cvGain, shapes[row]);
float gain = gainFunction(cvGain, shapes[row]) * outputLevels[row];
for (int c = 0; c < channels; c += 4) { for (int c = 0; c < channels; c += 4) {
in[c / 4] = simd::float_4::load(inputs[row].getVoltages(c)) * gain * outputLevels[row];
in[c / 4] = simd::float_4::load(inputs[row].getVoltages(c)) * gain;
} }
} }
// if not the final row
if (row != numRows - 1) {
bool finalRow = (row == numRows - 1);
if (!finalRow) {
if (outputs[OUT_OUTPUT + row].isConnected()) { if (outputs[OUT_OUTPUT + row].isConnected()) {
// if output is connected, we don't add to mix // if output is connected, we don't add to mix
outputs[OUT_OUTPUT + row].setChannels(channels); outputs[OUT_OUTPUT + row].setChannels(channels);


+ 0
- 37
src/Kickall.cpp View File

@@ -2,43 +2,6 @@
#include "Common.hpp" #include "Common.hpp"
#include "ChowDSP.hpp" #include "ChowDSP.hpp"
struct ADEnvelope {
enum Stage {
STAGE_OFF,
STAGE_ATTACK,
STAGE_DECAY
};
Stage stage = STAGE_OFF;
float env = 0.f;
float attackTime = 0.1, decayTime = 0.1;
// TODO: add shape, and generlise to use with Percall
ADEnvelope() { };
void process(const float& sampleTime) {
if (stage == STAGE_OFF) {
env = 0.0f;
}
else if (stage == STAGE_ATTACK) {
env += sampleTime / attackTime;
}
else if (stage == STAGE_DECAY) {
env -= sampleTime / decayTime;
}
if (env >= 1.0f) {
stage = STAGE_DECAY;
env = 1.0f;
}
else if (env <= 0.0f) {
stage = STAGE_OFF;
env = 0.0f;
}
}
};
struct Kickall : Module { struct Kickall : Module {
enum ParamIds { enum ParamIds {


+ 19
- 37
src/Percall.cpp View File

@@ -33,27 +33,29 @@ struct Percall : Module {
NUM_LIGHTS NUM_LIGHTS
}; };
enum Stage {
STAGE_OFF,
STAGE_ATTACK,
STAGE_DECAY
};
ADEnvelope envs[4];
Stage stage[4] = {};
float env[4] = {};
float gains[4] = {}; float gains[4] = {};
float fallTimes[4] = {};
float strength = 1.0f; float strength = 1.0f;
dsp::SchmittTrigger trigger[4]; dsp::SchmittTrigger trigger[4];
dsp::ClockDivider cvDivider; dsp::ClockDivider cvDivider;
dsp::ClockDivider lightDivider; dsp::ClockDivider lightDivider;
const int LAST_CHANNEL_ID = 3; const int LAST_CHANNEL_ID = 3;
const float attackTime = 1.5e-3;
const float minDecayTime = 4.5e-3;
const float maxDecayTime = 4.f;
Percall() { Percall() {
config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS); config(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
configParam(VOL_PARAMS + i, 0.f, 1.f, 1.f, "Ch " + std::to_string(i + 1) + " level", "%", 0, 100); configParam(VOL_PARAMS + i, 0.f, 1.f, 1.f, "Ch " + std::to_string(i + 1) + " level", "%", 0, 100);
configParam(DECAY_PARAMS + i, 0.f, 1.f, 0.f, "Ch " + std::to_string(i + 1) + " decay time"); configParam(DECAY_PARAMS + i, 0.f, 1.f, 0.f, "Ch " + std::to_string(i + 1) + " decay time");
envs[i].attackTime = attackTime;
envs[i].attackShape = 0.5f;
envs[i].decayShape = 3.0f;
} }
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
std::string description = "Choke " + std::to_string(2 * i + 1) + " to " + std::to_string(2 * i + 2); std::string description = "Choke " + std::to_string(2 * i + 1) + " to " + std::to_string(2 * i + 2);
@@ -77,7 +79,7 @@ struct Percall : Module {
gains[i] = std::pow(params[VOL_PARAMS + i].getValue(), 2.f) * strength; gains[i] = std::pow(params[VOL_PARAMS + i].getValue(), 2.f) * strength;
float fallCv = inputs[CV_INPUTS + i].getVoltage() + params[DECAY_PARAMS + i].getValue() * 10.f; float fallCv = inputs[CV_INPUTS + i].getVoltage() + params[DECAY_PARAMS + i].getValue() * 10.f;
fallTimes[i] = 0.01 * std::pow(2.0, clamp(fallCv, 0.0f, 10.0f));
envs[i].decayTime = minDecayTime * std::pow(2.0, clamp(fallCv, 0.0f, 10.0f));
} }
} }
@@ -88,36 +90,16 @@ struct Percall : Module {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (trigger[i].process(rescale(inputs[TRIG_INPUTS + i].getVoltage(), 0.1f, 2.f, 0.f, 1.f))) { if (trigger[i].process(rescale(inputs[TRIG_INPUTS + i].getVoltage(), 0.1f, 2.f, 0.f, 1.f))) {
stage[i] = STAGE_ATTACK;
envs[i].stage = ADEnvelope::STAGE_ATTACK;
} }
// if choke is enabled, and current channel is odd and left channel is in attack // if choke is enabled, and current channel is odd and left channel is in attack
if ((i % 2) && params[CHOKE_PARAMS + i / 2].getValue() && stage[i - 1] == STAGE_ATTACK) {
if ((i % 2) && params[CHOKE_PARAMS + i / 2].getValue() && envs[i - 1].stage == ADEnvelope::STAGE_ATTACK) {
// TODO: is there a more graceful way to choke, e.g. rapid envelope? // TODO: is there a more graceful way to choke, e.g. rapid envelope?
// TODO: this will just silence it instantly, maybe switch to STAGE_DECAY and modify fall time // TODO: this will just silence it instantly, maybe switch to STAGE_DECAY and modify fall time
stage[i] = STAGE_OFF;
}
float targetVoltage = (stage[i] == STAGE_ATTACK) ? 10.0f : 0.0f;
float delta = targetVoltage - env[i];
if (stage[i] == STAGE_OFF) {
env[i] = 0.0f;
}
else if (stage[i] == STAGE_ATTACK) {
env[i] += expDelta(delta, 2e-3) * args.sampleTime;
}
else if (stage[i] == STAGE_DECAY) {
env[i] += expDelta(delta, fallTimes[i]) * args.sampleTime;
envs[i].stage = ADEnvelope::STAGE_OFF;
} }
if (env[i] >= 10.0f) {
stage[i] = STAGE_DECAY;
env[i] = 10.0f;
}
else if (env[i] <= 0.0f) {
stage[i] = STAGE_OFF;
env[i] = 0.0f;
}
envs[i].process(args.sampleTime);
int channels = 1; int channels = 1;
simd::float_4 in[4] = {}; simd::float_4 in[4] = {};
@@ -129,8 +111,8 @@ struct Percall : Module {
maxChannels = std::max(maxChannels, channels); maxChannels = std::max(maxChannels, channels);
// only process input audio if envelope is active // only process input audio if envelope is active
if (stage[i] != STAGE_OFF) {
float gain = gains[i] * env[i] / 10.0f;
if (envs[i].stage != ADEnvelope::STAGE_OFF) {
float gain = gains[i] * envs[i].env;
for (int c = 0; c < channels; c += 4) { for (int c = 0; c < channels; c += 4) {
in[c / 4] = simd::float_4::load(inputs[channel_to_read_from].getVoltages(c)) * gain; in[c / 4] = simd::float_4::load(inputs[channel_to_read_from].getVoltages(c)) * gain;
} }
@@ -169,13 +151,13 @@ struct Percall : Module {
// set env output // set env output
if (outputs[ENV_OUTPUTS + i].isConnected()) { if (outputs[ENV_OUTPUTS + i].isConnected()) {
outputs[ENV_OUTPUTS + i].setVoltage(strength * env[i]);
outputs[ENV_OUTPUTS + i].setVoltage(10.f * strength * envs[i].env);
} }
} }
if (lightDivider.process()) { if (lightDivider.process()) {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
lights[LEDS + i].setBrightness(stage[i] != STAGE_OFF);
lights[LEDS + i].setBrightness(envs[i].env);
} }
} }


Loading…
Cancel
Save