Added trigger outputs to the quantizers
This commit is contained in:
parent
a496bb1b04
commit
8fa9ce35e9
4 changed files with 95 additions and 20 deletions
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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) => { {
|
||||
|
@ -43,12 +43,14 @@ macro_rules! fa_cqnt_omax { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct CQnt {
|
||||
quant: Box<CtrlPitchQuantizer>,
|
||||
change_trig: ChangeTrig,
|
||||
}
|
||||
|
||||
impl CQnt {
|
||||
pub fn new(_nid: &NodeId) -> Self {
|
||||
Self {
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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) => { {
|
||||
|
@ -15,22 +15,34 @@ macro_rules! fa_quant { ($formatter: expr, $v: expr, $denorm_v: expr) => { {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct Quant {
|
||||
quant: Box<Quantizer>,
|
||||
change_trig: ChangeTrig,
|
||||
}
|
||||
|
||||
impl Quant {
|
||||
pub fn new(_nid: &NodeId) -> Self {
|
||||
Self {
|
||||
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));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue