#pragma once #include namespace rack { namespace dsp { /** Detects when a boolean changes from false to true */ struct BooleanTrigger { bool state = true; void reset() { state = true; } bool process(bool state) { bool triggered = (state && !this->state); this->state = state; return triggered; } }; /** Turns HIGH when value reaches a threshold (default 0.f), turns LOW when value reaches a threshold (default 1.f). */ template struct TSchmittTrigger { T state; TSchmittTrigger() { reset(); } void reset() { state = T::mask(); } T process(T in, T offThreshold = 0.f, T onThreshold = 1.f) { T on = (in >= onThreshold); T off = (in <= offThreshold); T triggered = ~state & on; state = on | (state & ~off); return triggered; } T isHigh() { return state; } }; template <> struct TSchmittTrigger { bool state = true; void reset() { state = true; } /** Updates the state of the Schmitt Trigger given a value. Returns true if triggered, i.e. the value increases from 0 to 1. If different trigger thresholds are needed, use process(in, 0.1f, 2.f) for example. */ bool process(float in, float offThreshold = 0.f, float onThreshold = 1.f) { if (state) { // HIGH to LOW if (in <= offThreshold) { state = false; } } else { // LOW to HIGH if (in >= onThreshold) { state = true; return true; } } return false; } bool isHigh() { return state; } }; typedef TSchmittTrigger<> SchmittTrigger; /** When triggered, holds a high value for a specified time before going low again */ struct PulseGenerator { float remaining = 0.f; /** Immediately disables the pulse */ void reset() { remaining = 0.f; } /** Advances the state by `deltaTime`. Returns whether the pulse is in the HIGH state. */ bool process(float deltaTime) { if (remaining > 0.f) { remaining -= deltaTime; return true; } return false; } /** Begins a trigger with the given `duration`. */ void trigger(float duration = 1e-3f) { // Keep the previous pulse if the existing pulse will be held longer than the currently requested one. if (duration > remaining) { remaining = duration; } } }; /** Accumulates a timer when process() is called. */ template struct TTimer { T time = 0.f; void reset() { time = 0.f; } /** Returns the time since last reset or initialization. */ T process(T deltaTime) { time += deltaTime; return time; } T getTime() { return time; } }; typedef TTimer<> Timer; /** Counts calls to process(), returning true every `division` calls. Example: if (divider.process()) { // Runs every `division` calls } */ struct ClockDivider { uint32_t clock = 0; uint32_t division = 1; void reset() { clock = 0; } void setDivision(uint32_t division) { this->division = division; } uint32_t getDivision() { return division; } uint32_t getClock() { return clock; } /** Returns true when the clock reaches `division` and resets. */ bool process() { clock++; if (clock >= division) { clock = 0; return true; } return false; } }; } // namespace dsp } // namespace rack