Browse Source

Gates: Refactor to use array of Engine struct. Make Reset clear Delay buffer.

tags/v2.3.0
Andrew Belt 1 year ago
parent
commit
01b23319a4
1 changed files with 59 additions and 60 deletions
  1. +59
    -60
      src/Gates.cpp

+ 59
- 60
src/Gates.cpp View File

@@ -33,27 +33,30 @@ struct Gates : Module {
LIGHTS_LEN
};

double time = 0.0;
dsp::BooleanTrigger resetParamTrigger;
// Bit field for each channel
uint16_t stateBits = 0;
dsp::SchmittTrigger resetTrigger[16];
dsp::PulseGenerator risePulse[16];
dsp::PulseGenerator fallPulse[16];
bool flop[16] = {};
float gateTime[16] = {};
dsp::ClockDivider lightDivider;

double time = 0.0;
struct StateEvent {
double time;
uint16_t stateBits;
bool state;

bool operator<(const StateEvent& other) const {
return time < other.time;
}
};
// TODO Change this to a circular buffer with binary search, to avoid allocations.
std::set<StateEvent> stateEvents;

struct Engine {
bool state = false;
dsp::SchmittTrigger resetTrigger;
dsp::PulseGenerator risePulse;
dsp::PulseGenerator fallPulse;
bool flop = false;
float gateTime = INFINITY;
// TODO Change this to a circular buffer with binary search, to avoid allocations.
std::set<StateEvent> stateEvents;
};
Engine engines[16];

Gates() {
config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
@@ -70,9 +73,6 @@ struct Gates : Module {
configOutput(DELAY_OUTPUT, "Gate delay");

lightDivider.setDivision(32);
for (int c = 0; c < 16; c++) {
gateTime[c] = INFINITY;
}
}

void process(const ProcessArgs& args) override {
@@ -91,99 +91,98 @@ struct Gates : Module {
resetButton = true;
}

bool newState = false;

// Process channels
for (int c = 0; c < channels; c++) {
Engine& e = engines[c];
float in = inputs[IN_INPUT].getVoltage(c);

if (stateBits & (1 << c)) {
bool newState = false;
if (e.state) {
// HIGH to LOW
if (in <= 0.1f) {
// states[c] = false
stateBits &= ~(1 << c);
fallPulse[c].trigger(1e-3f);
e.state = false;
e.fallPulse.trigger(1e-3f);
newState = true;
}
}
else {
// LOW to HIGH
if (in >= 2.f) {
// states[c] = true
stateBits |= (1 << c);
risePulse[c].trigger(1e-3f);
e.state = true;
e.risePulse.trigger(1e-3f);
// Flip flop
flop[c] ^= true;
e.flop ^= true;
// Gate
gateTime[c] = 0.f;
e.gateTime = 0.f;
newState = true;
}
}

// Reset
bool reset = resetButton;
if (resetTrigger[c].process(inputs[RESET_INPUT].getVoltage(c), 0.1f, 2.f)) {
if (e.resetTrigger.process(inputs[RESET_INPUT].getVoltage(c), 0.1f, 2.f)) {
reset = true;
}
if (reset) {
flop[c] = false;
e.flop = false;
e.stateEvents.clear();
}

// Gate
float gatePitch = params[LENGTH_PARAM].getValue() + inputs[LENGTH_INPUT].getPolyVoltage(c);
float gateLength = dsp::approxExp2_taylor5(gatePitch + 30.f) / 1073741824;
if (std::isfinite(gateTime[c])) {
gateTime[c] += args.sampleTime;
if (reset || gateTime[c] >= gateLength) {
gateTime[c] = INFINITY;
if (std::isfinite(e.gateTime)) {
e.gateTime += args.sampleTime;
if (reset || e.gateTime >= gateLength) {
e.gateTime = INFINITY;
}
}

// Gate delay output
bool delayGate = false;
// Timestamp of past gate
double delayTime = time - gateLength;
// Find event less than or equal to delayTime.
// If not found, gate will be off.
auto eventIt = e.stateEvents.upper_bound({delayTime, false});
if (eventIt != e.stateEvents.begin()) {
eventIt--;
const StateEvent& event = *eventIt;
delayGate = event.state;
}

if (newState) {
// Keep buffer a reasonable size
if (e.stateEvents.size() >= (1 << 12) - 1) {
e.stateEvents.erase(e.stateEvents.begin());
}
// Insert current state at current time
e.stateEvents.insert({time, e.state});
}

// Outputs
bool rise = risePulse[c].process(args.sampleTime);
bool rise = e.risePulse.process(args.sampleTime);
outputs[RISE_OUTPUT].setVoltage(rise ? 10.f : 0.f, c);
anyRise = anyRise || rise;

bool fall = fallPulse[c].process(args.sampleTime);
bool fall = e.fallPulse.process(args.sampleTime);
outputs[FALL_OUTPUT].setVoltage(fall ? 10.f : 0.f, c);
anyFall = anyFall || fall;

outputs[FLIP_OUTPUT].setVoltage(!flop[c] ? 10.f : 0.f, c);
anyFlip = anyFlip || !flop[c];
outputs[FLIP_OUTPUT].setVoltage(!e.flop ? 10.f : 0.f, c);
anyFlip = anyFlip || !e.flop;

outputs[FLOP_OUTPUT].setVoltage(flop[c] ? 10.f : 0.f, c);
anyFlop = anyFlop || flop[c];
outputs[FLOP_OUTPUT].setVoltage(e.flop ? 10.f : 0.f, c);
anyFlop = anyFlop || e.flop;

bool gate = std::isfinite(gateTime[c]);
bool gate = std::isfinite(e.gateTime);
outputs[GATE_OUTPUT].setVoltage(gate ? 10.f : 0.f, c);
anyGate = anyGate || gate;

// Gate delay output
bool delayGate = false;
// Timestamp of past gate
double delayTime = time - gateLength;
// Find event less than or equal to delayTime.
// If not found, gate will be off.
auto eventIt = stateEvents.upper_bound({delayTime, 0});
if (eventIt != stateEvents.begin()) {
eventIt--;
const StateEvent& event = *eventIt;
delayGate = event.stateBits & (1 << c);
}

outputs[DELAY_OUTPUT].setVoltage(delayGate ? 10.f : 0.f, c);
anyDelay = anyDelay || delayGate;
}

// Push state event
if (newState) {
// Keep buffer a reasonable size
if (stateEvents.size() >= (1 << 12) - 1) {
stateEvents.erase(stateEvents.begin());
}

stateEvents.insert({time, stateBits});
}
time += args.sampleTime;

outputs[RISE_OUTPUT].setChannels(channels);


Loading…
Cancel
Save