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}