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}