Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Effects

Signal processing effects for shaping sound character.

Saturator

Soft clipping distortion based on analog saturation curves.

use quiver::analog::{Saturator, saturation};

let sat = patch.add("saturator", Saturator::new(saturation::tanh_sat));

Inputs

PortSignalDescription
inAudioInput signal
driveUnipolar CVSaturation amount

Output

PortSignalDescription
outAudioSaturated output

Saturation Types

FunctionCharacter
tanh_satSmooth, tube-like
soft_clipAdjustable knee
asym_satEven harmonics
diode_clipHard, aggressive

Wavefolder

Creates complex harmonics through wavefolding.

let folder = patch.add("folder", Wavefolder::new());

Inputs

PortSignalDescription
inAudioInput signal
foldsUnipolar CVNumber of folds

Output

PortSignalDescription
outAudioFolded output

The Folding Process

Input:   ╱╲
        ╱  ╲
       ╱    ╲

1 Fold: ╱╲╱╲
       ╱    ╲

2 Folds: ╱╲╱╲╱╲╱╲
        ╱      ╲

$$y = \sin(f \cdot \pi \cdot x)$$

Where $f$ is the fold amount.


Crosstalk

Simulates channel bleed between left and right.

let crosstalk = patch.add("xtalk", Crosstalk::new());

Inputs

PortSignalDescription
leftAudioLeft channel
rightAudioRight channel
amountUnipolar CVBleed amount (0-10%)

Outputs

PortSignalDescription
leftAudioLeft with right bleed
rightAudioRight with left bleed

The Effect

$$L_{out} = L_{in} + \text{amount} \cdot R_{in}$$ $$R_{out} = R_{in} + \text{amount} \cdot L_{in}$$

Adds subtle width and analog character.


Ground Loop

Simulates 50/60Hz power supply hum.

let hum = patch.add("hum", GroundLoop::new(44100.0));

Inputs

PortSignalDescription
amountUnipolar CVHum level

Output

PortSignalDescription
outAudioHum signal

Configuration

let hum = GroundLoop::new(44100.0)
    .with_frequency(60.0)   // 60Hz (US) or 50Hz (EU)
    .with_harmonics(3);     // Include 2nd and 3rd harmonics

Mix very subtly for vintage authenticity.


Scope

Real-time waveform visualization.

let scope = patch.add("scope", Scope::new(44100.0));

Inputs

PortSignalDescription
inAudioSignal to display
triggerGateTrigger sync

Trigger Modes

ModeDescription
FreeContinuous display
RisingEdgeSync on positive zero-cross
FallingEdgeSync on negative zero-cross
SingleOne-shot capture

Reading the Buffer

let waveform = scope.buffer();
// Vec<f64> of recent samples

Spectrum Analyzer

FFT-based frequency analysis.

let analyzer = patch.add("spectrum", SpectrumAnalyzer::new(44100.0));

Input

PortSignalDescription
inAudioSignal to analyze

Reading Data

let bins = analyzer.bins();           // Frequency bins
let mags = analyzer.magnitudes();     // dB values
let peak = analyzer.peak_frequency(); // Dominant frequency

Level Meter

RMS and peak level monitoring.

let meter = patch.add("meter", LevelMeter::new(44100.0));

Input

PortSignalDescription
inAudioSignal to meter

Reading Levels

let rms = meter.rms();       // RMS level in volts
let peak = meter.peak();     // Peak level
let rms_db = meter.rms_db(); // RMS in dB

Peak Hold

let meter = LevelMeter::new(44100.0)
    .with_peak_hold(500.0);  // 500ms hold time

Building Effect Chains

Serial Processing

// Input → Saturator → Filter → Output
patch.connect(input, sat.in_("in"))?;
patch.connect(sat.out("out"), vcf.in_("in"))?;
patch.connect(vcf.out("lp"), output)?;

Parallel Processing

// Dry/wet mix
patch.connect(input, mult.in_("in"))?;
patch.connect(mult.out("out_1"), effect.in_("in"))?;  // Wet
patch.connect(mult.out("out_2"), xfade.in_("a"))?;    // Dry
patch.connect(effect.out("out"), xfade.in_("b"))?;    // Wet

Feedback Loop

// With unit delay to prevent infinite loop
patch.connect(effect.out("out"), delay.in_("in"))?;
patch.connect(delay.out("out"), atten.in_("in"))?;  // Feedback amount
patch.connect(atten.out("out"), effect.in_("in"))?;