web_audio_api/node/
channel_splitter.rs1use std::fmt::Debug;
2
3use crate::context::{AudioContextRegistration, BaseAudioContext};
4use crate::render::{
5 AudioParamValues, AudioProcessor, AudioRenderQuantum, AudioWorkletGlobalScope,
6};
7use crate::MAX_CHANNELS;
8
9use super::{AudioNode, AudioNodeOptions, ChannelConfig, ChannelCountMode, ChannelInterpretation};
10
11const DEFAULT_NUMBER_OF_OUTPUTS: usize = 6;
12
13#[track_caller]
22#[inline(always)]
23pub(crate) fn assert_valid_number_of_channels(number_of_channels: usize) {
24 assert!(
25 number_of_channels > 0 && number_of_channels <= MAX_CHANNELS,
26 "IndexSizeError - Invalid number of channels: {:?} is outside range [1, {:?}]",
27 number_of_channels,
28 MAX_CHANNELS
29 );
30}
31
32#[track_caller]
40#[inline(always)]
41fn assert_valid_channel_count(count: usize, number_of_outputs: usize) {
42 assert!(
43 count == number_of_outputs,
44 "InvalidStateError - channel count of ChannelSplitterNode must be equal to number of outputs"
45 );
46}
47
48#[track_caller]
56#[inline(always)]
57fn assert_valid_channel_count_mode(mode: ChannelCountMode) {
58 assert!(
59 mode == ChannelCountMode::Explicit,
60 "InvalidStateError - channel count of ChannelSplitterNode must be set to Explicit"
61 );
62}
63
64#[track_caller]
72#[inline(always)]
73fn assert_valid_channel_interpretation(interpretation: ChannelInterpretation) {
74 assert!(
75 interpretation == ChannelInterpretation::Discrete,
76 "InvalidStateError - channel interpretation of ChannelSplitterNode must be set to Discrete"
77 );
78}
79
80#[derive(Clone, Debug)]
85pub struct ChannelSplitterOptions {
86 pub number_of_outputs: usize,
87 pub audio_node_options: AudioNodeOptions,
88}
89
90impl Default for ChannelSplitterOptions {
91 fn default() -> Self {
92 Self {
93 number_of_outputs: DEFAULT_NUMBER_OF_OUTPUTS,
94 audio_node_options: AudioNodeOptions {
95 channel_count: DEFAULT_NUMBER_OF_OUTPUTS, channel_count_mode: ChannelCountMode::Explicit,
97 channel_interpretation: ChannelInterpretation::Discrete,
98 },
99 }
100 }
101}
102
103#[derive(Debug)]
105pub struct ChannelSplitterNode {
106 registration: AudioContextRegistration,
107 channel_config: ChannelConfig,
108 number_of_outputs: usize,
109}
110
111impl AudioNode for ChannelSplitterNode {
112 fn registration(&self) -> &AudioContextRegistration {
113 &self.registration
114 }
115
116 fn channel_config(&self) -> &ChannelConfig {
117 &self.channel_config
118 }
119
120 fn set_channel_count(&self, count: usize) {
121 assert_valid_channel_count(count, self.number_of_outputs);
122 }
123
124 fn set_channel_count_mode(&self, mode: ChannelCountMode) {
125 assert_valid_channel_count_mode(mode);
126 self.channel_config
127 .set_count_mode(mode, self.registration());
128 }
129
130 fn set_channel_interpretation(&self, interpretation: ChannelInterpretation) {
131 assert_valid_channel_interpretation(interpretation);
132 self.channel_config
133 .set_interpretation(interpretation, self.registration());
134 }
135
136 fn number_of_inputs(&self) -> usize {
137 1
138 }
139
140 fn number_of_outputs(&self) -> usize {
141 self.number_of_outputs
142 }
143}
144
145impl ChannelSplitterNode {
146 pub fn new<C: BaseAudioContext>(context: &C, mut options: ChannelSplitterOptions) -> Self {
147 context.base().register(move |registration| {
148 assert_valid_number_of_channels(options.number_of_outputs);
149
150 if options.audio_node_options.channel_count != DEFAULT_NUMBER_OF_OUTPUTS {
153 assert_valid_channel_count(
154 options.audio_node_options.channel_count,
155 options.number_of_outputs,
156 );
157 }
158 options.audio_node_options.channel_count = options.number_of_outputs;
159
160 assert_valid_channel_count_mode(options.audio_node_options.channel_count_mode);
161 assert_valid_channel_interpretation(options.audio_node_options.channel_interpretation);
162
163 let node = ChannelSplitterNode {
164 registration,
165 channel_config: options.audio_node_options.into(),
166 number_of_outputs: options.number_of_outputs,
167 };
168
169 let render = ChannelSplitterRenderer {
170 number_of_outputs: options.number_of_outputs,
171 };
172
173 (node, Box::new(render))
174 })
175 }
176}
177
178#[derive(Debug)]
179struct ChannelSplitterRenderer {
180 pub number_of_outputs: usize,
181}
182
183impl AudioProcessor for ChannelSplitterRenderer {
184 fn process(
185 &mut self,
186 inputs: &[AudioRenderQuantum],
187 outputs: &mut [AudioRenderQuantum],
188 _params: AudioParamValues<'_>,
189 _scope: &AudioWorkletGlobalScope,
190 ) -> bool {
191 let input = &inputs[0];
193
194 assert_eq!(self.number_of_outputs, outputs.len());
196
197 for (i, output) in outputs.iter_mut().enumerate() {
198 output.set_number_of_channels(1);
199
200 if i < input.number_of_channels() {
201 *output.channel_data_mut(0) = input.channel_data(i).clone();
202 } else {
203 output.make_silent();
205 }
206 }
207
208 false
209 }
210}
211
212#[cfg(test)]
213mod tests {
214 use float_eq::assert_float_eq;
215
216 use crate::context::{BaseAudioContext, OfflineAudioContext};
217 use crate::node::{AudioNode, AudioScheduledSourceNode};
218 use crate::AudioBuffer;
219
220 use super::*;
221
222 #[test]
223 fn test_valid_constructor_options() {
224 let sample_rate = 48000.;
225 let context = OfflineAudioContext::new(1, 128, sample_rate);
226
227 let options = ChannelSplitterOptions {
228 number_of_outputs: 2,
229 ..Default::default()
230 };
231
232 let splitter = ChannelSplitterNode::new(&context, options);
233 assert_eq!(splitter.number_of_outputs(), 2);
234 assert_eq!(splitter.channel_count(), 2);
235 }
236
237 #[test]
238 #[should_panic]
239 fn test_invalid_constructor_options() {
240 let sample_rate = 48000.;
241 let context = OfflineAudioContext::new(1, 128, sample_rate);
242
243 let mut options = ChannelSplitterOptions::default();
244 options.audio_node_options.channel_count = 7;
245
246 let _splitter = ChannelSplitterNode::new(&context, options);
247 }
248
249 #[test]
250 #[should_panic]
251 fn test_set_channel_count() {
252 let sample_rate = 48000.;
253 let context = OfflineAudioContext::new(1, 128, sample_rate);
254
255 let options = ChannelSplitterOptions::default();
256 let splitter = ChannelSplitterNode::new(&context, options);
257 splitter.set_channel_count(3);
258 }
259
260 #[test]
261 fn test_splitter() {
262 let sample_rate = 48000.;
263 let mut context = OfflineAudioContext::new(1, 128, sample_rate);
264
265 let splitter = context.create_channel_splitter(2);
266
267 splitter.connect_from_output_to_input(&context.destination(), 1, 0);
269
270 let audio_buffer = AudioBuffer::from(vec![vec![1.], vec![-1.]], 48000.);
272 let mut src = context.create_buffer_source();
273 src.set_buffer(audio_buffer);
274 src.set_loop(true);
275 src.start();
276 src.connect(&splitter);
277
278 let buffer = context.start_rendering_sync();
279
280 let mono = buffer.get_channel_data(0);
281 assert_float_eq!(mono, &[-1.; 128][..], abs_all <= 0.);
282 }
283}