servo_media_audio/
oscillator_node.rs1use malloc_size_of_derive::MallocSizeOf;
6
7use crate::audio_node::{
8 AudioNodeEngine, AudioNodeType, AudioScheduledSourceNodeMessage, BlockInfo, ChannelInfo,
9 OnEndedCallback, ShouldPlay,
10};
11use crate::block::{Chunk, Tick};
12use crate::param::{Param, ParamType};
13use crate::periodic_wave::PeriodicWave;
14
15#[derive(Clone, Debug, MallocSizeOf)]
16pub enum OscillatorType {
17 Sine,
18 Square,
19 Sawtooth,
20 Triangle,
21 Custom(PeriodicWave),
22}
23
24#[derive(Clone, Debug, MallocSizeOf)]
25pub struct OscillatorNodeOptions {
26 pub oscillator_type: OscillatorType,
27 pub freq: f32,
28 pub detune: f32,
29}
30
31impl Default for OscillatorNodeOptions {
32 fn default() -> Self {
33 OscillatorNodeOptions {
34 oscillator_type: OscillatorType::Sine,
35 freq: 440.,
36 detune: 0.,
37 }
38 }
39}
40
41#[derive(Clone, Debug, MallocSizeOf)]
42pub enum OscillatorNodeMessage {
43 SetOscillatorType(OscillatorType),
44 SetPeriodicWave(PeriodicWave),
45}
46
47#[derive(AudioScheduledSourceNode, AudioNodeCommon)]
48pub(crate) struct OscillatorNode {
49 channel_info: ChannelInfo,
50 periodic_wave: PeriodicWave,
51 frequency: Param,
52 detune: Param,
53 phase: f64,
54 start_at: Option<Tick>,
56 stop_at: Option<Tick>,
58 onended_callback: Option<OnEndedCallback>,
60}
61
62impl OscillatorNode {
63 pub fn new(options: OscillatorNodeOptions, channel_info: ChannelInfo) -> Self {
64 Self {
65 channel_info,
66 periodic_wave: PeriodicWave::generate_waveform_coefficients(options.oscillator_type),
67 frequency: Param::new(options.freq),
68 detune: Param::new(options.detune),
69 phase: 0.,
70 start_at: None,
71 stop_at: None,
72 onended_callback: None,
73 }
74 }
75
76 pub fn update_parameters(&mut self, info: &BlockInfo, tick: Tick) -> bool {
77 let (frequency_updated, detune_updated) = (
78 self.frequency.update(info, tick),
79 self.detune.update(info, tick),
80 );
81 frequency_updated || detune_updated
82 }
83
84 fn compute_oscillator_frequency(&self, sample_rate: f64) -> f64 {
85 let mut detune = self.detune.value() as f64;
89 let critical_detune = 1200.0 * f64::MAX.log2();
90 detune = detune.clamp(-critical_detune, critical_detune);
91 let nyquist = sample_rate / 2.0;
92 let mut frequency = (self.frequency.value() as f64).clamp(-nyquist, nyquist);
93 frequency *= (detune / 1200.0).exp2();
94 frequency.clamp(-nyquist, nyquist)
96 }
97
98 fn handle_oscillator_message(&mut self, message: OscillatorNodeMessage, _sample_rate: f32) {
99 match message {
100 OscillatorNodeMessage::SetOscillatorType(o) => {
101 self.periodic_wave = PeriodicWave::generate_waveform_coefficients(o);
102 },
103 OscillatorNodeMessage::SetPeriodicWave(w) => {
104 self.periodic_wave = w;
105 },
106 }
107 }
108}
109
110impl AudioNodeEngine for OscillatorNode {
111 fn node_type(&self) -> AudioNodeType {
112 AudioNodeType::OscillatorNode
113 }
114
115 fn process(&mut self, mut inputs: Chunk, info: &BlockInfo) -> Chunk {
116 use std::f64::consts::PI;
117 debug_assert!(inputs.is_empty());
118 inputs.blocks.push(Default::default());
119 let (start_at, stop_at) = match self.should_play_at(info.frame) {
120 ShouldPlay::No => {
121 return inputs;
122 },
123 ShouldPlay::Between(start, end) => (start, end),
124 };
125
126 {
127 inputs.blocks[0].explicit_silence();
128 let mut iter = inputs.blocks[0].iter();
129
130 let vol: f32 = 1.0;
132 let sample_rate = info.sample_rate as f64;
133 let two_pi = 2.0 * PI;
134
135 let mut oscillator_frequency = self.compute_oscillator_frequency(sample_rate);
141 let mut step = two_pi * oscillator_frequency / sample_rate;
142 while let Some(mut frame) = iter.next() {
143 let tick = frame.tick();
144 if tick < start_at {
145 self.update_parameters(info, frame.tick());
147 continue;
148 } else if tick >= stop_at {
149 break;
150 }
151
152 if self.update_parameters(info, tick) {
153 oscillator_frequency = self.compute_oscillator_frequency(sample_rate);
154 step = two_pi * oscillator_frequency / sample_rate;
155 }
156 let value = vol *
157 self.periodic_wave.calculate_waveform(
158 oscillator_frequency,
159 sample_rate,
160 self.phase,
161 ) as f32;
162
163 frame.mutate_with(|sample, _| *sample = value);
164 self.phase = (self.phase + step).rem_euclid(two_pi);
166 }
167 }
168 inputs
169 }
170
171 fn input_count(&self) -> u32 {
172 0
173 }
174
175 fn get_param(&mut self, id: ParamType) -> &mut Param {
176 match id {
177 ParamType::Frequency => &mut self.frequency,
178 ParamType::Detune => &mut self.detune,
179 _ => panic!("Unknown param {:?} for OscillatorNode", id),
180 }
181 }
182 make_message_handler!(
183 AudioScheduledSourceNode: handle_source_node_message,
184 OscillatorNode: handle_oscillator_message
185 );
186}