fyrox_sound/bus.rs
1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Everything related to audio buses and audio bus graphs. See docs of [`AudioBus`] and [`AudioBusGraph`]
22//! for more info and examples
23
24use crate::effects::{Effect, EffectRenderTrait};
25use fyrox_core::{
26 pool::{Handle, Pool, Ticket},
27 reflect::prelude::*,
28 visitor::prelude::*,
29};
30use std::fmt::{Debug, Formatter};
31
32#[derive(Default, Clone)]
33struct PingPongBuffer {
34 buffer1: Vec<(f32, f32)>,
35 buffer2: Vec<(f32, f32)>,
36 first_is_input: bool,
37}
38
39impl Debug for PingPongBuffer {
40 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("PingPongBuffer")
42 .field("Buffer1", &format_args!("{:?} bytes", self.buffer1.len()))
43 .field("Buffer2", &format_args!("{:?} bytes", self.buffer2.len()))
44 .field("FirstIsInput", &self.first_is_input)
45 .finish()
46 }
47}
48
49impl PingPongBuffer {
50 fn resize(&mut self, size: usize) {
51 self.buffer1 = Vec::with_capacity(size);
52 self.buffer2 = Vec::with_capacity(size);
53 self.clear();
54 }
55
56 fn clear(&mut self) {
57 self.buffer1.clear();
58 self.buffer2.clear();
59 for _ in 0..self.buffer1.capacity() {
60 self.buffer1.push((0.0, 0.0));
61 self.buffer2.push((0.0, 0.0));
62 }
63 }
64
65 fn capacity(&self) -> usize {
66 self.buffer1.capacity()
67 }
68
69 fn swap(&mut self) {
70 self.first_is_input = !self.first_is_input;
71 }
72
73 #[allow(clippy::type_complexity)]
74 fn input_output_buffers(&mut self) -> (&[(f32, f32)], &mut [(f32, f32)]) {
75 if self.first_is_input {
76 (&self.buffer1, &mut self.buffer2)
77 } else {
78 (&self.buffer2, &mut self.buffer1)
79 }
80 }
81
82 fn input_ref(&self) -> &[(f32, f32)] {
83 if self.first_is_input {
84 &self.buffer1
85 } else {
86 &self.buffer2
87 }
88 }
89
90 fn input_mut(&mut self) -> &mut [(f32, f32)] {
91 if self.first_is_input {
92 &mut self.buffer1
93 } else {
94 &mut self.buffer2
95 }
96 }
97}
98
99/// Audio bus is a top-level audio processing unit. It takes data from multiple audio sources and passes their
100/// samples through a chain of effects. Output signal is then can be either sent to an audio playback device or
101/// to some other audio bus and be processed again, but with different sound effects (this can be done via
102/// [`AudioBusGraph`].
103#[derive(Debug, Reflect, Visit, Clone)]
104pub struct AudioBus {
105 pub(crate) name: String,
106 effects: Vec<Effect>,
107 gain: f32,
108
109 #[reflect(hidden)]
110 child_buses: Vec<Handle<AudioBus>>,
111
112 #[reflect(hidden)]
113 parent_bus: Handle<AudioBus>,
114
115 #[reflect(hidden)]
116 #[visit(skip)]
117 ping_pong_buffer: PingPongBuffer,
118}
119
120impl Default for AudioBus {
121 fn default() -> Self {
122 Self {
123 name: "Bus".to_string(),
124 child_buses: Default::default(),
125 effects: Default::default(),
126 gain: 1.0,
127 ping_pong_buffer: Default::default(),
128 parent_bus: Default::default(),
129 }
130 }
131}
132
133impl AudioBus {
134 /// Creates a new audio bus with the given name with no audio effects and unit gain. Produced audio bus must
135 /// be added to an [`AudioBusGraph`] to take effect.
136 pub fn new(name: String) -> Self {
137 Self {
138 name,
139 ..Default::default()
140 }
141 }
142
143 /// Sets a new name of the audio bus. Be careful when changing the name at runtime, each sound source is linked
144 /// to a bus by its name (implicit binding), so when changing the name you should also change the output bus name
145 /// of a sound source, that uses the bus.
146 pub fn set_name<S: AsRef<str>>(&mut self, name: S) {
147 name.as_ref().clone_into(&mut self.name);
148 }
149
150 /// Returns current name of the audio bus. Could be useful if you need to find all sound sources that uses the bus.
151 pub fn name(&self) -> &str {
152 &self.name
153 }
154
155 /// Returns a handle of the parent audio bus. Primary audio bus has no parent and will return ([`Handle::NONE`]).
156 pub fn parent(&self) -> Handle<AudioBus> {
157 self.parent_bus
158 }
159
160 /// Returns a list of handle to children audio buses.
161 pub fn children(&self) -> &[Handle<AudioBus>] {
162 &self.child_buses
163 }
164
165 /// Sets new gain of the audio bus.
166 pub fn set_gain(&mut self, gain: f32) {
167 self.gain = gain;
168 }
169
170 /// Returns current gain of the audio bus.
171 pub fn gain(&self) -> f32 {
172 self.gain
173 }
174
175 pub(crate) fn input_buffer(&mut self) -> &mut [(f32, f32)] {
176 self.ping_pong_buffer.input_mut()
177 }
178
179 pub(crate) fn begin_render(&mut self, buffer_size: usize) {
180 if self.ping_pong_buffer.capacity() < buffer_size {
181 self.ping_pong_buffer.resize(buffer_size);
182 } else {
183 self.ping_pong_buffer.clear();
184 }
185 }
186
187 fn apply_effects(&mut self) {
188 // Pass through the chain of effects.
189 for effect in self.effects.iter_mut() {
190 let (input, output) = self.ping_pong_buffer.input_output_buffers();
191 effect.render(input, output);
192 self.ping_pong_buffer.swap();
193 }
194 }
195
196 /// Adds new effect to the effects chain.
197 pub fn add_effect(&mut self, effect: Effect) {
198 self.effects.push(effect)
199 }
200
201 /// Removes an effect by the given handle.
202 pub fn remove_effect(&mut self, index: usize) {
203 self.effects.remove(index);
204 }
205
206 /// Returns a shared reference to an effect at the given handle.
207 pub fn effect(&self, index: usize) -> Option<&Effect> {
208 self.effects.get(index)
209 }
210
211 /// Returns mutable reference to effect at given handle.
212 pub fn effect_mut(&mut self, index: usize) -> Option<&mut Effect> {
213 self.effects.get_mut(index)
214 }
215
216 /// Returns an iterator over effects used by this audio bus.
217 pub fn effects(&self) -> impl Iterator<Item = &Effect> {
218 self.effects.iter()
219 }
220
221 /// Returns an iterator over effects used by this audio bus.
222 pub fn effects_mut(&mut self) -> impl Iterator<Item = &mut Effect> {
223 self.effects.iter_mut()
224 }
225}
226
227/// Audio bus graph is a complex audio data processing entity; it allows you to route samples from
228/// audio sources through a chain of audio buses or directly to an audio playback device. To get a
229/// better understanding of how the audio graph works take a look the data flow diagram below:
230///
231/// ```text
232///
233/// ┌────────────┐ ┌────────────┐
234/// │ │ │ │
235/// │ Source1 ├────────────┐ ┌──────────┤ Source2 │
236/// │ │ │ │ │ │
237/// └────────────┘ │ │ └────────────┘
238/// ▼ ▼
239/// ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌────────────┐
240/// │ │ │ │ │ │ │ │
241/// │ Source3 ├─────►│ Bus1 │ │ BusN │◄───┤ Source4 │
242/// │ │ ├────────────┤ ├────────────┤ │ │
243/// └────────────┘ │ │ │ │ └────────────┘
244/// │ Effect1 │ │ ┌───────────┐ │ Effect1 │ │
245/// │ │ │ │ │ │ │ │
246/// │ Effect2 │ │ │ SourceN │ │ Effect2 │ │
247/// │ │ │ │ │ │ │ │
248/// │ EffectN ▼ │ └─────┬─────┘ │ EffectN ▼ │
249/// │ │ │ │ │
250/// └─────┬──────┘ │ └─────┬──────┘
251/// │ │ │
252/// │ ▼ │
253/// │ ┌────────────┐ │
254/// │ │ │ │
255/// └─────────►│ Primary │◄──────┘
256/// ├────────────┤
257/// │ │
258/// │ Effect1 │ │
259/// │ │ │
260/// │ Effect2 │ │
261/// │ │ │
262/// │ EffectN ▼ │
263/// │ │
264/// └─────┬──────┘
265/// │
266/// │
267/// ▼
268/// ┌───────────────────────────┐
269/// │ │
270/// │ Output Device │
271/// │ │
272/// └───────────────────────────┘
273///
274/// ```
275///
276/// Each audio bus is backed with data (samples) by a set of sound sources (`Source1`, `Source2`, ..) of
277/// current audio context. This data is then passed through a set of effects, which could include various
278/// filters (lowpass, highpass, bandpass, shelf filters, etc.) and complex effects such as reverberation.
279///
280/// By default, each audio bus graph has a single audio bus called Primary. It is mandatory to at least one
281/// audio bus. Primary bus is responsible for outputting the data to an audio playback device.
282///
283/// # Sound source binding
284///
285/// Each sound source binds to an audio bus using its name; this is so called implicit binding. While it may
286/// look weird, it is actually very useful. Explicit binding requires you to know the exact handle of an
287/// audio bus to which a sound is "attached". This makes it less convenient to re-route data from one bus to
288/// another. Implicit binding is as much more effective: all you need to do is to set a new name of a bus
289/// to which output the samples from a sound source and the engine will do the rest for you. A simple example
290/// of a such binding is something like this:
291///
292/// ```rust
293/// # use fyrox_sound::bus::AudioBus;
294/// # use fyrox_sound::context::SoundContext;
295/// # use fyrox_sound::source::SoundSourceBuilder;
296/// let context = SoundContext::new();
297/// let mut state = context.state();
298///
299/// let sfx_bus = AudioBus::new("SFX".to_string());
300/// let bus_graph = state.bus_graph_mut();
301/// let primary_bus = bus_graph.primary_bus_handle();
302/// bus_graph.add_bus(sfx_bus, primary_bus);
303///
304/// // Create a source and implicitly bind to the SFX audio bus. By default each source
305/// // is bound to the primary audio bus.
306/// state.add_source(SoundSourceBuilder::new().with_bus("SFX").build().unwrap());
307/// ```
308///
309/// If you delete an audio bus to which a bunch of sound sources is bound, then they will simply stop playing.
310#[derive(Default, Debug, Clone, Visit, Reflect)]
311pub struct AudioBusGraph {
312 buses: Pool<AudioBus>,
313 root: Handle<AudioBus>,
314}
315
316impl AudioBusGraph {
317 /// The name of the audio bus that output samples directly to an audio playback device.
318 pub const PRIMARY_BUS: &'static str = "Primary";
319
320 /// Creates a new audio bus graph. Sound context already has an audio graph instance, so calling
321 /// this method is needed only for very specific cases (mostly tests).
322 pub fn new() -> Self {
323 let root = AudioBus::new(Self::PRIMARY_BUS.to_string());
324 let mut buses = Pool::new();
325 let root = buses.spawn(root);
326 Self { buses, root }
327 }
328
329 /// Adds a new audio bus to the graph and attaches it to the given parent. `parent` handle must be
330 /// valid, otherwise the method will panic. In most cases you can use primary bus as a parent.
331 ///
332 /// # Examples
333 ///
334 /// ```rust
335 /// use fyrox_sound::bus::{AudioBus, AudioBusGraph};
336 ///
337 /// // By default it has one primary audio bus.
338 /// let mut graph = AudioBusGraph::new();
339 ///
340 /// // Add another bus to the graph and attach it to the primary bus.
341 /// let primary_bus_handle = graph.primary_bus_handle();
342 /// graph.add_bus(AudioBus::new("SFX".to_owned()), primary_bus_handle);
343 ///
344 /// ```
345 pub fn add_bus(&mut self, mut bus: AudioBus, parent: Handle<AudioBus>) -> Handle<AudioBus> {
346 bus.parent_bus = parent;
347 let bus = self.buses.spawn(bus);
348 self.buses[parent].child_buses.push(bus);
349 bus
350 }
351
352 fn unlink_internal(&mut self, node_handle: Handle<AudioBus>) {
353 // Replace parent handle of child
354 let parent_handle =
355 std::mem::replace(&mut self.buses[node_handle].parent_bus, Handle::NONE);
356
357 // Remove child from parent's children list
358 if let Some(parent) = self.buses.try_borrow_mut(parent_handle) {
359 if let Some(i) = parent.children().iter().position(|h| *h == node_handle) {
360 parent.child_buses.remove(i);
361 }
362 }
363 }
364
365 /// Attaches the `child` audio bus to the `parent` audio bus. **Important:** this method does not
366 /// checks for any loops, adding any loops to the graph will cause infinite loop in the mixer thread.
367 #[inline]
368 pub fn link_buses(&mut self, child: Handle<AudioBus>, parent: Handle<AudioBus>) {
369 self.unlink_internal(child);
370 self.buses[child].parent_bus = parent;
371 self.buses[parent].child_buses.push(child);
372 }
373
374 pub(crate) fn try_get_bus_input_buffer(&mut self, name: &str) -> Option<&mut [(f32, f32)]> {
375 self.buses.iter_mut().find_map(|bus| {
376 if bus.name == name {
377 Some(bus.input_buffer())
378 } else {
379 None
380 }
381 })
382 }
383
384 /// Removes an audio bus at the given handle.
385 pub fn remove_bus(&mut self, handle: Handle<AudioBus>) -> AudioBus {
386 assert_ne!(handle, self.root);
387
388 let bus = self.buses.free(handle);
389 let parent_bus = &mut self.buses[bus.parent_bus];
390
391 let position = parent_bus
392 .child_buses
393 .iter()
394 .position(|h| *h == handle)
395 .expect("Malformed bus graph!");
396 parent_bus.child_buses.remove(position);
397
398 bus
399 }
400
401 /// Returns a handle of the primary audio bus. Primary bus outputs its samples directly to an audio playback
402 /// device.
403 pub fn primary_bus_handle(&self) -> Handle<AudioBus> {
404 self.root
405 }
406
407 /// Returns a reference to the primary audio bus.
408 pub fn primary_bus_ref(&self) -> &AudioBus {
409 &self.buses[self.root]
410 }
411
412 /// Returns a reference to the primary audio bus.
413 pub fn primary_bus_mut(&mut self) -> &mut AudioBus {
414 &mut self.buses[self.root]
415 }
416
417 /// Tries to borrow an audio bus by its handle.
418 pub fn try_get_bus_ref(&self, handle: Handle<AudioBus>) -> Option<&AudioBus> {
419 self.buses.try_borrow(handle)
420 }
421
422 /// Tries to borrow an audio bus by its handle.
423 pub fn try_get_bus_mut(&mut self, handle: Handle<AudioBus>) -> Option<&mut AudioBus> {
424 self.buses.try_borrow_mut(handle)
425 }
426
427 /// Returns total amount of audio buses in the graph.
428 pub fn len(&self) -> usize {
429 self.buses.alive_count() as usize
430 }
431
432 /// Checks if the graph is empty.
433 pub fn is_empty(&self) -> bool {
434 self.len() == 0
435 }
436
437 /// Tries to move out an audio bus with a promise that it will be returned back. See [`Pool::try_take_reserve`] method
438 /// docs for more info.
439 pub fn try_take_reserve_bus(
440 &mut self,
441 handle: Handle<AudioBus>,
442 ) -> Option<(Ticket<AudioBus>, AudioBus)> {
443 self.buses.try_take_reserve(handle)
444 }
445
446 /// Puts the audio bus back to graph on its previous place by the given ticket. See [`Pool::put_back`] method docs
447 /// for more info.
448 pub fn put_bus_back(&mut self, ticket: Ticket<AudioBus>, bus: AudioBus) -> Handle<AudioBus> {
449 self.buses.put_back(ticket, bus)
450 }
451
452 /// Forget an audio bus ticket making the respective handle free again. See [`Pool::forget_ticket`] method docs for
453 /// more info.
454 pub fn forget_bus_ticket(&mut self, ticket: Ticket<AudioBus>) {
455 self.buses.forget_ticket(ticket)
456 }
457
458 /// Returns an iterator over each audio bus in the graph.
459 pub fn buses_iter(&self) -> impl Iterator<Item = &AudioBus> {
460 self.buses.iter()
461 }
462
463 /// Returns an iterator over each audio bus in the graph.
464 pub fn buses_iter_mut(&mut self) -> impl Iterator<Item = &mut AudioBus> {
465 self.buses.iter_mut()
466 }
467
468 /// Returns an iterator yielding a pair of handle and a reference to each audio bus in the graph.
469 pub fn buses_pair_iter(&self) -> impl Iterator<Item = (Handle<AudioBus>, &AudioBus)> {
470 self.buses.pair_iter()
471 }
472
473 /// Returns an iterator yielding a pair of handle and a reference to each audio bus in the graph.
474 pub fn buses_pair_iter_mut(
475 &mut self,
476 ) -> impl Iterator<Item = (Handle<AudioBus>, &mut AudioBus)> {
477 self.buses.pair_iter_mut()
478 }
479
480 pub(crate) fn begin_render(&mut self, output_device_buffer_size: usize) {
481 for bus in self.buses.iter_mut() {
482 bus.begin_render(output_device_buffer_size);
483 }
484 }
485
486 pub(crate) fn end_render(&mut self, output_device_buffer: &mut [(f32, f32)]) {
487 let mut leafs = Vec::new();
488 for (handle, bus) in self.buses.pair_iter_mut() {
489 bus.apply_effects();
490
491 if bus.child_buses.is_empty() {
492 leafs.push(handle);
493 }
494 }
495
496 for mut leaf in leafs {
497 while leaf.is_some() {
498 let ctx = self.buses.begin_multi_borrow();
499
500 let leaf_ref = ctx.try_get_mut(leaf).expect("Malformed bus graph!");
501
502 let input_buffer = leaf_ref.ping_pong_buffer.input_ref();
503 let leaf_gain = leaf_ref.gain;
504 let mut parent_buffer = ctx.try_get_mut(leaf_ref.parent_bus);
505 let output_buffer = parent_buffer
506 .as_mut()
507 .map(|parent| parent.ping_pong_buffer.input_mut())
508 // Special case for the root bus - it writes directly to the output device buffer.
509 .unwrap_or(&mut *output_device_buffer);
510 for ((input_left, input_right), (output_left, output_right)) in
511 input_buffer.iter().zip(output_buffer)
512 {
513 *output_left += *input_left * leaf_gain;
514 *output_right += *input_right * leaf_gain;
515 }
516
517 leaf = leaf_ref.parent_bus;
518 }
519 }
520 }
521}
522
523#[cfg(test)]
524mod test {
525 use crate::{
526 bus::{AudioBus, AudioBusGraph},
527 effects::{Attenuate, Effect},
528 };
529
530 #[test]
531 fn test_multi_bus_data_flow() {
532 let mut output_buffer = [(0.0f32, 0.0f32)];
533
534 let mut graph = AudioBusGraph::new();
535
536 let bus1 = graph.add_bus(AudioBus::new("Bus1".to_string()), graph.root);
537 let bus2 = graph.add_bus(AudioBus::new("Bus2".to_string()), bus1);
538
539 graph.begin_render(output_buffer.len());
540
541 // Simulate output of sound sources to each bus.
542 for (left, right) in graph.buses[bus1].input_buffer() {
543 *left = 1.0;
544 *right = 1.0;
545 }
546
547 for (left, right) in graph.buses[bus2].input_buffer() {
548 *left = 1.0;
549 *right = 1.0;
550 }
551
552 graph.end_render(&mut output_buffer);
553
554 assert_eq!(output_buffer[0], (2.0, 2.0));
555 }
556
557 #[test]
558 fn test_primary_bus_data_flow() {
559 let mut output_buffer = [(0.0f32, 0.0f32)];
560
561 let mut graph = AudioBusGraph::new();
562
563 graph.begin_render(output_buffer.len());
564
565 // Simulate output of sound sources to each bus.
566 for (left, right) in graph.buses[graph.root].input_buffer() {
567 *left = 1.0;
568 *right = 1.0;
569 }
570
571 graph.end_render(&mut output_buffer);
572
573 assert_eq!(output_buffer[0], (1.0, 1.0));
574 }
575
576 #[test]
577 fn test_multi_bus_data_flow_with_effects() {
578 let mut output_buffer = [(0.0f32, 0.0f32)];
579
580 let mut graph = AudioBusGraph::new();
581
582 let mut bus1 = AudioBus::new("Bus1".to_string());
583 bus1.add_effect(Effect::Attenuate(Attenuate::new(0.5)));
584 bus1.add_effect(Effect::Attenuate(Attenuate::new(0.5)));
585
586 let bus1 = graph.add_bus(bus1, graph.root);
587
588 let mut bus2 = AudioBus::new("Bus2".to_string());
589 bus2.add_effect(Effect::Attenuate(Attenuate::new(0.5)));
590 let bus2 = graph.add_bus(bus2, bus1);
591
592 graph.begin_render(output_buffer.len());
593
594 // Simulate output of sound sources to each bus.
595 for (left, right) in graph.buses[bus1].input_buffer() {
596 *left = 1.0;
597 *right = 1.0;
598 }
599
600 for (left, right) in graph.buses[bus2].input_buffer() {
601 *left = 1.0;
602 *right = 1.0;
603 }
604
605 graph.end_render(&mut output_buffer);
606
607 assert_eq!(output_buffer[0], (0.75, 0.75));
608 }
609}