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
impl Mixer
Sourcepub fn new(sample_rate: u32) -> Self
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?
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}Sourcepub fn add(&mut self, source: impl AudioSource + Send + 'static) -> SourceId
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?
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}Sourcepub fn add_to(
&mut self,
bus: BusId,
source: impl AudioSource + Send + 'static,
) -> SourceId
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.
Sourcepub fn bus(&mut self, name: impl Into<String>) -> BusId
pub fn bus(&mut self, name: impl Into<String>) -> BusId
Create an input bus (sources → inserts → master, with optional sends).
Sourcepub fn fx_bus(
&mut self,
name: impl Into<String>,
effects: Vec<Node>,
) -> Result<BusId, MixerError>
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.
Sourcepub fn set_bus_effects(
&mut self,
bus: BusId,
effects: Vec<Node>,
) -> Result<(), MixerError>
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).
Sourcepub fn master_effects(&mut self, effects: Vec<Node>) -> Result<(), MixerError>
pub fn master_effects(&mut self, effects: Vec<Node>) -> Result<(), MixerError>
Set the master insert chain (a convenience for set_bus_effects(MASTER, …)).
Sourcepub fn set_send(&mut self, from: BusId, to_fx: BusId, level: f32)
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.
Sourcepub fn set_bus_gain(&mut self, bus: BusId, gain: f32)
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.
Sourcepub fn set_bus_dry(&mut self, bus: BusId, level: f32)
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.
Sourcepub fn set_gain(&mut self, id: SourceId, gain: f32)
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?
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}Sourcepub fn get_mut<T: AudioSource + 'static>(
&mut self,
id: SourceId,
) -> Option<&mut T>
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?
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}Sourcepub fn source_count(&self) -> usize
pub fn source_count(&self) -> usize
Number of sources in the mix.