Skip to main content

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}