2022-07-20 10:32:18 +00:00
|
|
|
use crate::dsp::{DspNode, LedPhaseVals, NodeContext, NodeId, ProcBuf, SAtom};
|
2022-07-19 09:44:54 +00:00
|
|
|
use crate::nodes::{NodeAudioContext, NodeExecContext};
|
|
|
|
|
|
|
|
/// A simple amplifier
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub struct Formant {
|
|
|
|
inv_sample_rate: f32,
|
|
|
|
phase: f32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Formant {
|
|
|
|
pub fn new(_nid: &NodeId) -> Self {
|
|
|
|
Self { inv_sample_rate: 1.0 / 44100.0, phase: 0.0 }
|
|
|
|
}
|
2022-07-20 10:32:18 +00:00
|
|
|
pub const freq: &'static str = "Formant freq\nBase frequency to oscilate at\n";
|
|
|
|
pub const form: &'static str = "Formant form\nFrequency of the formant\n";
|
2022-07-19 09:44:54 +00:00
|
|
|
pub const atk: &'static str =
|
2022-07-20 10:32:18 +00:00
|
|
|
"Formant atk\nFormant attack bandwidth, controls the general bandwidth";
|
|
|
|
pub const dcy: &'static str =
|
|
|
|
"Formant dcy\nFormant decay bandwidth, controls the peak bandwidth";
|
|
|
|
pub const sig: &'static str = "Formant sig\nGenerated formant signal";
|
2022-07-19 09:44:54 +00:00
|
|
|
pub const DESC: &'static str = r#"A direct formant synthesizer
|
|
|
|
|
|
|
|
This generates a single formant from a given frequency, formant frequency, as well as attack and decay frequencies.
|
|
|
|
The attack and decay frequencies both control the bandwidth of the formant, decay the peak of the bandwidth, attack peak.
|
|
|
|
"#;
|
|
|
|
pub const HELP: &'static str = r#"Formant - Single formant synthesizer
|
|
|
|
This is a formant synthesizer that directly generates the audio, no filters needed.
|
|
|
|
"#;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DspNode for Formant {
|
|
|
|
fn outputs() -> usize {
|
|
|
|
1
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_sample_rate(&mut self, srate: f32) {
|
|
|
|
self.inv_sample_rate = 1.0 / srate;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reset(&mut self) {
|
|
|
|
self.phase = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn process<T: NodeAudioContext>(
|
|
|
|
&mut self,
|
|
|
|
ctx: &mut T,
|
|
|
|
_ectx: &mut NodeExecContext,
|
|
|
|
_nctx: &NodeContext,
|
2022-07-20 10:32:18 +00:00
|
|
|
_atoms: &[SAtom],
|
2022-07-19 09:44:54 +00:00
|
|
|
inputs: &[ProcBuf],
|
|
|
|
outputs: &mut [ProcBuf],
|
2022-07-20 10:32:18 +00:00
|
|
|
_ctx_vals: LedPhaseVals,
|
2022-07-19 09:44:54 +00:00
|
|
|
) {
|
2022-07-20 10:32:18 +00:00
|
|
|
use crate::dsp::{denorm, inp, out};
|
2022-07-19 09:44:54 +00:00
|
|
|
|
|
|
|
let base_freq = inp::Formant::freq(inputs);
|
2022-07-20 10:32:18 +00:00
|
|
|
let formant_freq = inp::Formant::form(inputs);
|
2022-07-19 09:44:54 +00:00
|
|
|
let attack_freq = inp::Formant::atk(inputs);
|
|
|
|
let decay_freq = inp::Formant::dcy(inputs);
|
|
|
|
let out = out::Formant::sig(outputs);
|
|
|
|
|
|
|
|
for frame in 0..ctx.nframes() {
|
2022-07-20 10:32:18 +00:00
|
|
|
// get the inputs
|
2022-07-20 12:31:00 +00:00
|
|
|
let base_freq = denorm::Formant::freq(base_freq, frame);
|
2022-07-20 12:45:48 +00:00
|
|
|
let formant_freq = denorm::Formant::form(formant_freq, frame);
|
|
|
|
let attack_freq = denorm::Formant::atk(attack_freq, frame);
|
|
|
|
let decay_freq = denorm::Formant::dcy(decay_freq, frame);
|
2022-07-20 10:32:18 +00:00
|
|
|
|
2022-07-19 09:44:54 +00:00
|
|
|
// where the two decays meet
|
2022-08-07 19:28:45 +00:00
|
|
|
// clamp to avoid division by 0
|
|
|
|
let carrier_center =
|
|
|
|
(attack_freq / (attack_freq + decay_freq)).max(1e-6).min(1.0 - 1e-6);
|
2022-07-19 09:44:54 +00:00
|
|
|
|
|
|
|
// where they meet in amplitude
|
2022-08-07 19:28:45 +00:00
|
|
|
let carrier_lowest_amplitude =
|
|
|
|
if carrier_center * decay_freq > base_freq * 2.0 || base_freq == 0.0 {
|
|
|
|
0.0
|
|
|
|
} else {
|
|
|
|
(-(std::f32::consts::PI * carrier_center * decay_freq) / base_freq).exp()
|
|
|
|
};
|
2022-07-19 09:44:54 +00:00
|
|
|
|
2022-07-24 10:16:39 +00:00
|
|
|
// make a triangle wave, with the peak at carrier center
|
|
|
|
let carrier_base =
|
|
|
|
(self.phase / carrier_center).min((1.0 - self.phase) / (1.0 - carrier_center));
|
2022-07-19 09:44:54 +00:00
|
|
|
|
|
|
|
// smoothstep
|
2022-07-24 10:16:39 +00:00
|
|
|
let carrier = 1.0
|
|
|
|
- ((1.0 - carrier_lowest_amplitude)
|
|
|
|
* (carrier_base * carrier_base * (3.0 - 2.0 * carrier_base)));
|
2022-07-19 09:44:54 +00:00
|
|
|
|
|
|
|
// multiple of the frequency the modulators are at
|
2022-08-07 19:28:45 +00:00
|
|
|
let multiple = formant_freq / base_freq.max(1e-6);
|
2022-07-19 09:44:54 +00:00
|
|
|
|
|
|
|
// round them to the closest integer of the formant freq
|
2022-08-07 19:28:45 +00:00
|
|
|
let freq_a = multiple.floor();
|
2022-07-19 09:44:54 +00:00
|
|
|
let freq_b = freq_a + 1.0;
|
|
|
|
|
|
|
|
// and how much to lerp between them
|
2022-08-07 19:28:45 +00:00
|
|
|
let blend = multiple.fract();
|
2022-07-19 09:44:54 +00:00
|
|
|
|
|
|
|
// get the true modulator
|
2022-08-07 19:28:45 +00:00
|
|
|
let modulator = (1.0 - blend)
|
|
|
|
* if multiple < 1.0 {
|
|
|
|
0.0
|
|
|
|
} else {
|
|
|
|
(std::f32::consts::TAU * self.phase * freq_a).cos()
|
|
|
|
}
|
2022-07-19 09:44:54 +00:00
|
|
|
+ blend * (std::f32::consts::TAU * self.phase * freq_b).cos();
|
|
|
|
|
|
|
|
// entire wave
|
|
|
|
let wave = carrier * modulator;
|
|
|
|
|
2022-07-20 11:57:40 +00:00
|
|
|
// increment phase (very imporant)
|
2022-07-20 12:06:14 +00:00
|
|
|
self.phase += base_freq * self.inv_sample_rate;
|
2022-07-24 10:16:39 +00:00
|
|
|
|
|
|
|
// wrap around
|
2022-07-20 12:06:14 +00:00
|
|
|
self.phase = self.phase.fract();
|
2022-07-20 11:57:40 +00:00
|
|
|
|
2022-07-19 09:44:54 +00:00
|
|
|
out.write(frame, wave);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|