Skip to content

Commit

Permalink
Fixed #3 - debounce Moots gate voltages using hysteresis.
Browse files Browse the repository at this point in the history
Gate voltages are not always ideally square.
They can contain Gibbs ripple, leading to unintended rapid toggling.
Now Moots follows the recommended levels and behavior as explained at:
https://vcvrack.com/manual/VoltageStandards#Triggers-and-Gates

When one of the 5 controllers has a gate voltage connected,
it will stay off until the gate voltage reaches 1.0V or higher.
Then it will turn on and stay on until the gate voltage
descends to 0.1V or lower, causing it to turn off.
Thus any voltage greater than 0.1V and lower than 1.0V
will leave the controller's on/off state unchanged.

The controllers default to being off, and are turned back off
during a reset, so they have a well-defined state if
the initial gate voltage is inside the 0.1V .. 1.0V
gray area at startup/reset.
  • Loading branch information
cosinekitty committed Aug 25, 2022
1 parent 19992e7 commit a6c9363
Showing 1 changed file with 34 additions and 2 deletions.
36 changes: 34 additions & 2 deletions src/moots.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,19 @@ struct Moots : Module
LIGHTS_LEN
};

static const int NUM_CONTROLLERS = 5;
static_assert(NUM_CONTROLLERS == PARAMS_LEN);
static_assert(NUM_CONTROLLERS == OUTPUTS_LEN);
static_assert(NUM_CONTROLLERS == LIGHTS_LEN);
static_assert(2*NUM_CONTROLLERS == INPUTS_LEN);

bool isGateActive[NUM_CONTROLLERS];

Moots()
{
for (int i = 0; i < NUM_CONTROLLERS; ++i)
isGateActive[i] = false;

config(PARAMS_LEN, INPUTS_LEN, OUTPUTS_LEN, LIGHTS_LEN);
configButton(TOGGLEBUTTON1_PARAM, "Moot 1");
configButton(TOGGLEBUTTON2_PARAM, "Moot 2");
Expand All @@ -73,11 +84,19 @@ struct Moots : Module
configOutput(OUTAUDIO5_OUTPUT, "Signal 5");
}

void onReset(const ResetEvent& e) override
{
Module::onReset(e);

for (int i = 0; i < NUM_CONTROLLERS; ++i)
isGateActive[i] = false;
}

void process(const ProcessArgs& args) override
{
float volts[PORT_MAX_CHANNELS];

for (int i = 0; i < PARAMS_LEN; ++i)
for (int i = 0; i < NUM_CONTROLLERS; ++i)
{
auto & gate = inputs[INGATE1_INPUT + i];

Expand All @@ -86,7 +105,20 @@ struct Moots : Module
{
// If the gate input is connected, use the voltage of its first channel
// to control whether the output is enabled or disabled.
active = gate.getVoltage(0) >= 4.0f;
// Debounce the signal using hysteresis like a Schmitt trigger would.
// See: https://vcvrack.com/manual/VoltageStandards#Triggers-and-Gates
const float gv = gate.getVoltage(0);
if (isGateActive[i])
{
if (gv <= 0.1f)
isGateActive[i] = false;
}
else
{
if (gv >= 1.0f)
isGateActive[i] = true;
}
active = isGateActive[i];
}
else
{
Expand Down

0 comments on commit a6c9363

Please sign in to comment.