Skip to main content

phonon/dsp/
audio_buffer.rs

1//
2// Copyright 2017-2023 Valve Corporation.
3// Copyright 2024 phonon_rs contributors.
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9//     http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16//
17
18use derive_deref::{Deref, DerefMut};
19
20pub enum AudioEffectState {
21    TailRemaining,
22    TailComplete,
23}
24
25#[derive(Debug, Copy, Clone, PartialEq)]
26pub struct AudioSettings {
27    pub sampling_rate: i32,
28    pub frame_size: usize,
29}
30
31impl AudioSettings {
32    pub fn new(sampling_rate: i32, frame_size: usize) -> Self {
33        Self {
34            sampling_rate,
35            frame_size,
36        }
37    }
38}
39
40/// Phonon processes audio in audio buffers, which contain uncompressed Pulse
41/// Code Modulated (PCM) data (just like a .wav file).
42///
43/// Audio buffers contain one or more channels; for example, a stereo audio
44/// buffer contains 2 channels. Each channel typically contains several samples,
45/// which are values of the audio signal’s level at discrete points of time.
46/// Each channel has the same number of samples.
47///
48/// A sample is a 32-bit floating-point. The time interval between two
49/// successive samples is specified using the sampling rate. Typical sampling
50/// rates are 44100 Hz (CD quality) or 48000 Hz.
51///
52/// # Interleaving
53/// Phonon stores audio buffers in a deinterleaved layout. This means that all
54/// the samples for the first channel are store contiguously, followed by all
55/// the samples for the second channel, and so on.
56///
57/// Most audio formats instead use an interleaved layout, where data for each
58/// frame is stored together in memory. Interleaved data can be read to and
59/// written from using [`AudioBuffer::read_interleaved`] and [`AudioBuffer::write_interleaved`].
60#[derive(Deref, DerefMut)]
61pub struct AudioBuffer<const N_CHANNELS: usize>(pub [Vec<f32>; N_CHANNELS]);
62
63impl<const N_CHANNELS: usize> AudioBuffer<N_CHANNELS> {
64    /// Creates a new `AudioBuffer` with a fixed number of channels and samples.
65    ///
66    /// Initalized to all zeros, representing silence.
67    pub fn new(num_samples: usize) -> Self {
68        AudioBuffer(core::array::from_fn(|_| vec![0.0; num_samples]))
69    }
70
71    /// Returns the number of channels this `AudioBuffer` has.
72    pub fn num_channels(&self) -> usize {
73        self.len()
74    }
75
76    /// Returns the number of samples each channel has.
77    pub fn num_samples(&self) -> usize {
78        self[0].len()
79    }
80
81    /// Fills the `AudioBuffer` with all zero samples, representing silence.
82    pub fn make_silent(&mut self) {
83        for channel in &mut self.0 {
84            channel.fill(0.0);
85        }
86    }
87
88    /// Mixes the `AudioBuffer` into another by adding samples together.
89    // todo perf?
90    pub fn mix(&mut self, other: &AudioBuffer<N_CHANNELS>) {
91        for i in 0..other.len() {
92            for j in 0..other[0].len() {
93                self[i][j] += other[i][j];
94            }
95        }
96    }
97
98    /// Mixes all channels on an `AudioBuffer` into a single output channel.
99    /// Downmixing is performed by summing up the source channels and dividing
100    /// the result by the number of source channels.
101    // todo perf?
102    pub fn downmix(&self, output: &mut AudioBuffer<1>) {
103        let num_channels = self.len();
104        let factor = 1.0 / (num_channels as f32);
105
106        for i in 0..output[0].len() {
107            let mut sum = 0.0;
108
109            for j in 0..num_channels {
110                sum += self[j][i];
111            }
112
113            output[0][i] = sum * factor;
114        }
115    }
116
117    /// Reads a slice of interleaved samples into this `AudioBuffer`.
118    // todo: Check perf?
119    // todo: Can panic if the length of `other` is too small.
120    pub fn read_interleaved(&mut self, source: &[f32]) {
121        let mut index = 0;
122
123        for i in 0..self[0].len() {
124            for j in 0..N_CHANNELS {
125                self[j][i] = source[index];
126                index += 1;
127            }
128        }
129    }
130
131    /// Writes the `AudioBuffer` to an interleaved slice.
132    // todo: Check perf?
133    // todo: Can panic if the length of `other` is too small.
134    pub fn write_interleaved(&self, target: &mut [f32]) {
135        let mut index = 0;
136
137        for i in 0..self[0].len() {
138            for j in 0..N_CHANNELS {
139                target[index] = self[j][i];
140                index += 1;
141            }
142        }
143    }
144
145    /// Scales all the samples in the `AudioBuffer` by the given volume.
146    // todo: Check perf?
147    pub fn scale(&mut self, volume: f32) {
148        for i in 0..self.len() {
149            for j in 0..self[0].len() {
150                self[i][j] *= volume;
151            }
152        }
153    }
154}