Skip to main content

Mixer

Struct Mixer 

Source
pub struct Mixer { /* private fields */ }
Expand description

A routing stereo mixer of audio sources — instruments, the SFX Engine, StreamSources. Each source feeds a bus; buses carry live insert chains (reverb / EQ / compressor / …) and post-fader sends into shared FX/return buses, all summing through a master insert chain. It is itself an AudioSource, so it feeds one output callback (or nests).

With no buses or effects created, every source sits on the master bus at unity and the output is a plain additive sum — byte-identical to a bare mixer. Live effects need a sample rate: build with Mixer::new.

use tono_core::prelude::*;
use tono_core::dsl::Node;

let mut mixer = Mixer::new(48_000);
let sfx = mixer.bus("sfx");

let mut engine = Engine::new(48_000);
let drone = engine.load(&SoundDoc::new("drone", Node::Sine { freq: 110.0.into() }));
engine.play_looping(drone);
mixer.add_to(sfx, engine);             // the engine feeds the sfx bus
mixer.set_bus_gain(sfx, 0.8);          // a live fader

let mut out = vec![0.0f32; 512];
mixer.fill(&mut out);                  // one callback serves the whole desk
assert!(out.iter().any(|s| s.abs() > 0.0));

Implementations§

Source§

impl Mixer

Source

pub fn new(sample_rate: u32) -> Self

An empty mixer that renders at sample_rate, so buses can carry live effect chains (every other runtime constructor — Engine::new, AdaptiveMusic::new, Instrument::new — takes the rate up front too).

Examples found in repository?
examples/play_instrument.rs (line 64)
31fn main() {
32    let sr = 48_000;
33    let design = InstrumentDesign::new(lead()).with_amp(Adsr {
34        a: 0.01,
35        d: 0.15,
36        s: 0.6,
37        r: 0.25,
38        punch: 0.0,
39    });
40    let mut inst = Instrument::new(design, sr).expect("streamable instrument");
41
42    // --- Play a C-major chord, hold, then release -------------------------
43    inst.note_on(n("C4"), 0.9);
44    inst.note_on(n("E4"), 0.8);
45    inst.note_on(n("G4"), 0.7);
46    println!("chord: {} voices", inst.active_voices());
47
48    let mut block = vec![0.0f32; 512 * 2];
49    let mut p = 0.0f32;
50    for _ in 0..40 {
51        inst.fill(&mut block);
52        p = p.max(peak(&block));
53    }
54    inst.all_notes_off();
55    for _ in 0..60 {
56        inst.fill(&mut block);
57    }
58    println!(
59        "after release: {} voices (chord peak {p:.3})",
60        inst.active_voices()
61    );
62
63    // --- Host it in a mixer, and play a melody by reaching back in --------
64    let mut mixer = Mixer::new(sr);
65    let lead_id = mixer.add(inst);
66    mixer.set_gain(lead_id, 0.8);
67
68    let melody = ["C4", "E4", "G4", "C5", "G4", "E4"];
69    let mut apeak = 0.0f32;
70    for name in melody {
71        let voice = mixer.get_mut::<Instrument>(lead_id).unwrap();
72        voice.note_on(n(name), 0.85);
73        // ~120 ms of audio per note.
74        for _ in 0..11 {
75            mixer.fill(&mut block);
76            apeak = apeak.max(peak(&block));
77        }
78        mixer
79            .get_mut::<Instrument>(lead_id)
80            .unwrap()
81            .note_off(n(name));
82    }
83    println!("melody through the mixer: peak {apeak:.3}");
84}
Source

pub fn add(&mut self, source: impl AudioSource + Send + 'static) -> SourceId

Add a source to the master bus at unity gain; returns its handle.

Examples found in repository?
examples/play_instrument.rs (line 65)
31fn main() {
32    let sr = 48_000;
33    let design = InstrumentDesign::new(lead()).with_amp(Adsr {
34        a: 0.01,
35        d: 0.15,
36        s: 0.6,
37        r: 0.25,
38        punch: 0.0,
39    });
40    let mut inst = Instrument::new(design, sr).expect("streamable instrument");
41
42    // --- Play a C-major chord, hold, then release -------------------------
43    inst.note_on(n("C4"), 0.9);
44    inst.note_on(n("E4"), 0.8);
45    inst.note_on(n("G4"), 0.7);
46    println!("chord: {} voices", inst.active_voices());
47
48    let mut block = vec![0.0f32; 512 * 2];
49    let mut p = 0.0f32;
50    for _ in 0..40 {
51        inst.fill(&mut block);
52        p = p.max(peak(&block));
53    }
54    inst.all_notes_off();
55    for _ in 0..60 {
56        inst.fill(&mut block);
57    }
58    println!(
59        "after release: {} voices (chord peak {p:.3})",
60        inst.active_voices()
61    );
62
63    // --- Host it in a mixer, and play a melody by reaching back in --------
64    let mut mixer = Mixer::new(sr);
65    let lead_id = mixer.add(inst);
66    mixer.set_gain(lead_id, 0.8);
67
68    let melody = ["C4", "E4", "G4", "C5", "G4", "E4"];
69    let mut apeak = 0.0f32;
70    for name in melody {
71        let voice = mixer.get_mut::<Instrument>(lead_id).unwrap();
72        voice.note_on(n(name), 0.85);
73        // ~120 ms of audio per note.
74        for _ in 0..11 {
75            mixer.fill(&mut block);
76            apeak = apeak.max(peak(&block));
77        }
78        mixer
79            .get_mut::<Instrument>(lead_id)
80            .unwrap()
81            .note_off(n(name));
82    }
83    println!("melody through the mixer: peak {apeak:.3}");
84}
Source

pub fn add_to( &mut self, bus: BusId, source: impl AudioSource + Send + 'static, ) -> SourceId

Add a source to a specific bus at unity gain; returns its handle. An unknown bus falls back to master.

Source

pub fn bus(&mut self, name: impl Into<String>) -> BusId

Create an input bus (sources → inserts → master, with optional sends).

Source

pub fn fx_bus( &mut self, name: impl Into<String>, effects: Vec<Node>, ) -> Result<BusId, MixerError>

Create an FX/return bus with an insert chain fed only by sends. Returns MixerError if the effects aren’t streamable or the mixer has no rate.

Source

pub fn bus_named(&self, name: &str) -> Option<BusId>

Look up a bus by name.

Source

pub fn set_bus_effects( &mut self, bus: BusId, effects: Vec<Node>, ) -> Result<(), MixerError>

Set (or clear, with an empty list) a bus’s insert chain. Works on any bus, including master. Returns MixerError::UnknownBus for a foreign/stale handle (it used to build the chain and silently discard it).

Source

pub fn master_effects(&mut self, effects: Vec<Node>) -> Result<(), MixerError>

Set the master insert chain (a convenience for set_bus_effects(MASTER, …)).

Source

pub fn set_send(&mut self, from: BusId, to_fx: BusId, level: f32)

Set a post-fader send from an input bus into an FX bus. A no-op unless from is an input bus and to_fx is an FX bus.

Source

pub fn set_bus_gain(&mut self, bus: BusId, gain: f32)

Set a bus fader (0 = silent). Applies to the bus’s dry output and its sends.

Source

pub fn set_bus_dry(&mut self, bus: BusId, level: f32)

Set a bus’s dry level into master (0 = send-only). No-op for master.

Source

pub fn set_gain(&mut self, id: SourceId, gain: f32)

Set a source’s gain (no-op for an unknown handle).

Examples found in repository?
examples/play_instrument.rs (line 66)
31fn main() {
32    let sr = 48_000;
33    let design = InstrumentDesign::new(lead()).with_amp(Adsr {
34        a: 0.01,
35        d: 0.15,
36        s: 0.6,
37        r: 0.25,
38        punch: 0.0,
39    });
40    let mut inst = Instrument::new(design, sr).expect("streamable instrument");
41
42    // --- Play a C-major chord, hold, then release -------------------------
43    inst.note_on(n("C4"), 0.9);
44    inst.note_on(n("E4"), 0.8);
45    inst.note_on(n("G4"), 0.7);
46    println!("chord: {} voices", inst.active_voices());
47
48    let mut block = vec![0.0f32; 512 * 2];
49    let mut p = 0.0f32;
50    for _ in 0..40 {
51        inst.fill(&mut block);
52        p = p.max(peak(&block));
53    }
54    inst.all_notes_off();
55    for _ in 0..60 {
56        inst.fill(&mut block);
57    }
58    println!(
59        "after release: {} voices (chord peak {p:.3})",
60        inst.active_voices()
61    );
62
63    // --- Host it in a mixer, and play a melody by reaching back in --------
64    let mut mixer = Mixer::new(sr);
65    let lead_id = mixer.add(inst);
66    mixer.set_gain(lead_id, 0.8);
67
68    let melody = ["C4", "E4", "G4", "C5", "G4", "E4"];
69    let mut apeak = 0.0f32;
70    for name in melody {
71        let voice = mixer.get_mut::<Instrument>(lead_id).unwrap();
72        voice.note_on(n(name), 0.85);
73        // ~120 ms of audio per note.
74        for _ in 0..11 {
75            mixer.fill(&mut block);
76            apeak = apeak.max(peak(&block));
77        }
78        mixer
79            .get_mut::<Instrument>(lead_id)
80            .unwrap()
81            .note_off(n(name));
82    }
83    println!("melody through the mixer: peak {apeak:.3}");
84}
Source

pub fn get_mut<T: AudioSource + 'static>( &mut self, id: SourceId, ) -> Option<&mut T>

Mutable access to an added source, downcast to its concrete type — e.g. to call Instrument::note_on.

Examples found in repository?
examples/play_instrument.rs (line 71)
31fn main() {
32    let sr = 48_000;
33    let design = InstrumentDesign::new(lead()).with_amp(Adsr {
34        a: 0.01,
35        d: 0.15,
36        s: 0.6,
37        r: 0.25,
38        punch: 0.0,
39    });
40    let mut inst = Instrument::new(design, sr).expect("streamable instrument");
41
42    // --- Play a C-major chord, hold, then release -------------------------
43    inst.note_on(n("C4"), 0.9);
44    inst.note_on(n("E4"), 0.8);
45    inst.note_on(n("G4"), 0.7);
46    println!("chord: {} voices", inst.active_voices());
47
48    let mut block = vec![0.0f32; 512 * 2];
49    let mut p = 0.0f32;
50    for _ in 0..40 {
51        inst.fill(&mut block);
52        p = p.max(peak(&block));
53    }
54    inst.all_notes_off();
55    for _ in 0..60 {
56        inst.fill(&mut block);
57    }
58    println!(
59        "after release: {} voices (chord peak {p:.3})",
60        inst.active_voices()
61    );
62
63    // --- Host it in a mixer, and play a melody by reaching back in --------
64    let mut mixer = Mixer::new(sr);
65    let lead_id = mixer.add(inst);
66    mixer.set_gain(lead_id, 0.8);
67
68    let melody = ["C4", "E4", "G4", "C5", "G4", "E4"];
69    let mut apeak = 0.0f32;
70    for name in melody {
71        let voice = mixer.get_mut::<Instrument>(lead_id).unwrap();
72        voice.note_on(n(name), 0.85);
73        // ~120 ms of audio per note.
74        for _ in 0..11 {
75            mixer.fill(&mut block);
76            apeak = apeak.max(peak(&block));
77        }
78        mixer
79            .get_mut::<Instrument>(lead_id)
80            .unwrap()
81            .note_off(n(name));
82    }
83    println!("melody through the mixer: peak {apeak:.3}");
84}
Source

pub fn remove(&mut self, id: SourceId)

Remove a source.

Source

pub fn source_count(&self) -> usize

Number of sources in the mix.

Source

pub fn contains(&self, id: SourceId) -> bool

Whether id still refers to a source in the mix.

Trait Implementations§

Source§

impl AudioSource for Mixer

Source§

fn reset(&mut self)

Rewind every source so a transport restart replays the mix from the top. Bus insert/send state (reverb tails, delay lines) is left ringing.

Source§

fn fill(&mut self, out: &mut [f32]) -> usize

Fill out with the next block of interleaved-stereo audio.

Auto Trait Implementations§

§

impl !RefUnwindSafe for Mixer

§

impl !Sync for Mixer

§

impl !UnwindSafe for Mixer

§

impl Freeze for Mixer

§

impl Send for Mixer

§

impl Unpin for Mixer

§

impl UnsafeUnpin for Mixer

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more