VcaBlock

Voltage Controlled Amplifier - multiplies audio by a control signal.

Overview

VcaBlock multiplies an audio signal by a control signal sample-by-sample. This is the standard way to apply envelope control to audio in synthesizers.

Creating a VCA Block

#![allow(unused)]
fn main() {
use bbx_dsp::{blocks::VcaBlock, graph::GraphBuilder};

let mut builder = GraphBuilder::<f32>::new(44100.0, 512, 2);

let vca = builder.add(VcaBlock::new());
}

Port Layout

PortDirectionDescription
0InputAudio signal
1InputControl signal (0.0 to 1.0)
0OutputModulated audio

Parameters

VcaBlock has no parameters - it simply multiplies its two inputs together.

Usage Examples

Envelope-Controlled Amplitude

The most common use case: apply an ADSR envelope to an oscillator.

#![allow(unused)]
fn main() {
use bbx_dsp::{
    blocks::{EnvelopeBlock, OscillatorBlock, VcaBlock},
    graph::GraphBuilder,
    waveform::Waveform,
};

let mut builder = GraphBuilder::<f32>::new(44100.0, 512, 2);

// Signal chain: Oscillator → VCA ← Envelope
let osc = builder.add(OscillatorBlock::new(440.0, Waveform::Saw, None));
let env = builder.add(EnvelopeBlock::new(0.01, 0.1, 0.7, 0.3));
let vca = builder.add(VcaBlock::new());

// Audio to VCA input 0
builder.connect(osc, 0, vca, 0);

// Envelope to VCA input 1 (control)
builder.connect(env, 0, vca, 1);
}

LFO Tremolo

Use an LFO for amplitude modulation (tremolo effect):

#![allow(unused)]
fn main() {
use bbx_dsp::{
    blocks::{LfoBlock, OscillatorBlock, VcaBlock},
    graph::GraphBuilder,
    waveform::Waveform,
};

let mut builder = GraphBuilder::<f32>::new(44100.0, 512, 2);

let osc = builder.add(OscillatorBlock::new(440.0, Waveform::Sine, None));
let lfo = builder.add(LfoBlock::new(6.0, 0.5, Waveform::Sine, None));  // 6 Hz, 50% depth
let vca = builder.add(VcaBlock::new());

builder.connect(osc, 0, vca, 0);
builder.connect(lfo, 0, vca, 1);
}

Subtractive Synth Voice

Complete synthesizer voice with oscillator, envelope, filter, and VCA:

#![allow(unused)]
fn main() {
use bbx_dsp::{
    blocks::{EnvelopeBlock, GainBlock, LowPassFilterBlock, OscillatorBlock, VcaBlock},
    graph::GraphBuilder,
    waveform::Waveform,
};

let mut builder = GraphBuilder::<f32>::new(44100.0, 512, 2);

// Sound source
let osc = builder.add(OscillatorBlock::new(440.0, Waveform::Saw, None));

// Amplitude envelope
let env = builder.add(EnvelopeBlock::new(0.01, 0.1, 0.7, 0.3));

// VCA for envelope control
let vca = builder.add(VcaBlock::new());

// Filter and output gain
let filter = builder.add(LowPassFilterBlock::new(2000.0, 1.5));
let gain = builder.add(GainBlock::new(-6.0, None));

// Connect: Osc → VCA → Filter → Gain
builder
    .connect(osc, 0, vca, 0)
    .connect(env, 0, vca, 1)
    .connect(vca, 0, filter, 0)
    .connect(filter, 0, gain, 0);
}

Behavior

  • When control input is missing, defaults to 1.0 (unity gain)
  • When audio input is missing, outputs silence
  • Output is sample-by-sample multiplication: output[i] = audio[i] * control[i]

VCA vs GainBlock

FeatureVcaBlockGainBlock
ControlSample-by-sample from inputFixed dB parameter
Use caseEnvelope/LFO modulationStatic level control
Inputs2 (audio + control)1 (audio only)

Use VCA for dynamic amplitude control. Use Gain for static level adjustments.

Implementation Notes

  • No internal state or smoothing
  • Zero-latency processing
  • Handles any buffer size