From d24809112f53b54d0a1ee777fb7be2324969316d Mon Sep 17 00:00:00 2001 From: Weird Constructor Date: Sat, 28 Aug 2021 08:09:17 +0200 Subject: [PATCH] started implementing the right quantizer --- scripts/pitch_quantize_prototype.wl | 4 +- src/dsp/helpers.rs | 126 ++++++++++++++++++++++++++-- src/dsp/mod.rs | 2 + tests/quant.rs | 35 ++++++++ 4 files changed, 156 insertions(+), 11 deletions(-) create mode 100644 tests/quant.rs diff --git a/scripts/pitch_quantize_prototype.wl b/scripts/pitch_quantize_prototype.wl index c2f176e..47bee97 100644 --- a/scripts/pitch_quantize_prototype.wl +++ b/scripts/pitch_quantize_prototype.wl @@ -184,8 +184,8 @@ iter f 0 => n { }; !lkup = mk_pitch_lookup_table $[ - $t, $f, $f, $f, $f, $t, - $t, $f, $f, $f, $f, $t, + $f, $f, $f, $f, $f, $f, + $f, $f, $f, $t, $t, $t, ]; std:displayln ~ eucMod -1 12; diff --git a/src/dsp/helpers.rs b/src/dsp/helpers.rs index 36bda58..058c70e 100644 --- a/src/dsp/helpers.rs +++ b/src/dsp/helpers.rs @@ -2134,6 +2134,122 @@ impl TriSawLFO { } } +#[derive(Debug, Clone)] +pub struct Quantizer { + old_mask: i64, + keys: [f32; 12], + lkup_tbl: [u8; 24], +} + +impl Quantizer { + pub fn new() -> Self { + Self { + old_mask: 0xFFFF_FFFF, + keys: [0.0; 12], + lkup_tbl: [0; 24] + } + } + + #[inline] + pub fn set_keys(&mut self, keys_mask: i64) { + if keys_mask == self.old_mask { + return; + } + self.old_mask = keys_mask; + + for i in 0..12 { + self.keys[i] = + ((i as f32 / 12.0) * 0.1) - QUANT_TUNE_TO_A4; + } + + 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; + let any_enabled = mask > 0x0; + + for i in 0..24 { + let mut min_dist_note = 0; + let mut min_dist = 1000000000; + + for note in -12..=24 { + let dist = ((i + 1_i64) / 2 - note).abs(); + + let note_idx = note.rem_euclid(12); + if any_enabled && (mask & (0x1 << note_idx)) == 0x0 { + continue; + } + + if dist < min_dist { + min_dist_note = note_idx; + min_dist = dist; + } else { + break; + } + } + + self.lkup_tbl[i as usize] = min_dist_note as u8; + } + } + +//# 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).floor() as i64; + let octave = note_num.div_euclid(240); + let note_idx = note_num - octave * 240; + + println!("INP {:6.4} => octave={:2}, note_idx={:2}", inp, octave, note_idx); + println!("KEYS: {:?}", self.keys); + + let note_idx = self.lkup_tbl[note_idx as usize % 24]; // + octave * 12; + let pitch = self.keys[note_idx as usize]; + + pitch + } +} + #[derive(Debug, Clone)] pub struct CtrlPitchQuantizer { /// All keys, containing the min/max octave! @@ -2189,15 +2305,7 @@ impl CtrlPitchQuantizer { let mut mask_count = 0; - for i in 0..9 { - if mask & (0x1 << i) > 0 { - self.used_keys[mask_count] = ((i as f32 / 12.0) * 0.1) - QUANT_TUNE_TO_A4; - mask_count += 1; - } - } - - for i in 9..12 { - let key_pitch_idx = (i + 9 + 12) % 12; + for i in 0..12 { if mask & (0x1 << i) > 0 { self.used_keys[mask_count] = (i as f32 / 12.0) * 0.1 - QUANT_TUNE_TO_A4; mask_count += 1; diff --git a/src/dsp/mod.rs b/src/dsp/mod.rs index ce607a6..ef6133a 100644 --- a/src/dsp/mod.rs +++ b/src/dsp/mod.rs @@ -382,10 +382,12 @@ macro_rules! define_exp6 { } +#[macro_export] macro_rules! n_pit { ($x: expr) => { 0.1 * (($x as f32).max(0.01) / 440.0).log2() } } +#[macro_export] macro_rules! d_pit { ($x: expr) => { { let note : f32 = ($x as f32) * 10.0; diff --git a/tests/quant.rs b/tests/quant.rs new file mode 100644 index 0000000..7224580 --- /dev/null +++ b/tests/quant.rs @@ -0,0 +1,35 @@ +// 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. + +mod common; +use common::*; + +use hexodsp::dsp::helpers::Quantizer; +use hexodsp::d_pit; + +#[test] +fn check_quant_1() { + let mut q = Quantizer::new(); + q.set_keys(0x0); + + let v = + (0..=12).map(|i| + d_pit!(q.process(i as f32 * (0.1 / 12.0))) + ).collect::>(); + + assert_vec_feq!(v, vec![ + 440.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + ]); +}