Skip to content

Oscillator

Tier: Primitives | ComponentType: 0 | Params: 3

Multi-waveform oscillator with wavetable morphing support.

Overview

The Oscillator generates periodic waveforms via phase accumulation. It supports six waveform types: sine, triangle, square, sawtooth, white noise, and custom wavetables. In wavetable mode, multi-frame tables can be smoothly morphed between frames using a position parameter.

At sub-Hz frequencies it acts as an LFO; at audio rate it's a tone generator; at high frequencies it becomes a whistle or modulator. The same component covers the entire range — no artificial ceiling separates "LFO" from "oscillator."

The wavetable engine supports 10 single-frame algorithmic presets (WarmAsymmetric, ExponentialRise, Plateau, etc.) and 5 multi-frame morphing presets (SineToSquare, OrganDrawbars, etc.) with 8 frames each and smooth cross-frame interpolation.

File Locations

Path
Header Sources/FolioDSP/include/FolioDSP/Primitives/Oscillator.h
Implementation Sources/FolioDSP/src/Primitives/Oscillator.cpp
Tests Tests/FolioDSPTests/OscillatorTests.swift
Bridge Sources/FolioDSPBridge/src/FolioDSPBridge.mm (OscillatorBridge)

Parameters

Index Name Description Min Max Default Min Default Max Default Unit
0 Frequency Oscillator frequency — sub-Hz for LFO, audio rate for tones 0.01 20000.0 0.1 2000.0 1.0 Hz
1 Waveform Waveform selection: 0=Sine, 1=Tri, 2=Square, 3=Saw, 4=Noise, 5=Wavetable 0.0 5.0 0.0 5.0 0.0
2 Morph Position Crossfade position between wavetable frames (wavetable mode only) 0.0 1.0 0.0 1.0 0.0

Processing Algorithm

1. Waveform Generation

The oscillator generates one sample per call based on the current phase:

  • Sine: \(y = \sin(\phi)\)
  • Triangle: \(y = 4 \cdot |t - 0.5| - 1\) where \(t = \phi / 2\pi\)
  • Square: \(y = \begin{cases} 1 & \phi < \pi \\ -1 & \phi \geq \pi \end{cases}\)
  • Sawtooth: \(y = 2t - 1\) where \(t = \phi / 2\pi\)
  • Noise: xorshift32 PRNG, independent of phase
  • Wavetable: Linear interpolation within frame, cross-frame morph blending

2. Phase Accumulation

\[\phi \leftarrow \phi + \frac{2\pi f}{f_s}\]

Phase wraps at \(2\pi\).

3. Wavetable Morphing (multi-frame)

For multi-frame wavetables, two adjacent frames are blended:

\[\text{framePos} = \text{morph} \cdot (N_{\text{frames}} - 1)\]
\[y = (1 - \text{frac}) \cdot \text{frame}_0[t] + \text{frac} \cdot \text{frame}_1[t]\]

Within each frame, samples are linearly interpolated.

Snapshot Fields

Field Type Range Unit Description
Phase Float 0–1 Normalized phase position
Output Float -1–1 Current output sample
Frequency Float 0.01–20000 Hz Current frequency
Waveform Float 0–5 Active waveform type
Wavetable Uint8 0–1 Whether wavetable is loaded
Morph Float 0–1 Current morph position
Frames Float 0–256 Number of wavetable frames
Preview Float[32] -1–1 32-point waveform preview

Implementation Notes

  • xorshift32 PRNG for noise: state ^= state << 13; state ^= state >> 17; state ^= state << 5
  • Wavetable loading via loadWaveform() (single-frame) or loadWavetable() (multi-frame)
  • 10 single-frame presets synthesized at 256 samples; 5 multi-frame presets with 8 frames each
  • 32-point waveform preview computed in snapshot emission, not per-sample
  • All parameters use std::atomic<float> with relaxed memory order

Equation Summary

phase += 2π·f/sr; y = waveform(phase)