|
|
@@ -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); |
|
|
|