Your First DSP Graph

This tutorial walks you through creating your first audio processing graph with bbx_audio.

Prerequisites

Add bbx_dsp to your project:

[dependencies]
bbx_dsp = "0.1"

Creating a Graph

DSP graphs in bbx_audio are built using GraphBuilder:

use bbx_dsp::graph::GraphBuilder;

fn main() {
    // Create a builder with:
    // - 44100 Hz sample rate
    // - 512 sample buffer size
    // - 2 channels (stereo)
    let mut builder = GraphBuilder::<f32>::new(44100.0, 512, 2);

    // Build the graph
    let graph = builder.build();
}

Adding an Oscillator

Let's add a sine wave oscillator:

use bbx_dsp::{
    blocks::OscillatorBlock,
    graph::GraphBuilder,
    waveform::Waveform,
};

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

    // Add a 440 Hz sine wave oscillator
    // The third parameter is an optional seed for the random number generator
    // (used by the Noise waveform for deterministic output)
    let osc = builder.add(OscillatorBlock::new(440.0, Waveform::Sine, None));

    let graph = builder.build();
}

The add method returns a BlockId that you can use to connect blocks.

Processing Audio

Once you have a graph, you can process audio:

use bbx_dsp::{
    blocks::OscillatorBlock,
    graph::GraphBuilder,
    waveform::Waveform,
};

fn main() {
    let mut builder = GraphBuilder::<f32>::new(44100.0, 512, 2);
    let _osc = builder.add(OscillatorBlock::new(440.0, Waveform::Sine, None));
    let mut graph = builder.build();

    // Create output buffers
    let mut left = vec![0.0f32; 512];
    let mut right = vec![0.0f32; 512];

    // Process into the buffers
    let mut outputs: [&mut [f32]; 2] = [&mut left, &mut right];
    graph.process_buffers(&mut outputs);

    // left and right now contain 512 samples of a 440 Hz sine wave
    println!("First sample: {}", left[0]);
}

Connecting Blocks

Blocks are connected using the connect method:

use bbx_dsp::{
    blocks::{GainBlock, OscillatorBlock},
    graph::GraphBuilder,
    waveform::Waveform,
};

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

    // Add blocks
    let osc = builder.add(OscillatorBlock::new(440.0, Waveform::Sine, None));
    let gain = builder.add(GainBlock::new(-6.0, None));  // -6 dB

    // Connect oscillator output 0 to gain input 0
    builder.connect(osc, 0, gain, 0);

    let graph = builder.build();
}

Understanding Block IDs

Each block added to the graph gets a unique BlockId:

#![allow(unused)]
fn main() {
let osc = builder.add(OscillatorBlock::new(440.0, Waveform::Sine, None));  // Block 0
let gain = builder.add(GainBlock::new(-6.0, None));                        // Block 1
let pan = builder.add(PannerBlock::new(0.0));                              // Block 2
}

Use these IDs when connecting blocks:

#![allow(unused)]
fn main() {
builder.connect(from_block, from_port, to_block, to_port);
}

Complete Example

use bbx_dsp::{
    blocks::{GainBlock, OscillatorBlock, PannerBlock},
    graph::GraphBuilder,
    waveform::Waveform,
};

fn main() {
    // Create builder
    let mut builder = GraphBuilder::<f32>::new(44100.0, 512, 2);

    // Build a simple synth chain
    let osc = builder.add(OscillatorBlock::new(440.0, Waveform::Saw, None));
    let gain = builder.add(GainBlock::new(-12.0, None));
    let pan = builder.add(PannerBlock::new(25.0));  // Slightly right

    // Connect: Osc -> Gain -> Panner
    builder.connect(osc, 0, gain, 0);
    builder.connect(gain, 0, pan, 0);

    // Build the graph
    let mut graph = builder.build();

    // Process multiple buffers
    let mut left = vec![0.0f32; 512];
    let mut right = vec![0.0f32; 512];

    for _ in 0..100 {
        let mut outputs: [&mut [f32]; 2] = [&mut left, &mut right];
        graph.process_buffers(&mut outputs);

        // Do something with the audio...
    }
}

Next Steps

Choose your learning path: