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