firewheel_nodes/noise_generator/
white.rs1use firewheel_core::node::NodeError;
4use firewheel_core::param::smoother::DEFAULT_GAIN_SPAN;
5use firewheel_core::{
6 channel_config::{ChannelConfig, ChannelCount},
7 diff::{Diff, Patch},
8 dsp::{
9 filter::smoothing_filter::DEFAULT_SMOOTH_SECONDS,
10 volume::{DEFAULT_MIN_AMP, Volume},
11 },
12 event::ProcEvents,
13 node::{
14 AudioNode, AudioNodeInfo, AudioNodeProcessor, ConstructProcessorContext, ProcBuffers,
15 ProcExtra, ProcInfo, ProcessStatus,
16 },
17 param::smoother::{SmoothedParam, SmootherConfig},
18};
19
20#[derive(Diff, Patch, Debug, Clone, Copy, PartialEq)]
22#[cfg_attr(feature = "bevy", derive(bevy_ecs::prelude::Component))]
23#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct WhiteNoiseGenNode {
26 pub volume: Volume,
31 pub smooth_seconds: f32,
37}
38
39impl Default for WhiteNoiseGenNode {
40 fn default() -> Self {
41 Self {
42 volume: Volume::Linear(0.4),
43 smooth_seconds: DEFAULT_SMOOTH_SECONDS,
44 }
45 }
46}
47
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
50#[cfg_attr(feature = "bevy", derive(bevy_ecs::prelude::Component))]
51#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
52#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
53pub struct WhiteNoiseGenConfig {
54 pub seed: i32,
56}
57
58impl Default for WhiteNoiseGenConfig {
59 fn default() -> Self {
60 Self { seed: 17 }
61 }
62}
63
64impl AudioNode for WhiteNoiseGenNode {
65 type Configuration = WhiteNoiseGenConfig;
66
67 fn info(&self, _config: &Self::Configuration) -> Result<AudioNodeInfo, NodeError> {
68 Ok(AudioNodeInfo::new()
69 .debug_name("white_noise_gen")
70 .channel_config(ChannelConfig {
71 num_inputs: ChannelCount::ZERO,
72 num_outputs: ChannelCount::MONO,
73 }))
74 }
75
76 fn construct_processor(
77 &self,
78 config: &Self::Configuration,
79 cx: ConstructProcessorContext,
80 ) -> Result<impl AudioNodeProcessor, NodeError> {
81 let seed = if config.seed == 0 { 17 } else { config.seed };
83
84 Ok(Processor {
85 fpd: seed,
86 gain: SmoothedParam::new(
87 self.volume.amp_clamped(DEFAULT_MIN_AMP),
88 DEFAULT_GAIN_SPAN,
89 SmootherConfig {
90 smooth_seconds: self.smooth_seconds,
91 ..Default::default()
92 },
93 cx.stream_info.sample_rate,
94 ),
95 params: *self,
96 })
97 }
98}
99
100struct Processor {
102 fpd: i32,
103 params: WhiteNoiseGenNode,
104 gain: SmoothedParam,
105}
106
107impl AudioNodeProcessor for Processor {
108 fn events(&mut self, info: &ProcInfo, events: &mut ProcEvents, _extra: &mut ProcExtra) {
109 for patch in events.drain_patches::<WhiteNoiseGenNode>() {
110 match patch {
111 WhiteNoiseGenNodePatch::Volume(vol) => {
112 self.gain.set_value(vol.amp_clamped(DEFAULT_MIN_AMP));
113 }
114 WhiteNoiseGenNodePatch::SmoothSeconds(seconds) => {
115 self.gain.set_smooth_seconds(seconds, info.sample_rate);
116 }
117 }
118
119 self.params.apply(patch);
120 }
121 }
122
123 fn process(
124 &mut self,
125 _info: &ProcInfo,
126 buffers: ProcBuffers,
127 _extra: &mut ProcExtra,
128 ) -> ProcessStatus {
129 if self.gain.has_settled_at_or_below(DEFAULT_MIN_AMP) {
130 self.gain.reset_to_target();
131 return ProcessStatus::ClearAllOutputs;
132 }
133
134 for s in buffers.outputs[0].iter_mut() {
135 self.fpd ^= self.fpd << 13;
136 self.fpd ^= self.fpd >> 17;
137 self.fpd ^= self.fpd << 5;
138
139 let r = self.fpd as f32 * (1.0 / 2_147_483_648.0);
141
142 *s = r * self.gain.next_smoothed();
143 }
144
145 ProcessStatus::OutputsModified
146 }
147}