|
@@ -37,15 +37,6 @@ struct Gates : Module { |
|
|
dsp::BooleanTrigger resetParamTrigger; |
|
|
dsp::BooleanTrigger resetParamTrigger; |
|
|
dsp::ClockDivider lightDivider; |
|
|
dsp::ClockDivider lightDivider; |
|
|
|
|
|
|
|
|
struct StateEvent { |
|
|
|
|
|
double time; |
|
|
|
|
|
bool state; |
|
|
|
|
|
|
|
|
|
|
|
bool operator<(const StateEvent& other) const { |
|
|
|
|
|
return time < other.time; |
|
|
|
|
|
} |
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct Engine { |
|
|
struct Engine { |
|
|
bool state = false; |
|
|
bool state = false; |
|
|
dsp::SchmittTrigger resetTrigger; |
|
|
dsp::SchmittTrigger resetTrigger; |
|
@@ -53,8 +44,8 @@ struct Gates : Module { |
|
|
dsp::PulseGenerator fallPulse; |
|
|
dsp::PulseGenerator fallPulse; |
|
|
bool flop = false; |
|
|
bool flop = false; |
|
|
float gateTime = INFINITY; |
|
|
float gateTime = INFINITY; |
|
|
// TODO Change this to a circular buffer with binary search, to avoid allocations. |
|
|
|
|
|
std::set<StateEvent> stateEvents; |
|
|
|
|
|
|
|
|
// TODO Change this to a circular buffer with binary search, to avoid allocations when events are pushed. |
|
|
|
|
|
std::map<double, bool> stateEvents; |
|
|
}; |
|
|
}; |
|
|
Engine engines[16]; |
|
|
Engine engines[16]; |
|
|
|
|
|
|
|
@@ -128,38 +119,6 @@ struct Gates : Module { |
|
|
e.stateEvents.clear(); |
|
|
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(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 |
|
|
// Outputs |
|
|
bool rise = e.risePulse.process(args.sampleTime); |
|
|
bool rise = e.risePulse.process(args.sampleTime); |
|
|
outputs[RISE_OUTPUT].setVoltage(rise ? 10.f : 0.f, c); |
|
|
outputs[RISE_OUTPUT].setVoltage(rise ? 10.f : 0.f, c); |
|
@@ -175,12 +134,45 @@ struct Gates : Module { |
|
|
outputs[FLOP_OUTPUT].setVoltage(e.flop ? 10.f : 0.f, c); |
|
|
outputs[FLOP_OUTPUT].setVoltage(e.flop ? 10.f : 0.f, c); |
|
|
anyFlop = anyFlop || e.flop; |
|
|
anyFlop = anyFlop || e.flop; |
|
|
|
|
|
|
|
|
|
|
|
// Gate output |
|
|
|
|
|
float gatePitch = params[LENGTH_PARAM].getValue() + inputs[LENGTH_INPUT].getPolyVoltage(c); |
|
|
|
|
|
float gateLength = dsp::approxExp2_taylor5(gatePitch + 30.f) / 1073741824; |
|
|
|
|
|
if (std::isfinite(e.gateTime)) { |
|
|
|
|
|
e.gateTime += args.sampleTime; |
|
|
|
|
|
if (reset || e.gateTime >= gateLength) { |
|
|
|
|
|
e.gateTime = INFINITY; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
bool gate = std::isfinite(e.gateTime); |
|
|
bool gate = std::isfinite(e.gateTime); |
|
|
outputs[GATE_OUTPUT].setVoltage(gate ? 10.f : 0.f, c); |
|
|
outputs[GATE_OUTPUT].setVoltage(gate ? 10.f : 0.f, c); |
|
|
anyGate = anyGate || gate; |
|
|
anyGate = anyGate || gate; |
|
|
|
|
|
|
|
|
outputs[DELAY_OUTPUT].setVoltage(delayGate ? 10.f : 0.f, c); |
|
|
|
|
|
anyDelay = anyDelay || delayGate; |
|
|
|
|
|
|
|
|
// Gate delay output |
|
|
|
|
|
if (outputs[DELAY_OUTPUT].isConnected()) { |
|
|
|
|
|
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); |
|
|
|
|
|
if (eventIt != e.stateEvents.begin()) { |
|
|
|
|
|
eventIt--; |
|
|
|
|
|
delayGate = eventIt->second; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (newState) { |
|
|
|
|
|
// Keep buffer a reasonable size |
|
|
|
|
|
if (e.stateEvents.size() >= (1 << 10) - 1) { |
|
|
|
|
|
e.stateEvents.erase(e.stateEvents.begin()); |
|
|
|
|
|
} |
|
|
|
|
|
// Insert current state at current time |
|
|
|
|
|
e.stateEvents[time] = e.state; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
outputs[DELAY_OUTPUT].setVoltage(delayGate ? 10.f : 0.f, c); |
|
|
|
|
|
anyDelay = anyDelay || delayGate; |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
time += args.sampleTime; |
|
|
time += args.sampleTime; |
|
|