Skip to content

LFO

The LFO (Low Frequency Oscillator) component generates slow-moving control voltage signals for modulating other parameters. It's essential for creating vibrato, tremolo, filter sweeps, and other modulation effects.

Props

PropTypeDefaultDescription
outputModStreamRefRequiredReference to output the CV signal
labelstring'lfo'Label for the component in metadata
frequencynumber1Frequency in Hz (controlled or initial value), typically 0.1-20 Hz
onFrequencyChange(frequency: number) => void-Callback when frequency changes
amplitudenumber1Amplitude 0-1 (controlled or initial value)
onAmplitudeChange(amplitude: number) => void-Callback when amplitude changes
waveformLFOWaveform'sine'Waveform type (controlled or initial value): 'sine', 'square', 'sawtooth', or 'triangle'
onWaveformChange(waveform: LFOWaveform) => void-Callback when waveform changes
childrenfunction-Render prop function receiving control props

Render Props

When using the children render prop, the following controls are provided:

PropertyTypeDescription
frequencynumberCurrent frequency in Hz (typically 0.1-20 Hz)
setFrequency(value: number) => voidUpdate the frequency
amplitudenumberCurrent amplitude (0-1)
setAmplitude(value: number) => voidUpdate the amplitude
waveformLFOWaveformCurrent waveform type
setWaveform(value: LFOWaveform) => voidUpdate the waveform
isActivebooleanWhether the LFO is running

Waveform Types

  • 'sine' - Smooth, rounded modulation
  • 'square' - Hard on/off switching
  • 'sawtooth' - Linear ramp up, instant reset
  • 'triangle' - Linear up and down

Usage

Basic Usage

tsx
import { LFO, ToneGenerator, Monitor } from '@mode-7/mod';
import { useRef } from 'react';

function App() {
  const lfoOut = useRef(null);
  const toneOut = useRef(null);

  return (
    <>
      <LFO output={lfoOut} />
      <ToneGenerator
        output={toneOut}
        frequency={440}
        cv={lfoOut}
        cvAmount={50}  // Vibrato of ±50Hz
      />
      <Monitor input={toneOut} />
    </>
  );
}

With UI Controls

tsx
import { LFO } from '@mode-7/mod';
import { useRef } from 'react';

function App() {
  const lfoOut = useRef(null);

  return (
    <LFO output={lfoOut}>
      {({ frequency, setFrequency, amplitude, setAmplitude, waveform, setWaveform }) => (
        <div>
          <div>
            <label>Frequency: {frequency.toFixed(2)} Hz</label>
            <input
              type="range"
              min="0.1"
              max="20"
              step="0.1"
              value={frequency}
              onChange={(e) => setFrequency(Number(e.target.value))}
            />
          </div>

          <div>
            <label>Amplitude: {amplitude.toFixed(2)}</label>
            <input
              type="range"
              min="0"
              max="1"
              step="0.01"
              value={amplitude}
              onChange={(e) => setAmplitude(Number(e.target.value))}
            />
          </div>

          <div>
            <label>Waveform:</label>
            <select value={waveform} onChange={(e) => setWaveform(e.target.value as any)}>
              <option value="sine">Sine</option>
              <option value="square">Square</option>
              <option value="sawtooth">Sawtooth</option>
              <option value="triangle">Triangle</option>
            </select>
          </div>
        </div>
      )}
    </LFO>
  );
}

Filter Sweep

tsx
import { LFO, ToneGenerator, Filter, Monitor } from '@mode-7/mod';
import { useRef } from 'react';

function App() {
  const lfoOut = useRef(null);
  const toneOut = useRef(null);
  const filterOut = useRef(null);

  return (
    <>
      <LFO output={lfoOut}>
        {({ setFrequency, setWaveform }) => {
          // Initialize on mount
          React.useEffect(() => {
            setFrequency(0.5);  // Slow sweep
            setWaveform('triangle');
          }, []);
          return null;
        }}
      </LFO>
      <ToneGenerator output={toneOut} waveform="sawtooth" />
      <Filter
        input={toneOut}
        output={filterOut}
        type="lowpass"
        frequency={500}
        cv={lfoOut}
        cvAmount={2000}  // Sweep from 500Hz to 2500Hz
      />
      <Monitor input={filterOut} />
    </>
  );
}

Tremolo Effect

tsx
import { LFO, ToneGenerator, Monitor } from '@mode-7/mod';
import { useRef } from 'react';

function App() {
  const lfoOut = useRef(null);
  const toneOut = useRef(null);

  return (
    <>
      <LFO output={lfoOut}>
        {({ setFrequency, setAmplitude, setWaveform }) => {
          React.useEffect(() => {
            setFrequency(5);  // 5 Hz tremolo
            setAmplitude(0.5);
            setWaveform('sine');
          }, []);
          return null;
        }}
      </LFO>
      <ToneGenerator
        output={toneOut}
        frequency={440}
        // Note: For amplitude modulation, use with a VCA or gain control
      />
      <Monitor input={toneOut} />
    </>
  );
}

Controlled Props

You can control the LFO from external state using controlled props:

tsx
import { LFO, ToneGenerator, Monitor } from '@mode-7/mod';
import { useState, useRef } from 'react';

function App() {
  const lfoOut = useRef(null);
  const toneOut = useRef(null);
  const [frequency, setFrequency] = useState(2.0);
  const [amplitude, setAmplitude] = useState(1.0);
  const [waveform, setWaveform] = useState<LFOWaveform>('sine');

  return (
    <>
      <LFO
        output={lfoOut}
        frequency={frequency}
        onFrequencyChange={setFrequency}
        amplitude={amplitude}
        onAmplitudeChange={setAmplitude}
        waveform={waveform}
        onWaveformChange={setWaveform}
      />

      <div>
        <label>LFO Rate: {frequency.toFixed(2)} Hz</label>
        <input
          type="range"
          min="0.1"
          max="20"
          step="0.1"
          value={frequency}
          onChange={(e) => setFrequency(Number(e.target.value))}
        />
      </div>

      <div>
        <label>Depth: {amplitude.toFixed(2)}</label>
        <input
          type="range"
          min="0"
          max="1"
          step="0.01"
          value={amplitude}
          onChange={(e) => setAmplitude(Number(e.target.value))}
        />
      </div>

      <ToneGenerator
        output={toneOut}
        frequency={440}
        cv={lfoOut}
        cvAmount={100}
      />
      <Monitor input={toneOut} />
    </>
  );
}

Imperative Refs

For programmatic access to state, you can use refs:

tsx
import { LFO, LFOHandle, ToneGenerator, Monitor } from '@mode-7/mod';
import { useRef, useEffect } from 'react';

function App() {
  const lfoRef = useRef<LFOHandle>(null);
  const lfoOut = useRef(null);
  const toneOut = useRef(null);

  useEffect(() => {
    // Access current state
    if (lfoRef.current) {
      const state = lfoRef.current.getState();
      console.log('Frequency:', state.frequency);
      console.log('Amplitude:', state.amplitude);
      console.log('Waveform:', state.waveform);
    }
  }, []);

  return (
    <>
      <LFO ref={lfoRef} output={lfoOut} />
      <ToneGenerator
        output={toneOut}
        frequency={440}
        cv={lfoOut}
        cvAmount={20}  // Vibrato of ±20Hz
      />
      <Monitor input={toneOut} />
    </>
  );
}

Note: The imperative handle provides read-only access via getState(). To control the LFO programmatically, use the controlled props pattern shown above.

Important Notes

Frequency Range

  • LFOs typically operate at sub-audio frequencies (0.1 - 20 Hz)
  • Lower frequencies create slow, sweeping modulations
  • Higher frequencies create faster, vibrato-like effects
  • At very high frequencies (20+ Hz), the LFO enters audio rate

Modulation Depth

  • The amplitude parameter controls the output level of the CV signal
  • The receiving module's cvAmount parameter scales this further
  • Together, these control the depth of modulation

Starting Phase

  • The LFO starts immediately when mounted
  • Initial phase is 0 (starting from the waveform's minimum value for most types)
  • ToneGenerator - Modulate frequency for vibrato
  • Filter - Modulate filter cutoff
  • Panner - Modulate stereo position
  • ADSR - For envelope-based modulation

Released under the MIT License.