Skip to content

️🛠 - Enhance the LfoBlock capabilities #64

Description

@maxwellmattryan

Description

The current LfoBlock implementation provides basic functionality but lacks several standard features found in typical synthesizer LFOs. While the codebase already has 6 waveforms implemented (Sine, Square, Sawtooth, Triangle, Pulse, Noise), only Sine is currently exposed through the GraphBuilder API.

Current capabilities:

  • Frequency parameter (0.01 Hz to ~43 Hz at 44.1kHz/512 buffer)
  • Depth parameter (amplitude scaling)
  • Both parameters are modulatable
  • SIMD-optimized processing
  • Control-rate output (one value per buffer)

Missing standard LFO features:

  1. Waveform selection - Waveforms exist internally but aren't exposed to users
  2. Offset/polarity control - No way to shift output range (e.g., unipolar 0-1 vs bipolar -1 to 1)
  3. Fade-in/delay - No gradual onset for modulation
  4. Phase sync/retrigger - No mechanism to reset phase on note-on or sync to external events
  5. Tempo sync - No integration with host tempo/BPM

Open questions

  • Should waveform be a runtime-changeable parameter, or set once at construction?
  • Should we add a simple unipolar / bipolar toggle, a continuous offset parameter, or both?
  • In a plugin context, can the LFO access note-on events from the DSP layer? If not, retrigger functionality may need to be deferred or limited to standalone / terminal synth use cases. Alternative approaches include:
    • Expose a reset_phase() method that external code can call
    • Accept a trigger input from another block
    • Defer to a future issue once MIDI routing to modulators is established
  • How should tempo / BPM be communicated to the LFO?
    • Via a parameter that the host / plugin sets each buffer
    • Via a dedicated tempo input from the graph context
    • Tempo sync note divisions (1/4, 1/8, 1/16, dotted, triplet, etc.)
  • Should users be able to set an initial phase offset (0-360 degrees)? Useful for layering multiple LFOs
  • Should fade-in time be time-based (seconds) or tempo-synced (bars/beats)? Should it restart on retrigger?

Acceptance criteria

Waveform Selection

  • Users can select from all available waveforms (Sine, Square, Sawtooth, Triangle, Pulse, Noise) when creating an LFO
  • The selected waveform produces the expected output shape

Offset/Polarity Control

  • Users can configure the LFO to output in bipolar mode (-1 to +1, centered at 0)
  • Users can configure the LFO to output in unipolar mode (0 to +1)
  • The depth parameter correctly scales the output in both modes

Fade-In/Delay

  • Users can configure a delay time before the LFO begins modulating
  • Users can configure a fade-in time for gradual modulation onset
  • The LFO output smoothly transitions from zero to full depth during fade-in

Tempo Sync

  • Users can sync LFO rate to tempo (BPM) instead of specifying frequency in Hz
  • Standard note divisions are available (1/1, 1/2, 1/4, 1/8, 1/16, 1/32)
  • Dotted and triplet variants are available for each division
  • LFO rate updates correctly when tempo changes

Phase Reset

  • Users can programmatically reset the LFO phase
  • Phase resets happen cleanly without audible artifacts
  • Free-running mode (current behavior) remains available

Documentation

  • LFO documentation reflects all new parameters and modes
  • Examples demonstrate common LFO configurations (e.g., tempo-synced tremolo, unipolar vibrato with fade-in)

Tasks

TBD

Metadata

Metadata

Labels

No labels
No labels
No fields configured for Enhancement.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions