use firewheel_core::{
channel_config::{ChannelConfig, ChannelCount},
diff::{Diff, Patch},
dsp::volume::{Volume, DEFAULT_AMP_EPSILON},
event::NodeEventList,
log::RealtimeLogger,
node::{
AudioNode, AudioNodeInfo, AudioNodeProcessor, ConstructProcessorContext, EmptyConfig,
ProcBuffers, ProcInfo, ProcessStatus,
},
};
#[derive(Diff, Patch, Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "bevy", derive(bevy_ecs::prelude::Component))]
#[cfg_attr(feature = "bevy_reflect", derive(bevy_reflect::Reflect))]
pub struct BeepTestNode {
pub freq_hz: f32,
pub volume: Volume,
pub enabled: bool,
}
impl Default for BeepTestNode {
fn default() -> Self {
Self {
freq_hz: 440.0,
volume: Volume::Linear(0.5),
enabled: true,
}
}
}
impl AudioNode for BeepTestNode {
type Configuration = EmptyConfig;
fn info(&self, _config: &Self::Configuration) -> AudioNodeInfo {
AudioNodeInfo::new()
.debug_name("beep_test")
.channel_config(ChannelConfig {
num_inputs: ChannelCount::ZERO,
num_outputs: ChannelCount::MONO,
})
}
fn construct_processor(
&self,
_config: &Self::Configuration,
cx: ConstructProcessorContext,
) -> impl AudioNodeProcessor {
Processor {
phasor: 0.0,
phasor_inc: self.freq_hz.clamp(20.0, 20_000.0)
* cx.stream_info.sample_rate_recip as f32,
gain: self.volume.amp_clamped(DEFAULT_AMP_EPSILON),
enabled: self.enabled,
}
}
}
struct Processor {
phasor: f32,
phasor_inc: f32,
gain: f32,
enabled: bool,
}
impl AudioNodeProcessor for Processor {
fn process(
&mut self,
buffers: ProcBuffers,
proc_info: &ProcInfo,
events: &mut NodeEventList,
_logger: &mut RealtimeLogger,
) -> ProcessStatus {
let Some(out) = buffers.outputs.first_mut() else {
return ProcessStatus::ClearAllOutputs;
};
for patch in events.drain_patches::<BeepTestNode>() {
match patch {
BeepTestNodePatch::FreqHz(f) => {
self.phasor_inc = f.clamp(20.0, 20_000.0) * proc_info.sample_rate_recip as f32;
}
BeepTestNodePatch::Volume(v) => {
self.gain = v.amp_clamped(DEFAULT_AMP_EPSILON);
}
BeepTestNodePatch::Enabled(e) => self.enabled = e,
}
}
if !self.enabled {
return ProcessStatus::ClearAllOutputs;
}
for s in out.iter_mut() {
*s = (self.phasor * core::f32::consts::TAU).sin() * self.gain;
self.phasor = (self.phasor + self.phasor_inc).fract();
}
ProcessStatus::outputs_not_silent()
}
}