Added trigger outputs to the quantizers

This commit is contained in:
Weird Constructor 2021-08-30 03:55:42 +02:00
parent a496bb1b04
commit 8fa9ce35e9
4 changed files with 95 additions and 20 deletions

View file

@ -577,6 +577,44 @@ impl Default for TrigSignal {
fn default() -> Self { Self::new() }
}
#[derive(Debug, Clone, Copy)]
pub struct ChangeTrig {
ts: TrigSignal,
last: f32,
}
impl ChangeTrig {
pub fn new() -> Self {
Self {
ts: TrigSignal::new(),
last: -100.0, // some random value :-)
}
}
pub fn reset(&mut self) {
self.ts.reset();
self.last = -100.0;
}
pub fn set_sample_rate(&mut self, srate: f32) {
self.ts.set_sample_rate(srate);
}
#[inline]
pub fn next(&mut self, inp: f32) -> f32 {
if (inp - self.last).abs() > std::f32::EPSILON {
self.ts.trigger();
self.last = inp;
}
self.ts.next()
}
}
impl Default for ChangeTrig {
fn default() -> Self { Self::new() }
}
#[derive(Debug, Clone, Copy)]
pub struct Trigger {
triggered: bool,

View file

@ -747,14 +747,16 @@ macro_rules! node_list {
(0 freq n_pit d_pit r_id f_freq stp_d -1.0, 0.5647131, 440.0)
(1 oct n_id d_id r_s f_def stp_d -1.0, 1.0, 0.0)
{2 0 keys setting(0) fa_quant 0 0}
[0 sig],
[0 sig]
[1 t],
cqnt => CQnt UIType::Generic UICategory::CV
(0 inp n_id d_id r_id f_def stp_d 0.0, 1.0, 0.0)
(1 oct n_id d_id r_s f_def stp_d -1.0, 1.0, 0.0)
{2 0 keys setting(0) fa_cqnt 0 0}
{3 1 omin setting(0) fa_cqnt_omin 0 4}
{4 2 omax setting(0) fa_cqnt_omax 0 4}
[0 sig],
[0 sig]
[1 t],
tseq => TSeq UIType::Generic UICategory::Mod
(0 clock n_id d_id r_id f_def stp_d 0.0, 1.0, 0.0)
(1 trig n_id n_id r_id f_def stp_d -1.0, 1.0, 0.0)

View file

@ -4,7 +4,7 @@
use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext};
use crate::dsp::helpers::CtrlPitchQuantizer;
use crate::dsp::helpers::{CtrlPitchQuantizer, ChangeTrig};
#[macro_export]
macro_rules! fa_cqnt { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
@ -42,13 +42,15 @@ macro_rules! fa_cqnt_omax { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
/// A control signal to pitch quantizer/converter
#[derive(Debug, Clone)]
pub struct CQnt {
quant: Box<CtrlPitchQuantizer>,
quant: Box<CtrlPitchQuantizer>,
change_trig: ChangeTrig,
}
impl CQnt {
pub fn new(_nid: &NodeId) -> Self {
Self {
quant: Box::new(CtrlPitchQuantizer::new()),
quant: Box::new(CtrlPitchQuantizer::new()),
change_trig: ChangeTrig::new(),
}
}
pub const inp : &'static str =
@ -61,6 +63,10 @@ impl CQnt {
"CQnt omax\n\nRange: (-1..1)";
pub const sig : &'static str =
"CQnt sig\n\nRange: (-1..1)";
pub const t : &'static str =
"CQnt t\nEverytime the quantizer snaps to a new pitch, it will \
emit a short trigger on this signal output. This is useful \
to trigger for example an envelope.";
pub const keys : &'static str =
"CQnt keys\n";
pub const DESC : &'static str =
@ -80,8 +86,14 @@ like the 'Quant' node.
impl DspNode for CQnt {
fn outputs() -> usize { 1 }
fn set_sample_rate(&mut self, _srate: f32) { }
fn reset(&mut self) { }
fn set_sample_rate(&mut self, srate: f32) {
self.change_trig.set_sample_rate(srate);
}
fn reset(&mut self) {
self.change_trig.reset();
}
#[inline]
fn process<T: NodeAudioContext>(
@ -90,11 +102,12 @@ impl DspNode for CQnt {
atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{
use crate::dsp::{at, out, inp, denorm};
use crate::dsp::{at, out_buf, inp, denorm};
let inp = inp::CQnt::inp(inputs);
let oct = inp::CQnt::oct(inputs);
let out = out::CQnt::sig(outputs);
let mut out = out_buf::CQnt::sig(outputs);
let mut t = out_buf::CQnt::t(outputs);
let keys = at::CQnt::keys(atoms);
let omin = at::CQnt::omin(atoms);
let omax = at::CQnt::omax(atoms);
@ -107,6 +120,8 @@ impl DspNode for CQnt {
let pitch =
self.quant.signal_to_pitch(
denorm::CQnt::inp(inp, frame));
t.write(frame, self.change_trig.next(pitch));
out.write(frame, pitch + denorm::CQnt::oct(oct, frame));
}

View file

@ -4,7 +4,7 @@
use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext};
use crate::dsp::helpers::Quantizer;
use crate::dsp::helpers::{Quantizer, ChangeTrig};
#[macro_export]
macro_rules! fa_quant { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
@ -14,23 +14,35 @@ macro_rules! fa_quant { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
/// A pitch quantizer
#[derive(Debug, Clone)]
pub struct Quant {
quant: Box<Quantizer>,
quant: Box<Quantizer>,
change_trig: ChangeTrig,
}
impl Quant {
pub fn new(_nid: &NodeId) -> Self {
Self {
quant: Box::new(Quantizer::new()),
quant: Box::new(Quantizer::new()),
change_trig: ChangeTrig::new(),
}
}
pub const freq : &'static str =
"Quant freq\n\nRange: (0..1)";
"Quant freq\nAny signal that is to be pitch quantized.\nRange: (-1..1)";
pub const oct : &'static str =
"Quant oct\n\nRange: (-1..1)";
"Quant oct\nPitch offset, the knob is snapping to octave offsets. \
Feed signal values snapped to 0.1 multiples for exact octave offsets.\
\nRange: (-1..1)";
pub const sig : &'static str =
"Quant sig\n\nRange: (-1..1)";
"Quant sig\nThe quantized output signal that is rounded to \
the next selected note pitch within the octave of the \
original input to 'freq'.\nRange: (-1..1)";
pub const keys : &'static str =
"Quant keys\n";
"Quant keys\nSelect the notes you want to snap to here. \
If no notes are selected, the quantizer will snap the \
incoming signal to any closest note.";
pub const t : &'static str =
"Quant t\nEverytime the quantizer snaps to a new pitch, it will \
emit a short trigger on this signal output. This is useful \
to trigger for example an envelope.";
pub const DESC : &'static str =
r#"Pitch Quantizer
@ -52,8 +64,13 @@ please see also the 'CQnt' node.
impl DspNode for Quant {
fn outputs() -> usize { 1 }
fn set_sample_rate(&mut self, _srate: f32) { }
fn reset(&mut self) { }
fn set_sample_rate(&mut self, srate: f32) {
self.change_trig.set_sample_rate(srate);
}
fn reset(&mut self) {
self.change_trig.reset();
}
#[inline]
fn process<T: NodeAudioContext>(
@ -62,17 +79,20 @@ impl DspNode for Quant {
atoms: &[SAtom], inputs: &[ProcBuf],
outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals)
{
use crate::dsp::{at, out, inp, denorm};
use crate::dsp::{at, out_buf, inp, denorm};
let freq = inp::Quant::freq(inputs);
let oct = inp::Quant::oct(inputs);
let keys = at::Quant::keys(atoms);
let out = out::Quant::sig(outputs);
let mut out = out_buf::CQnt::sig(outputs);
let mut t = out_buf::CQnt::t(outputs);
self.quant.set_keys(keys.i());
for frame in 0..ctx.nframes() {
let pitch = self.quant.process(freq.read(frame));
t.write(frame, self.change_trig.next(pitch));
out.write(frame, pitch + denorm::Quant::oct(oct, frame));
}