firewheel_nodes/
beep_test.rs1#[cfg(not(feature = "std"))]
2use num_traits::Float;
3
4use firewheel_core::node::NodeError;
5use firewheel_core::{
6 channel_config::{ChannelConfig, ChannelCount},
7 diff::{Diff, Patch},
8 dsp::volume::{DEFAULT_MIN_AMP, Volume},
9 event::ProcEvents,
10 node::{
11 AudioNode, AudioNodeInfo, AudioNodeProcessor, ConstructProcessorContext, EmptyConfig,
12 ProcBuffers, ProcExtra, ProcInfo, ProcessStatus,
13 },
14};
15
16#[derive(Diff, Patch, Debug, Clone, Copy, PartialEq)]
21#[cfg_attr(feature = "bevy", derive(bevy_ecs::prelude::Component))]
22#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24pub struct BeepTestNode {
25 pub freq_hz: f32,
28
29 pub volume: Volume,
35}
36
37impl Default for BeepTestNode {
38 fn default() -> Self {
39 Self {
40 freq_hz: 440.0,
41 volume: Volume::Linear(0.5),
42 }
43 }
44}
45
46impl AudioNode for BeepTestNode {
47 type Configuration = EmptyConfig;
48
49 fn info(&self, _config: &Self::Configuration) -> Result<AudioNodeInfo, NodeError> {
50 Ok(AudioNodeInfo::new()
51 .debug_name("beep_test")
52 .channel_config(ChannelConfig {
53 num_inputs: ChannelCount::ZERO,
54 num_outputs: ChannelCount::MONO,
55 }))
56 }
57
58 fn construct_processor(
59 &self,
60 _config: &Self::Configuration,
61 cx: ConstructProcessorContext,
62 ) -> Result<impl AudioNodeProcessor, NodeError> {
63 Ok(Processor {
64 phasor: 0.0,
65 phasor_inc: self.freq_hz.clamp(20.0, 20_000.0)
66 * cx.stream_info.sample_rate_recip as f32,
67 gain: self.volume.amp_clamped(DEFAULT_MIN_AMP),
68 })
69 }
70}
71
72struct Processor {
73 phasor: f32,
74 phasor_inc: f32,
75 gain: f32,
76}
77
78impl AudioNodeProcessor for Processor {
79 fn events(&mut self, info: &ProcInfo, events: &mut ProcEvents, _extra: &mut ProcExtra) {
80 for patch in events.drain_patches::<BeepTestNode>() {
81 match patch {
82 BeepTestNodePatch::FreqHz(f) => {
83 self.phasor_inc = f.clamp(20.0, 20_000.0) * info.sample_rate_recip as f32;
84 }
85 BeepTestNodePatch::Volume(v) => {
86 self.gain = v.amp_clamped(DEFAULT_MIN_AMP);
87 }
88 }
89 }
90 }
91
92 fn process(
93 &mut self,
94 _info: &ProcInfo,
95 buffers: ProcBuffers,
96 _extra: &mut ProcExtra,
97 ) -> ProcessStatus {
98 for s in buffers.outputs[0].iter_mut() {
99 *s = (self.phasor * core::f32::consts::TAU).sin() * self.gain;
100 self.phasor = (self.phasor + self.phasor_inc).fract();
101 }
102
103 ProcessStatus::OutputsModified
104 }
105}