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