From 172138bc19ed9ed78ca46ed09812d5db2fc8bfe2 Mon Sep 17 00:00:00 2001 From: Weird Constructor Date: Sat, 28 Aug 2021 19:56:08 +0200 Subject: [PATCH] Implemented the real quantizer node now. --- src/dsp/helpers.rs | 48 ++---------------------- src/dsp/mod.rs | 9 +++++ src/dsp/node_cqnt.rs | 2 +- src/dsp/node_quant.rs | 85 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 45 deletions(-) create mode 100644 src/dsp/node_quant.rs diff --git a/src/dsp/helpers.rs b/src/dsp/helpers.rs index 2f30be2..85d2b46 100644 --- a/src/dsp/helpers.rs +++ b/src/dsp/helpers.rs @@ -2158,36 +2158,6 @@ impl Quantizer { self.setup_lookup_table(); } -// mk_pitch_lookup_table = {!enabled = _; -// !any = $f; -// iter n enabled { if n { .any = $t } }; -// -// !tbl = $[]; -// -// iter i 0 => 24 { -// !minDistNote = 0; -// !minDist = 10000000000; -// -// iter note -12 => 25 { -// !dist = std:num:abs[ (i + 1) / 2 - note ]; -// -// !idx = eucMod note 12; -// if any &and not[enabled.(idx)] { -// next[]; -// }; -// std:displayln "DIST" (i + 1) / 2 note idx "=>" dist; -// if dist < minDist { -// .minDistNote = idx; -// .minDist = dist; -// } { break[] }; -// }; -// -// tbl.(i) = minDistNote; -// }; -// -// tbl -//}; -// #[inline] fn setup_lookup_table(&mut self) { let mask = self.old_mask; @@ -2210,10 +2180,10 @@ impl Quantizer { continue; } - println!("I={:3} NOTE={:3} (IDX={:3} => bitset {}) DIST={:3}", - i, note, note_idx, - if (mask & (0x1 << ((note_idx + 9) % 12))) > 0x0 { 1 } else { 0 }, - dist); + //d// println!("I={:3} NOTE={:3} (IDX={:3} => bitset {}) DIST={:3}", + //d// i, note, note_idx, + //d// if (mask & (0x1 << ((note_idx + 9) % 12))) > 0x0 { 1 } else { 0 }, + //d// dist); if dist < min_dist { min_d_note_idx = note; @@ -2232,16 +2202,6 @@ impl Quantizer { //d// println!("TBL: {:?}", self.lkup_tbl); } -//# float pitch = inputs[PITCH_INPUT].getVoltage(c); -//# int range = std::floor(pitch * 24); // 1.1 => 26 -//# int octave = eucDiv(range, 24); // 26 => 1 -//# range -= octave * 24; // 26 => 2 - -//# int note = ranges[range] + octave * 12; -//# playingNotes[eucMod(note, 12)] = true; -//# pitch = float(note) / 12; -//# outputs[PITCH_OUTPUT].setVoltage(pitch, c); - #[inline] pub fn process(&self, inp: f32) -> f32 { let note_num = (inp * 240.0).round() as i64; diff --git a/src/dsp/mod.rs b/src/dsp/mod.rs index ef6133a..d0e0a5f 100644 --- a/src/dsp/mod.rs +++ b/src/dsp/mod.rs @@ -50,6 +50,8 @@ mod node_rndwk; mod node_mux9; #[allow(non_upper_case_globals)] mod node_cqnt; +#[allow(non_upper_case_globals)] +mod node_quant; pub mod biquad; pub mod tracker; @@ -91,6 +93,7 @@ use crate::fa_mux9_in_cnt; use crate::fa_cqnt; use crate::fa_cqnt_omin; use crate::fa_cqnt_omax; +use crate::fa_quant; use node_amp::Amp; use node_sin::Sin; @@ -117,6 +120,7 @@ use node_pverb::PVerb; use node_rndwk::RndWk; use node_mux9::Mux9; use node_cqnt::CQnt; +use node_quant::Quant; pub const MIDI_MAX_FREQ : f32 = 13289.75; @@ -739,6 +743,11 @@ macro_rules! node_list { (6 max n_id d_id r_s f_def stp_d -1.0, 1.0, 1.0) {7 0 clip setting(0) fa_map_clip 0 1} [0 sig], + quant => Quant UIType::Generic UICategory::CV + (0 freq n_pit d_pit r_fq 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], 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) diff --git a/src/dsp/node_cqnt.rs b/src/dsp/node_cqnt.rs index ffedf04..b2b9e10 100644 --- a/src/dsp/node_cqnt.rs +++ b/src/dsp/node_cqnt.rs @@ -39,7 +39,7 @@ macro_rules! fa_cqnt_omax { ($formatter: expr, $v: expr, $denorm_v: expr) => { { write!($formatter, "{}", s) } } } -/// A 9 channel signal multiplexer +/// A control signal to pitch quantizer/converter #[derive(Debug, Clone)] pub struct CQnt { quant: Box, diff --git a/src/dsp/node_quant.rs b/src/dsp/node_quant.rs new file mode 100644 index 0000000..05120f7 --- /dev/null +++ b/src/dsp/node_quant.rs @@ -0,0 +1,85 @@ +// Copyright (c) 2021 Weird Constructor +// This file is a part of HexoDSP. Released under GPL-3.0-or-later. +// See README.md and COPYING for details. + +use crate::nodes::{NodeAudioContext, NodeExecContext}; +use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; +use crate::dsp::helpers::Quantizer; + +#[macro_export] +macro_rules! fa_quant { ($formatter: expr, $v: expr, $denorm_v: expr) => { { + write!($formatter, "?") +} } } + +/// A pitch quantizer +#[derive(Debug, Clone)] +pub struct Quant { + quant: Box, +} + +impl Quant { + pub fn new(_nid: &NodeId) -> Self { + Self { + quant: Box::new(Quantizer::new()), + } + } + pub const freq : &'static str = + "Quant freq\n\nRange: (0..1)"; + pub const oct : &'static str = + "Quant oct\n\nRange: (-1..1)"; + pub const sig : &'static str = + "Quant sig\n\nRange: (-1..1)"; + pub const keys : &'static str = + "Quant keys\n"; + pub const DESC : &'static str = +r#"Pitch Quantizer + +This is a simple quantizer, that snaps a pitch signal on 'freq' to the closest selected notes within their octave. +"#; + pub const HELP : &'static str = +r#"Quant - A pitch quantizer + +This is a simple quantizer, that snaps a pitch signal on 'freq' to the +closest selected notes within their octave. + +If you sweep along pitches you will notice that notes that are closer together +are travelled across faster. That means the notes are not evenly distributed +across the pitch input. If you want a more evenly distributed pitch selection +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) { } + + #[inline] + fn process( + &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + nctx: &NodeContext, + atoms: &[SAtom], inputs: &[ProcBuf], + outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) + { + use crate::dsp::{at, out, 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); + + self.quant.set_keys(keys.i()); + +// let mut last_key = 0; + + for frame in 0..ctx.nframes() { + let pitch = self.quant.process(freq.read(frame)); + out.write(frame, pitch + denorm::Quant::oct(oct, frame)); + } + +// let last_pitch = self.quant.last_key_pitch(); +// ctx_vals[1].set(last_pitch * 10.0 + 0.0001); +// ctx_vals[0].set((last_pitch * 10.0 - 0.5) * 2.0); + } +}