1use super::basic::{BasicOscillator, Waveform};
10use crate::generators::{Generator, ModulatableGenerator};
11use crate::vector::prelude::*;
12use rill_core::traits::algorithm::{Algorithm, AlgorithmCategory, AlgorithmMetadata};
13use rill_core::traits::ProcessResult;
14use rill_core::Transcendental;
15
16#[derive(Clone, Copy)]
52pub struct SimpleFmSynth<T: Transcendental> {
53 carrier: BasicOscillator<T>,
55 modulator: BasicOscillator<T>,
57 modulation_index: ScalarVector1<T>,
59 ratio: f32,
61}
62
63impl<T: Transcendental> SimpleFmSynth<T> {
64 pub fn new(carrier_freq: f32, modulator_ratio: f32, modulation_index: T) -> Self {
71 let one = T::from_f32(1.0);
72 Self {
73 carrier: BasicOscillator::new(Waveform::Sine, carrier_freq, one),
74 modulator: BasicOscillator::new(Waveform::Sine, carrier_freq * modulator_ratio, one),
75 modulation_index: ScalarVector1::splat(modulation_index),
76 ratio: modulator_ratio,
77 }
78 }
79
80 pub fn with_carrier_waveform(mut self, waveform: Waveform) -> Self {
84 let freq = self.carrier.frequency();
85 self.carrier = BasicOscillator::new(waveform, freq, T::from_f32(1.0));
86 self
87 }
88
89 pub fn with_modulator_waveform(mut self, waveform: Waveform) -> Self {
93 let freq = self.modulator.frequency();
94 self.modulator = BasicOscillator::new(waveform, freq, T::from_f32(1.0));
95 self
96 }
97
98 pub fn set_carrier_frequency(&mut self, freq: f32) {
100 self.carrier.set_frequency(freq);
101 self.modulator.set_frequency(freq * self.ratio);
102 }
103
104 pub fn set_modulation_index(&mut self, index: T) {
109 self.modulation_index = ScalarVector1::splat(index);
110 self.carrier.set_modulation_index(index);
111 }
112
113 pub fn set_ratio(&mut self, ratio: f32) {
118 self.ratio = ratio;
119 self.modulator
120 .set_frequency(self.carrier.frequency() * ratio);
121 }
122
123 pub fn modulation_index(&self) -> T {
125 self.modulation_index.extract(0)
126 }
127
128 pub fn ratio(&self) -> f32 {
130 self.ratio
131 }
132}
133
134impl<T: Transcendental> Algorithm<T> for SimpleFmSynth<T> {
135 fn init(&mut self, sample_rate: f32) {
136 self.carrier.init(sample_rate);
137 self.modulator.init(sample_rate);
138 }
139
140 fn reset(&mut self) {
141 self.carrier.reset();
142 self.modulator.reset();
143 }
144
145 fn process(&mut self, _input: Option<&[T]>, output: &mut [T]) -> ProcessResult<()> {
146 for out in output.iter_mut() {
147 let mod_signal = self.modulator.generate().extract(0);
149
150 self.carrier
152 .modulate_frequency(mod_signal * self.modulation_index.extract(0));
153
154 *out = self.carrier.generate().extract(0);
156 }
157 Ok(())
158 }
159
160 fn metadata(&self) -> AlgorithmMetadata {
161 AlgorithmMetadata {
162 name: "Simple FM Synth",
163 category: AlgorithmCategory::Generator,
164 description: "2-operator FM synthesizer",
165 author: "Rill",
166 version: env!("CARGO_PKG_VERSION"),
167 }
168 }
169}
170
171impl<T: Transcendental> Generator<T> for SimpleFmSynth<T> {
174 fn phase(&self) -> T {
175 self.carrier.phase()
176 }
177
178 fn set_phase(&mut self, phase: T) {
179 self.carrier.set_phase(phase);
180 self.modulator.set_phase(phase);
181 }
182
183 fn frequency(&self) -> f32 {
184 self.carrier.frequency()
185 }
186
187 fn set_frequency(&mut self, freq: f32) {
188 self.set_carrier_frequency(freq);
189 }
190
191 fn amplitude(&self) -> T {
192 self.carrier.amplitude()
193 }
194
195 fn set_amplitude(&mut self, amp: T) {
196 self.carrier.set_amplitude(amp);
197 self.modulator.set_amplitude(amp);
198 }
199}
200
201impl<T: Transcendental> ModulatableGenerator<T> for SimpleFmSynth<T> {
204 fn modulate_frequency(&mut self, amount: T) {
205 self.carrier.modulate_frequency(amount);
206 self.modulation_index = ScalarVector1::splat(amount);
208 }
209
210 fn modulation_index(&self) -> T {
211 SimpleFmSynth::modulation_index(self)
212 }
213
214 fn set_modulation_index(&mut self, index: T) {
215 SimpleFmSynth::set_modulation_index(self, index);
216 }
217}
218
219pub struct FmSynth<T: Transcendental, const N: usize> {
251 operators: [BasicOscillator<T>; N],
253 algorithm: [[bool; N]; N],
256 modulation_indices: [ScalarVector1<T>; N],
258}
259
260impl<T: Transcendental, const N: usize> FmSynth<T, N> {
261 pub fn new(frequencies: [f32; N], algorithm: [[bool; N]; N]) -> Self {
267 let one = T::from_f32(1.0);
268 let mut operators = [BasicOscillator::new(Waveform::Sine, 440.0, one); N];
269 for i in 0..N {
270 operators[i].set_frequency(frequencies[i]);
271 }
272
273 Self {
274 operators,
275 algorithm,
276 modulation_indices: [ScalarVector1::splat(T::ZERO); N],
277 }
278 }
279
280 pub fn new_with_freq(frequency: f32, algorithm: [[bool; N]; N]) -> Self {
282 let one = T::from_f32(1.0);
283 let operators = [BasicOscillator::new(Waveform::Sine, frequency, one); N];
284
285 Self {
286 operators,
287 algorithm,
288 modulation_indices: [ScalarVector1::splat(T::ZERO); N],
289 }
290 }
291
292 pub fn set_waveform(&mut self, index: usize, waveform: Waveform) {
294 if index < N {
295 let freq = self.operators[index].frequency();
296 self.operators[index] = BasicOscillator::new(waveform, freq, T::from_f32(1.0));
297 }
298 }
299
300 pub fn set_frequency(&mut self, index: usize, freq: f32) {
302 if index < N {
303 self.operators[index].set_frequency(freq);
304 }
305 }
306
307 pub fn set_modulation_index(&mut self, index: usize, idx: T) {
309 if index < N {
310 self.modulation_indices[index] = ScalarVector1::splat(idx);
311 }
312 }
313
314 pub fn peek_operator(&self, index: usize) -> T {
316 if index < N {
317 self.operators[index].phase()
318 } else {
319 T::ZERO
320 }
321 }
322
323 pub fn reset_all(&mut self) {
325 for op in &mut self.operators {
326 op.reset();
327 }
328 }
329}
330
331impl<T: Transcendental, const N: usize> Algorithm<T> for FmSynth<T, N> {
332 fn init(&mut self, sample_rate: f32) {
333 for op in &mut self.operators {
334 op.init(sample_rate);
335 }
336 }
337
338 fn reset(&mut self) {
339 self.reset_all();
340 }
341
342 fn process(&mut self, _input: Option<&[T]>, output: &mut [T]) -> ProcessResult<()> {
343 for out in output.iter_mut() {
344 let values: [_; N] = core::array::from_fn(|i| self.operators[i].generate().extract(0));
346
347 for (i, op) in self.operators.iter_mut().enumerate() {
349 let mut mod_sum = T::ZERO;
350
351 for (j, &is_mod) in self.algorithm[i].iter().enumerate() {
353 if is_mod {
354 mod_sum += values[j] * self.modulation_indices[j].extract(0);
355 }
356 }
357
358 if mod_sum != T::ZERO {
360 op.modulate_frequency(mod_sum);
361 }
362 }
363
364 *out = values[N - 1];
367 }
368 Ok(())
369 }
370
371 fn metadata(&self) -> AlgorithmMetadata {
372 match N {
374 2 => AlgorithmMetadata {
375 name: "2-operator FM Synth",
376 category: AlgorithmCategory::Generator,
377 description: "2-operator FM synthesizer",
378 author: "Rill",
379 version: env!("CARGO_PKG_VERSION"),
380 },
381 3 => AlgorithmMetadata {
382 name: "3-operator FM Synth",
383 category: AlgorithmCategory::Generator,
384 description: "3-operator FM synthesizer",
385 author: "Rill",
386 version: env!("CARGO_PKG_VERSION"),
387 },
388 4 => AlgorithmMetadata {
389 name: "4-operator FM Synth",
390 category: AlgorithmCategory::Generator,
391 description: "4-operator FM synthesizer (DX7 style)",
392 author: "Rill",
393 version: env!("CARGO_PKG_VERSION"),
394 },
395 5 => AlgorithmMetadata {
396 name: "5-operator FM Synth",
397 category: AlgorithmCategory::Generator,
398 description: "5-operator FM synthesizer",
399 author: "Rill",
400 version: env!("CARGO_PKG_VERSION"),
401 },
402 6 => AlgorithmMetadata {
403 name: "6-operator FM Synth",
404 category: AlgorithmCategory::Generator,
405 description: "6-operator FM synthesizer (DX7 style)",
406 author: "Rill",
407 version: env!("CARGO_PKG_VERSION"),
408 },
409 _ => AlgorithmMetadata {
410 name: "FM Synth",
411 category: AlgorithmCategory::Generator,
412 description: "Multi-operator FM synthesizer",
413 author: "Rill",
414 version: env!("CARGO_PKG_VERSION"),
415 },
416 }
417 }
418}
419
420pub mod algorithms_4op {
426 pub const ALGORITHM_1: [[bool; 4]; 4] = [
428 [false, true, false, false],
429 [false, false, true, false],
430 [false, false, false, true],
431 [false, false, false, false],
432 ];
433
434 pub const ALGORITHM_2: [[bool; 4]; 4] = [
436 [false, true, false, false],
437 [false, false, false, false],
438 [false, false, false, true],
439 [false, false, false, false],
440 ];
441
442 pub const ALGORITHM_3: [[bool; 4]; 4] = [
444 [false, false, false, false],
445 [false, false, false, false],
446 [true, true, false, false],
447 [false, false, false, false],
448 ];
449}
450
451pub mod algorithms_6op {
453 pub const ALGORITHM_1: [[bool; 6]; 6] = [
455 [false, true, false, false, false, false],
456 [false, false, true, false, false, false],
457 [false, false, false, true, false, false],
458 [false, false, false, false, true, false],
459 [false, false, false, false, false, true],
460 [false, false, false, false, false, false],
461 ];
462
463 pub const ALGORITHM_2: [[bool; 6]; 6] = [
465 [false, true, false, false, false, false],
466 [false, false, true, false, false, false],
467 [false, false, false, false, false, false],
468 [false, false, false, false, true, false],
469 [false, false, false, false, false, true],
470 [false, false, false, false, false, false],
471 ];
472
473 pub const ALGORITHM_3: [[bool; 6]; 6] = [
475 [false, true, false, false, false, false],
476 [true, false, true, false, false, false],
477 [false, false, false, true, false, false],
478 [false, false, false, false, true, false],
479 [false, false, false, false, false, true],
480 [false, false, false, false, false, false],
481 ];
482}
483
484#[cfg(test)]
489mod tests {
490 use super::*;
491
492 #[test]
493 fn test_simple_fm_synth() {
494 let mut fm = SimpleFmSynth::<f32>::new(440.0, 2.0, 1.5);
495 fm.init(44100.0);
496
497 let mut output = [0.0f32; 1];
498 fm.process(None, &mut output).unwrap();
499 let sample = output[0];
500 assert!((-1.0..=1.0).contains(&sample));
501 }
502
503 #[test]
504 fn test_simple_fm_with_different_waveforms() {
505 let mut fm = SimpleFmSynth::<f32>::new(440.0, 2.0, 1.5)
506 .with_carrier_waveform(Waveform::Saw)
507 .with_modulator_waveform(Waveform::Square);
508 fm.init(44100.0);
509
510 let mut output = [0.0f32; 1];
511 fm.process(None, &mut output).unwrap();
512 let sample = output[0];
513 assert!((-1.0..=1.0).contains(&sample));
514 }
515
516 #[test]
517 fn test_simple_fm_parameters() {
518 let mut fm = SimpleFmSynth::<f32>::new(440.0, 2.0, 1.5);
519 fm.init(44100.0);
520
521 assert_eq!(fm.frequency(), 440.0);
522 assert_eq!(fm.ratio(), 2.0);
523 assert_eq!(fm.modulation_index(), 1.5);
524
525 fm.set_carrier_frequency(880.0);
526 assert_eq!(fm.frequency(), 880.0);
527
528 fm.set_ratio(3.0);
529 assert_eq!(fm.ratio(), 3.0);
530
531 fm.set_modulation_index(2.0);
532 assert_eq!(fm.modulation_index(), 2.0);
533 }
534
535 #[test]
536 fn test_fm_synth_4op() {
537 let frequencies = [440.0, 880.0, 1320.0, 1760.0];
538 let mut fm = FmSynth::<f32, 4>::new(frequencies, algorithms_4op::ALGORITHM_1);
539 fm.init(44100.0);
540
541 let mut output = [0.0f32; 1];
542 fm.process(None, &mut output).unwrap();
543 let sample = output[0];
544 assert!((-1.0..=1.0).contains(&sample));
545 }
546
547 #[test]
548 fn test_fm_synth_6op() {
549 let frequencies = [440.0, 880.0, 1320.0, 1760.0, 2200.0, 2640.0];
550 let mut fm = FmSynth::<f32, 6>::new(frequencies, algorithms_6op::ALGORITHM_1);
551 fm.init(44100.0);
552
553 let mut output = [0.0f32; 1];
554 fm.process(None, &mut output).unwrap();
555 let sample = output[0];
556 assert!((-1.0..=1.0).contains(&sample));
557 }
558
559 #[test]
560 fn test_fm_synth_set_waveform() {
561 let frequencies = [440.0, 880.0];
562 let algorithm = [[false, true], [false, false]];
563
564 let mut fm = FmSynth::<f32, 2>::new(frequencies, algorithm);
565 fm.init(44100.0);
566
567 fm.set_waveform(0, Waveform::Saw);
568 fm.set_waveform(1, Waveform::Square);
569
570 let mut output = [0.0f32; 1];
571 fm.process(None, &mut output).unwrap();
572 let sample = output[0];
573 assert!((-1.0..=1.0).contains(&sample));
574 }
575
576 #[test]
577 fn test_generator_trait() {
578 use crate::generators::Generator;
579
580 let mut fm = SimpleFmSynth::<f32>::new(440.0, 2.0, 1.5);
581 fm.init(44100.0);
582
583 assert_eq!(fm.frequency(), 440.0);
584 fm.set_frequency(880.0);
585 assert_eq!(fm.frequency(), 880.0);
586
587 fm.set_amplitude(0.5);
588 assert_eq!(fm.amplitude(), 0.5);
589
590 let phase = fm.phase();
591 assert!((0.0..=1.0).contains(&phase));
592 }
593
594 #[test]
595 fn test_modulatable_trait() {
596 use crate::generators::ModulatableGenerator;
597
598 let mut fm = SimpleFmSynth::<f32>::new(440.0, 2.0, 1.5);
599 fm.init(44100.0);
600
601 assert_eq!(fm.modulation_index(), 1.5);
603
604 fm.modulate_frequency(0.3);
606 assert_eq!(
607 fm.modulation_index(),
608 0.3,
609 "modulation_index should be updated to 0.3"
610 );
611
612 fm.set_modulation_index(0.8);
614 assert_eq!(
615 fm.modulation_index(),
616 0.8,
617 "modulation_index should be updated to 0.8"
618 );
619 }
620
621 #[test]
622 fn test_clone_copy() {
623 let fm1 = SimpleFmSynth::<f32>::new(440.0, 2.0, 1.5);
624 let fm2 = fm1; let fm3 = Clone::clone(&fm1); assert_eq!(fm1.frequency(), fm2.frequency());
628 assert_eq!(fm1.frequency(), fm3.frequency());
629 assert_eq!(fm1.ratio(), fm2.ratio());
630 }
631}