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