1use crate::generators::{Generator, ModulatableGenerator, SyncableGenerator};
4use crate::vector::prelude::*;
5use rill_core::math::vector::scalar::ScalarVector4;
6use rill_core::math::vector::traits::{Vector, VectorMask, VectorTranscendental};
7use rill_core::traits::algorithm::{Algorithm, AlgorithmCategory, AlgorithmMetadata};
8use rill_core::traits::parameter_write::ParameterWrite;
9use rill_core::traits::{ParamValue, ProcessError, ProcessResult};
10use rill_core::Transcendental;
11use std::f32::consts::PI;
12
13#[derive(Debug, Clone, Copy, PartialEq)]
15pub enum Waveform {
16 Sine,
18 Saw,
20 Square,
22 Triangle,
24 Pulse(f32), }
27
28impl Waveform {
29 pub fn name(&self) -> &'static str {
31 match self {
32 Waveform::Sine => "Sine",
33 Waveform::Saw => "Saw",
34 Waveform::Square => "Square",
35 Waveform::Triangle => "Triangle",
36 Waveform::Pulse(_) => "Pulse",
37 }
38 }
39
40 pub fn description(&self) -> &'static str {
42 match self {
43 Waveform::Sine => "Pure sine wave - single harmonic",
44 Waveform::Saw => "Sawtooth wave - all harmonics (1/n)",
45 Waveform::Square => "Square wave - odd harmonics (1/n)",
46 Waveform::Triangle => "Triangle wave - odd harmonics (1/n²)",
47 Waveform::Pulse(_) => "Pulse wave with variable width",
48 }
49 }
50}
51
52#[derive(Clone, Copy)]
60pub struct BasicOscillator<T: Transcendental> {
61 waveform: Waveform,
63 frequency: f32,
65 amplitude: ScalarVector1<T>,
67 phase: ScalarVector1<T>,
69 phase_inc: ScalarVector1<T>,
71 sample_rate: f32,
73 periods: u32,
75 fm_amount: ScalarVector1<T>,
77}
78
79impl<T: Transcendental> BasicOscillator<T> {
80 pub fn new(waveform: Waveform, frequency: f32, amplitude: T) -> Self {
87 let mut osc = Self {
88 waveform,
89 frequency,
90 amplitude: ScalarVector1::splat(amplitude),
91 phase: ScalarVector1::splat(T::ZERO),
92 phase_inc: ScalarVector1::splat(T::ZERO),
93 sample_rate: 44100.0,
94 periods: 0,
95 fm_amount: ScalarVector1::splat(T::ZERO),
96 };
97 osc.update_phase_inc();
98 osc
99 }
100
101 #[inline(always)]
103 fn update_phase_inc(&mut self) {
104 self.phase_inc = ScalarVector1::splat(T::from_f32(self.frequency / self.sample_rate));
105 }
106
107 fn generate_block_simd(&mut self, output: &mut [T]) {
110 let chunks = output.len() / 4;
111 let _remainder = output.len() % 4;
112
113 if chunks > 0 {
114 let inc = self.phase_inc;
115 let inc4 = inc * ScalarVector1::splat(T::from_usize(4));
116 let one = ScalarVector1::splat(T::ONE);
117 let use_simd = (inc.extract(0) * T::from_usize(4)) < T::ONE;
118
119 if use_simd {
120 let mut phase = self.phase;
121 let amp_v = self.amplitude;
122
123 for chunk in 0..chunks {
124 let offset = chunk * 4;
125 let p0 = phase.extract(0);
126 let inc_t = inc.extract(0);
127
128 let phases = ScalarVector4::load(&[
129 p0,
130 p0 + inc_t,
131 p0 + inc_t + inc_t,
132 p0 + inc_t + inc_t + inc_t,
133 ]);
134
135 let vals = match self.waveform {
136 Waveform::Sine => self.simd_sine(&phases, &_v),
137 Waveform::Saw => self.simd_saw_blep(&phases, inc_t, &_v),
138 Waveform::Square => self.simd_square(&phases, &_v),
139 Waveform::Triangle => self.simd_triangle(&phases, &_v),
140 Waveform::Pulse(width) => {
141 self.simd_pulse(&phases, T::from_f32(width.clamp(0.01, 0.99)), &_v)
142 }
143 };
144
145 vals.store(&mut output[offset..offset + 4]);
146
147 phase = phase + inc4;
148 if phase.extract(0) >= one.extract(0) {
149 phase = phase - one;
150 self.periods += 1;
151 }
152 }
153 self.phase = phase;
154 } else {
155 for out in output[..chunks * 4].iter_mut() {
157 *out = self.generate_scalar();
158 }
159 }
160 }
161
162 for out in output[chunks * 4..].iter_mut() {
164 *out = self.generate_scalar();
165 }
166 }
167
168 fn generate_scalar(&mut self) -> T {
171 let effective_inc = self.phase_inc + self.fm_amount;
172 let output_vec = match self.waveform {
173 Waveform::Sine => self.scalar_sine(),
174 Waveform::Saw => self.scalar_saw_bandlimited(),
175 Waveform::Square => self.scalar_square(),
176 Waveform::Triangle => self.scalar_triangle(),
177 Waveform::Pulse(width) => self.scalar_pulse(width),
178 };
179 self.phase = self.phase + effective_inc;
180 let one = ScalarVector1::splat(T::ONE);
181 if self.phase.extract(0) >= one.extract(0) {
182 self.phase = self.phase - one;
183 self.periods += 1;
184 }
185 output_vec.extract(0)
186 }
187
188 #[inline(always)]
191 fn scalar_sine(&self) -> ScalarVector1<T> {
192 let phase_rad = self.phase.mul(&ScalarVector1::splat(T::from_f32(2.0 * PI)));
193 phase_rad.sin().mul(&self.amplitude)
194 }
195
196 #[inline(always)]
197 fn scalar_saw_raw(&self) -> ScalarVector1<T> {
198 self.phase
199 .mul(&ScalarVector1::splat(T::from_f32(2.0)))
200 .sub(&ScalarVector1::splat(T::from_f32(1.0)))
201 .mul(&self.amplitude)
202 }
203
204 #[inline(always)]
205 fn scalar_saw_bandlimited(&mut self) -> ScalarVector1<T> {
206 let raw = self.scalar_saw_raw();
207 let next_phase = self.phase.add(&self.phase_inc).extract(0);
208 let one = T::from_f32(1.0);
209 if next_phase >= one {
210 let one_vec = ScalarVector1::splat(one);
211 let t = (one_vec - self.phase) / self.phase_inc;
212 let blep =
213 t * ScalarVector1::splat(T::from_f32(2.0)) - ScalarVector1::splat(T::from_f32(1.0));
214 raw - blep * self.amplitude
215 } else {
216 raw
217 }
218 }
219
220 #[inline(always)]
221 fn scalar_square(&self) -> ScalarVector1<T> {
222 let half = T::from_f32(0.5);
223 if self.phase.extract(0) < half {
224 self.amplitude
225 } else {
226 -self.amplitude
227 }
228 }
229
230 #[inline(always)]
231 fn scalar_triangle(&self) -> ScalarVector1<T> {
232 let half = ScalarVector1::splat(T::from_f32(0.5));
233 let p = self.phase - half;
234 (p.abs() * ScalarVector1::splat(T::from_f32(4.0)) - ScalarVector1::splat(T::from_f32(1.0)))
235 * self.amplitude
236 }
237
238 #[inline(always)]
239 fn scalar_pulse(&self, width: f32) -> ScalarVector1<T> {
240 let width_t = T::from_f32(width.clamp(0.01, 0.99));
241 if self.phase.extract(0) < width_t {
242 self.amplitude
243 } else {
244 -self.amplitude
245 }
246 }
247
248 #[inline(always)]
251 fn simd_sine(&self, phases: &ScalarVector4<T>, amp: &ScalarVector1<T>) -> ScalarVector4<T> {
252 let pi2 = ScalarVector4::splat(T::from_f32(2.0 * PI));
253 let rad = phases.mul(&pi2);
254 let raw = rad.sin();
255 let amp_broadcast = ScalarVector4::splat(amp.extract(0));
256 raw.mul(&_broadcast)
257 }
258
259 #[inline(always)]
260 fn simd_triangle(&self, phases: &ScalarVector4<T>, amp: &ScalarVector1<T>) -> ScalarVector4<T> {
261 let half = ScalarVector4::splat(T::from_f32(0.5));
262 let four = ScalarVector4::splat(T::from_f32(4.0));
263 let one = ScalarVector4::splat(T::from_f32(1.0));
264 let amp_b = ScalarVector4::splat(amp.extract(0));
265 let p = phases.sub(&half);
266 p.abs().mul(&four).sub(&one).mul(&_b)
267 }
268
269 #[inline(always)]
270 fn simd_square(&self, phases: &ScalarVector4<T>, amp: &ScalarVector1<T>) -> ScalarVector4<T> {
271 let half = ScalarVector4::splat(T::from_f32(0.5));
272 let pos = ScalarVector4::splat(amp.extract(0));
273 let neg = ScalarVector4::splat(-amp.extract(0));
274 let mask = phases.lt(&half);
275 <ScalarVector4<T> as VectorMask<T, 4>>::select(&pos, &neg, mask)
276 }
277
278 #[inline(always)]
279 fn simd_pulse(
280 &self,
281 phases: &ScalarVector4<T>,
282 width_t: T,
283 amp: &ScalarVector1<T>,
284 ) -> ScalarVector4<T> {
285 let threshold = ScalarVector4::splat(width_t);
286 let pos = ScalarVector4::splat(amp.extract(0));
287 let neg = ScalarVector4::splat(-amp.extract(0));
288 let mask = phases.lt(&threshold);
289 <ScalarVector4<T> as VectorMask<T, 4>>::select(&pos, &neg, mask)
290 }
291
292 #[inline(always)]
293 fn simd_saw_raw(&self, phases: &ScalarVector4<T>, amp: &ScalarVector1<T>) -> ScalarVector4<T> {
294 let two = ScalarVector4::splat(T::from_f32(2.0));
295 let one = ScalarVector4::splat(T::from_f32(1.0));
296 let amp_b = ScalarVector4::splat(amp.extract(0));
297 phases.mul(&two).sub(&one).mul(&_b)
298 }
299
300 #[inline(always)]
301 fn simd_saw_blep(
302 &mut self,
303 phases: &ScalarVector4<T>,
304 inc: T,
305 amp: &ScalarVector1<T>,
306 ) -> ScalarVector4<T> {
307 let raw = self.simd_saw_raw(phases, amp);
308 let one = ScalarVector4::splat(T::ONE);
309 let two = ScalarVector4::splat(T::from_f32(2.0));
310 let inc_v = ScalarVector4::splat(inc);
311 let amp_v = ScalarVector4::splat(amp.extract(0));
312
313 let next = phases.add(&inc_v);
315
316 let wrap_mask = next.ge(&one);
318
319 let t = one.sub(phases).div(&inc_v);
321
322 let blep = t.mul(&two).sub(&one).mul(&_v);
324
325 let corrected = raw.sub(&blep);
326
327 <ScalarVector4<T> as VectorMask<T, 4>>::select(&corrected, &raw, wrap_mask)
328 }
329
330 pub(crate) fn generate(&mut self) -> ScalarVector1<T> {
332 let effective_inc = self.phase_inc + self.fm_amount;
333 let output_vec = match self.waveform {
334 Waveform::Sine => self.scalar_sine(),
335 Waveform::Saw => self.scalar_saw_bandlimited(),
336 Waveform::Square => self.scalar_square(),
337 Waveform::Triangle => self.scalar_triangle(),
338 Waveform::Pulse(width) => self.scalar_pulse(width),
339 };
340 self.phase = self.phase + effective_inc;
341 let one = ScalarVector1::splat(T::from_f32(1.0));
342 if self.phase.extract(0) >= one.extract(0) {
343 self.phase = self.phase - one;
344 self.periods += 1;
345 }
346 output_vec
347 }
348
349 pub fn reset_phase(&mut self) {
351 self.phase = ScalarVector1::splat(T::ZERO);
352 self.periods = 0;
353 }
354
355 pub fn current_phase(&self) -> T {
357 self.phase.extract(0)
358 }
359
360 pub fn period_count(&self) -> u32 {
362 self.periods
363 }
364
365 pub fn set_pulse_width(&mut self, width: f32) {
367 if let Waveform::Pulse(_) = self.waveform {
368 self.waveform = Waveform::Pulse(width.clamp(0.01, 0.99));
369 }
370 }
371}
372
373impl<T: Transcendental> Algorithm<T> for BasicOscillator<T> {
376 fn init(&mut self, sample_rate: f32) {
377 self.sample_rate = sample_rate;
378 self.update_phase_inc();
379 self.phase = ScalarVector1::splat(T::ZERO);
380 self.periods = 0;
381 }
382
383 fn reset(&mut self) {
384 self.phase = ScalarVector1::splat(T::ZERO);
385 self.periods = 0;
386 self.fm_amount = ScalarVector1::splat(T::ZERO);
387 }
388
389 fn process(&mut self, _input: Option<&[T]>, output: &mut [T]) -> ProcessResult<()> {
390 self.generate_block_simd(output);
391 Ok(())
392 }
393
394 fn metadata(&self) -> AlgorithmMetadata {
395 AlgorithmMetadata {
396 name: self.waveform.name(),
397 category: AlgorithmCategory::Generator,
398 description: self.waveform.description(),
399 author: "Rill",
400 version: env!("CARGO_PKG_VERSION"),
401 }
402 }
403}
404
405impl<T: Transcendental> Generator<T> for BasicOscillator<T> {
408 fn phase(&self) -> T {
409 self.phase.extract(0)
410 }
411
412 fn set_phase(&mut self, phase: T) {
413 let one = T::from_f32(1.0);
414 let zero = T::ZERO;
415 self.phase = ScalarVector1::splat(if phase > one {
416 one
417 } else if phase < zero {
418 zero
419 } else {
420 phase
421 });
422 }
423
424 fn frequency(&self) -> f32 {
425 self.frequency
426 }
427
428 fn set_frequency(&mut self, freq: f32) {
429 self.frequency = freq.clamp(0.1, 20000.0);
430 self.update_phase_inc();
431 }
432
433 fn amplitude(&self) -> T {
434 self.amplitude.extract(0)
435 }
436
437 fn set_amplitude(&mut self, amp: T) {
438 let one = T::from_f32(1.0);
439 let zero = T::ZERO;
440 self.amplitude = ScalarVector1::splat(if amp > one {
441 one
442 } else if amp < zero {
443 zero
444 } else {
445 amp
446 });
447 }
448}
449
450impl<T: Transcendental> ParameterWrite for BasicOscillator<T> {
453 fn write_parameter(&mut self, name: &str, value: ParamValue) -> ProcessResult<()> {
454 match name {
455 "frequency" => {
456 if let Some(f) = value.as_f32() {
457 self.set_frequency(f);
458 return Ok(());
459 }
460 Err(ProcessError::parameter("frequency expects float"))
461 }
462 "amplitude" => {
463 if let Some(a) = value.as_f32() {
464 self.set_amplitude(T::from_f32(a));
465 return Ok(());
466 }
467 Err(ProcessError::parameter("amplitude expects float"))
468 }
469 "phase" => {
470 if let Some(p) = value.as_f32() {
471 self.set_phase(T::from_f32(p));
472 return Ok(());
473 }
474 Err(ProcessError::parameter("phase expects float"))
475 }
476 "fm_amount" => {
477 if let Some(f) = value.as_f32() {
478 self.fm_amount = ScalarVector1::splat(T::from_f32(f));
479 return Ok(());
480 }
481 Err(ProcessError::parameter("fm_amount expects float"))
482 }
483 _ => Err(ProcessError::parameter(format!(
484 "unknown parameter: {name}"
485 ))),
486 }
487 }
488
489 fn read_parameter(&self, name: &str) -> Option<ParamValue> {
490 match name {
491 "frequency" => Some(ParamValue::Float(self.frequency())),
492 "amplitude" => Some(ParamValue::Float(self.amplitude().to_f32())),
493 "phase" => Some(ParamValue::Float(self.phase().to_f32())),
494 _ => None,
495 }
496 }
497}
498
499impl<T: Transcendental> SyncableGenerator<T> for BasicOscillator<T> {
502 fn sync(&mut self, reset: bool) {
503 if reset {
504 self.phase = ScalarVector1::splat(T::ZERO);
505 }
506 }
507
508 fn periods(&self) -> u32 {
509 self.periods
510 }
511}
512
513impl<T: Transcendental> ModulatableGenerator<T> for BasicOscillator<T> {
516 fn modulate_frequency(&mut self, amount: T) {
517 self.fm_amount = ScalarVector1::splat(amount);
518 }
519
520 fn modulation_index(&self) -> T {
521 self.fm_amount.extract(0)
522 }
523
524 fn set_modulation_index(&mut self, index: T) {
525 self.fm_amount = ScalarVector1::splat(index);
526 }
527}
528
529#[cfg(test)]
532mod tests {
533 use super::*;
534 use float_cmp::approx_eq;
535
536 #[test]
537 fn test_sine_oscillator() {
538 let mut osc = BasicOscillator::<f32>::new(Waveform::Sine, 440.0, 0.5);
539 osc.init(44100.0);
540
541 let mut output = [0.0f32; 1];
543 osc.process(None, &mut output).unwrap();
544 let sample1 = output[0];
545 assert!(approx_eq!(f32, sample1, 0.0, epsilon = 1e-6));
546
547 osc.process(None, &mut output).unwrap();
549 let sample2 = output[0];
550 assert!(sample2 != 0.0);
551 assert!((-0.5..=0.5).contains(&sample2));
552 }
553
554 #[test]
555 fn test_saw_oscillator() {
556 let mut osc = BasicOscillator::<f32>::new(Waveform::Saw, 440.0, 0.5);
557 osc.init(44100.0);
558
559 let mut output = [0.0f32; 1];
560 osc.process(None, &mut output).unwrap();
561 let sample = output[0];
562 assert!((-0.5..=0.5).contains(&sample));
563 }
564
565 #[test]
566 fn test_square_oscillator() {
567 let mut osc = BasicOscillator::<f32>::new(Waveform::Square, 440.0, 0.5);
568 osc.init(44100.0);
569
570 let mut output = [0.0f32; 1];
571 osc.process(None, &mut output).unwrap();
572 let sample = output[0];
573 assert!(sample == 0.5 || sample == -0.5);
574 }
575
576 #[test]
577 fn test_triangle_oscillator() {
578 let mut osc = BasicOscillator::<f32>::new(Waveform::Triangle, 440.0, 0.5);
579 osc.init(44100.0);
580
581 let mut output = [0.0f32; 1];
582 osc.process(None, &mut output).unwrap();
583 let sample = output[0];
584 assert!((-0.5..=0.5).contains(&sample));
585 }
586
587 #[test]
588 fn test_pulse_oscillator() {
589 let mut osc = BasicOscillator::<f32>::new(Waveform::Pulse(0.25), 440.0, 0.5);
590 osc.init(44100.0);
591
592 let mut output = [0.0f32; 1];
593 osc.process(None, &mut output).unwrap();
594 let sample = output[0];
595 assert!(sample == 0.5); }
597
598 #[test]
599 fn test_frequency_change() {
600 let mut osc = BasicOscillator::<f32>::new(Waveform::Sine, 440.0, 0.5);
601 osc.init(44100.0);
602
603 assert_eq!(osc.frequency(), 440.0);
604
605 osc.set_frequency(880.0);
606 assert_eq!(osc.frequency(), 880.0);
607 }
608
609 #[test]
610 fn test_amplitude_change() {
611 let mut osc = BasicOscillator::<f32>::new(Waveform::Sine, 440.0, 0.5);
612 osc.init(44100.0);
613
614 assert_eq!(osc.amplitude(), 0.5);
615
616 osc.set_amplitude(0.8);
617 assert_eq!(osc.amplitude(), 0.8);
618 }
619
620 #[test]
621 fn test_phase_manipulation() {
622 let mut osc = BasicOscillator::<f32>::new(Waveform::Sine, 440.0, 1.0);
623 osc.init(44100.0);
624
625 osc.set_phase(0.25); let mut output = [0.0f32; 1];
627 osc.process(None, &mut output).unwrap();
628 let sample = output[0];
629 assert!(approx_eq!(f32, sample, 1.0, epsilon = 1e-4)); }
631
632 #[test]
633 fn test_fm_modulation() {
634 let mut osc = BasicOscillator::<f32>::new(Waveform::Sine, 440.0, 1.0);
635 osc.init(44100.0);
636
637 osc.modulate_frequency(0.5);
638 assert_eq!(osc.modulation_index(), 0.5);
639
640 let mut output = [0.0f32; 1];
642 osc.process(None, &mut output).unwrap();
643 let sample = output[0];
644 assert!((-1.0..=1.0).contains(&sample));
645 }
646
647 #[test]
648 fn test_clone_copy() {
649 let osc1 = BasicOscillator::<f32>::new(Waveform::Sine, 440.0, 0.5);
650 let osc2 = osc1; let osc3 = Clone::clone(&osc1); assert_eq!(osc1.frequency(), osc2.frequency());
654 assert_eq!(osc1.frequency(), osc3.frequency());
655 }
656}