ruffbox_synth/building_blocks/oscillators/
fm_tri.rs1use crate::building_blocks::{
2 Modulator, MonoSource, SampleBuffer, SynthParameterLabel, SynthParameterValue,
3};
4
5use std::f32::consts::PI;
6
7#[derive(Clone)]
16pub struct FMTri<const BUFSIZE: usize> {
17 freq: f32,
19 amp: f32,
20
21 samplerate: f32,
23 osc1: f32, osc2: f32, phase: f32, w: f32, scaling: f32, dc_comp: f32, norm: f32, del: f32, freq_mod: Option<Modulator<BUFSIZE>>, amp_mod: Option<Modulator<BUFSIZE>>, }
38
39impl<const BUFSIZE: usize> FMTri<BUFSIZE> {
40 pub fn new(freq: f32, amp: f32, samplerate: f32) -> Self {
41 let w: f32 = freq / samplerate;
42 let n: f32 = 0.5 - w;
43 FMTri {
44 freq,
45 amp,
46 samplerate,
47 osc1: 0.0, osc2: 0.0, phase: 0.0, w, scaling: 13.0 * n * n * n * n * 0.5, dc_comp: 0.11 + w * 0.2, norm: 1.0 - 2.0 * w, del: 0.0, freq_mod: None,
57 amp_mod: None,
58 }
59 }
60
61 #[inline(always)]
62 pub fn update_internals(&mut self, freq: f32) {
63 self.w = freq / self.samplerate;
64 let n: f32 = 0.5 - self.w;
65 self.scaling = 13.0 * n * n * n * n * 0.5;
66 self.dc_comp = 0.11 + self.w * 0.2;
67 self.norm = 1.0 - 2.0 * self.w;
68 }
69}
70
71impl<const BUFSIZE: usize> MonoSource<BUFSIZE> for FMTri<BUFSIZE> {
72 fn reset(&mut self) {}
73
74 fn set_modulator(
75 &mut self,
76 par: SynthParameterLabel,
77 init: f32,
78 modulator: Modulator<BUFSIZE>,
79 ) {
80 match par {
81 SynthParameterLabel::PitchFrequency => {
82 self.freq = init;
83 self.freq_mod = Some(modulator);
84 }
85 SynthParameterLabel::OscillatorAmplitude => {
86 self.amp = init;
87 self.amp_mod = Some(modulator);
88 }
89 _ => {}
90 }
91 }
92
93 fn set_parameter(&mut self, par: SynthParameterLabel, value: &SynthParameterValue) {
95 match par {
96 SynthParameterLabel::PitchFrequency => {
97 if let SynthParameterValue::ScalarF32(f) = value {
98 self.freq = *f;
99 self.update_internals(*f);
100 }
101 }
102 SynthParameterLabel::OscillatorAmplitude => {
103 if let SynthParameterValue::ScalarF32(l) = value {
104 self.amp = *l;
105 }
106 }
107 _ => (),
108 };
109 }
110
111 fn finish(&mut self) {}
112
113 fn is_finished(&self) -> bool {
114 false
115 }
116
117 fn get_next_block(
118 &mut self,
119 start_sample: usize,
120 in_buffers: &[SampleBuffer],
121 ) -> [f32; BUFSIZE] {
122 let mut out_buf: [f32; BUFSIZE] = [0.0; BUFSIZE];
123
124 if self.freq_mod.is_some() || self.amp_mod.is_some() {
125 let amp_buf = if let Some(m) = self.amp_mod.as_mut() {
126 m.process(self.amp, start_sample, in_buffers)
127 } else {
128 [self.amp; BUFSIZE]
129 };
130
131 let freq_buf = if let Some(m) = self.freq_mod.as_mut() {
132 m.process(self.freq, start_sample, in_buffers)
133 } else {
134 [self.freq; BUFSIZE]
135 };
136
137 for (i, current_sample) in out_buf
138 .iter_mut()
139 .enumerate()
140 .take(BUFSIZE)
141 .skip(start_sample)
142 {
143 self.update_internals(freq_buf[i]);
144
145 self.phase += 2.0 * self.w;
146 if self.phase >= 1.0 {
147 self.phase -= 2.0;
148 }
149
150 self.osc1 =
151 (self.osc1 + (PI * (self.phase + self.scaling * self.osc1)).sin()) * 0.5;
152 self.osc2 = (self.osc2
153 + (PI * ((self.phase + 0.25) + self.scaling * self.osc2)).sin())
154 * 0.5;
155
156 let min = f32::min(self.osc1, -self.osc2);
157 let o = 2.5 * min - 1.5 * self.del;
158 self.del = min;
159
160 *current_sample = (((o + 0.5) * 2.0) - self.dc_comp) * self.norm * amp_buf[i];
161 }
162 } else {
163 for current_sample in out_buf.iter_mut().take(BUFSIZE).skip(start_sample) {
164 self.phase += 2.0 * self.w;
167 if self.phase >= 1.0 {
168 self.phase -= 2.0;
169 }
170
171 self.osc1 =
172 (self.osc1 + (PI * (self.phase + self.scaling * self.osc1)).sin()) * 0.5;
173 self.osc2 = (self.osc2
174 + (PI * ((self.phase + 0.25) + self.scaling * self.osc2)).sin())
175 * 0.5;
176
177 let min = f32::min(self.osc1, -self.osc2);
178 let o = 2.5 * min - 1.5 * self.del;
179 self.del = min;
180
181 *current_sample = (((o + 0.5) * 2.0) - self.dc_comp) * self.norm * self.amp;
182 }
183 }
184
185 out_buf
186 }
187}