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