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