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 continue;
146 } else if tick > stop_at {
147 break;
148 }
149
150 if self.update_parameters(info, tick) {
151 oscillator_frequency = self.compute_oscillator_frequency(sample_rate);
152 step = two_pi * oscillator_frequency / sample_rate;
153 }
154 let value = vol *
155 self.periodic_wave.calculate_waveform(
156 oscillator_frequency,
157 sample_rate,
158 self.phase,
159 ) as f32;
160
161 frame.mutate_with(|sample, _| *sample = value);
162 self.phase = (self.phase + step).rem_euclid(two_pi);
164 }
165 }
166 inputs
167 }
168
169 fn input_count(&self) -> u32 {
170 0
171 }
172
173 fn get_param(&mut self, id: ParamType) -> &mut Param {
174 match id {
175 ParamType::Frequency => &mut self.frequency,
176 ParamType::Detune => &mut self.detune,
177 _ => panic!("Unknown param {:?} for OscillatorNode", id),
178 }
179 }
180 make_message_handler!(
181 AudioScheduledSourceNode: handle_source_node_message,
182 OscillatorNode: handle_oscillator_message
183 );
184}