SUPERB
Examples

session_steps

examples/flows/session_steps.rs, the whole program

Run it with cargo run --example session_steps (see the examples for the features some need).

//! `session::steps` is four functions. They are the engine side of
//! `session` — the verbs (`track::add`, `clip::add`) call them; you can
//! call them too.
//!
//! ```text
//! rebuild(session)                        from Memory, build a mixer, swap it into the engine
//! render_blocks(session, n) -> audio      run n blocks with no sound card
//! build_mixer(&memory, &audio, channels)  just the mixer; no Session
//! publish(&mut engine, mixer)             just the swap
//! ```
//!
//! ```text
//! use superb::primitives::buffers::PlanarBuffer;
//! use superb::primitives::session::TrackKind;
//! use superb::primitives::{SampleRate, TimePosition};
//! use superb::{clip, session, track, transport};
//!
//! fn main() -> superb::primitives::Result<()> {
//!     let folder = std::env::temp_dir().join("steps");
//!     let mut session = session::create(&folder, SampleRate::HZ_48K, 256)?;
//!
//!     let vox = track::add(&mut session, "vox", TrackKind::Audio)?;
//!     let mut tone = PlanarBuffer::new(2, 48_000);
//!     tone.fill(0.5);
//!     session.audio.insert("audio/tone.wav", tone);
//!     clip::add(&mut session, vox, "audio/tone.wav", TimePosition::ZERO)?;
//!
//!     transport::start(&mut session)?;
//!     let heard = session::steps::render_blocks(&mut session, 8)?;
//!     println!("{}", heard.peak());
//!     Ok(())
//! }
//! ```
//!
//! This file uses `build_mixer` with no Session.
//!
//! ```text
//! cargo run --example session_steps
//! ```

use std::path::PathBuf;

use superb::primitives::buffers::PlanarBuffer;
use superb::primitives::io::cache::AudioCache;
use superb::primitives::io::wav::{self, WavFormat};
use superb::primitives::io::{offline, Engine};
use superb::primitives::session::{Clip, ClipSource, Memory, MidiNote, TrackKind, TrackSend};
use superb::primitives::transport::Transport;
use superb::primitives::{Result, SampleRate, TimeDuration, TimePosition};
use superb::session;

fn main() -> Result<()> {
    let rate = SampleRate::HZ_48K;
    // 48 kHz, tempo 120. Starts with a master bus.
    let mut memory = Memory::new("session-steps", rate);

    // Audio track. 0.5 s of 0.2, cached as "audio/tone.wav". Clip at 0.25 s.
    let vox = memory.add_track("vox", TrackKind::Audio);
    let mut tone = PlanarBuffer::new(2, 24_000);
    tone.fill(0.2);
    let mut cache = AudioCache::new();
    cache.insert("audio/tone.wav", tone);
    memory.add_clip(
        vox,
        Clip::new(
            "take",
            TimePosition::from_samples(12_000),
            TimeDuration::from_samples(24_000),
            ClipSource::Audio {
                path: PathBuf::from("audio/tone.wav"),
                offset: TimeDuration::ZERO,
            },
        )?,
    )?;

    // MIDI track at -3 dB. One note 69 from beat 0 for 0.5 beats. Clip is 1 s.
    let keys = memory.add_track("keys", TrackKind::Midi);
    memory.track_mut(keys)?.state.volume_db = -3.0;
    memory.add_clip(
        keys,
        Clip::new(
            "a4",
            TimePosition::ZERO,
            TimeDuration::from_samples(48_000),
            ClipSource::Midi {
                notes: vec![MidiNote {
                    beat: 0.0,
                    length: 0.5,
                    note: 69,
                    velocity: 100,
                    channel: 0,
                }],
            },
        )?,
    )?;

    // Bus at -6 dB. keys routes into it. vox sends into it at -12 dB, pre-fader.
    let room = memory.add_track("room", TrackKind::Bus);
    memory.track_mut(room)?.state.volume_db = -6.0;
    memory.set_track_output(keys, Some(room))?;
    let send = memory.add_send(vox, TrackSend::new(room).level_db(-12.0).pre_fader())?;

    let (mixer, handles) = session::steps::build_mixer(&memory, &cache, 2)?;
    println!(
        "{} tracks became {} strips, {} send(s); the graph has {} nodes",
        memory.track_count(),
        handles.strips.len(),
        handles.sends.len(),
        mixer.graph().node_count()
    );
    for (track, strip) in &handles.strips {
        println!(
            "  {} at {:.1} dB{}",
            memory.track(*track)?.name,
            strip.volume_db(),
            if strip.is_muted() { " (muted)" } else { "" }
        );
    }
    println!(
        "  vox send at {:.1} dB, on: {}",
        handles.send(send).map_or(0.0, |s| s.level_db()),
        handles.send(send).is_some_and(|s| s.is_enabled())
    );

    // Playing; render 1 s in blocks of 256.
    let mut transport = Transport::with_tempo_map(memory.tempo_map().clone());
    transport.play();
    let mut engine = Engine::new(mixer, transport);
    let audio = offline::render(&mut engine, rate, 256, 48_000)?;
    println!(
        "rendered {} frames, peak {:.3}",
        audio.frames(),
        audio.peak()
    );

    let path = std::env::temp_dir().join("session_steps.wav");
    wav::write(&path, &audio, rate, WavFormat::Float32)?;
    println!("wrote {}", path.display());
    Ok(())
}