firewheel_nodes/
stereo_to_mono.rs

1use firewheel_core::{
2    channel_config::{ChannelConfig, ChannelCount},
3    event::NodeEventList,
4    node::{
5        AudioNode, AudioNodeInfo, AudioNodeProcessor, ConstructProcessorContext, EmptyConfig,
6        ProcBuffers, ProcInfo, ProcessStatus,
7    },
8};
9
10#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
11#[cfg_attr(feature = "bevy", derive(bevy_ecs::prelude::Component))]
12pub struct StereoToMonoNode;
13
14impl AudioNode for StereoToMonoNode {
15    type Configuration = EmptyConfig;
16
17    fn info(&self, _config: &Self::Configuration) -> AudioNodeInfo {
18        AudioNodeInfo::new()
19            .debug_name("stereo_to_mono")
20            .channel_config(ChannelConfig {
21                num_inputs: ChannelCount::STEREO,
22                num_outputs: ChannelCount::MONO,
23            })
24            .uses_events(false)
25    }
26
27    fn construct_processor(
28        &self,
29        _config: &Self::Configuration,
30        _cx: ConstructProcessorContext,
31    ) -> impl AudioNodeProcessor {
32        StereoToMonoProcessor
33    }
34}
35
36struct StereoToMonoProcessor;
37
38impl AudioNodeProcessor for StereoToMonoProcessor {
39    fn process(
40        &mut self,
41        buffers: ProcBuffers,
42        proc_info: &ProcInfo,
43        _events: NodeEventList,
44    ) -> ProcessStatus {
45        if proc_info.in_silence_mask.all_channels_silent(2)
46            || buffers.inputs.len() < 2
47            || buffers.outputs.is_empty()
48        {
49            return ProcessStatus::ClearAllOutputs;
50        }
51
52        for (out_s, (&in1, &in2)) in buffers.outputs[0]
53            .iter_mut()
54            .zip(buffers.inputs[0].iter().zip(buffers.inputs[1].iter()))
55        {
56            *out_s = (in1 + in2) * 0.5;
57        }
58
59        ProcessStatus::outputs_not_silent()
60    }
61}