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