applied detune to the sampler and sin, added tests that need to be fixed

This commit is contained in:
Weird Constructor 2021-06-06 09:24:41 +02:00
parent 79c3e36eab
commit a9ac28e351
6 changed files with 147 additions and 12 deletions

View file

@ -254,8 +254,8 @@ macro_rules! d_pit { ($x: expr) => {
// 5.0 * 0.1 => 12.0
// 5.0 * 0.008333333 => 1.0
// 5.0 * 0.000083333 => 0.001
macro_rules! n_det { ($x: expr) => { ($x * 5.0 * 0.1) / 12.0 } }
macro_rules! d_det { ($x: expr) => { $x * 0.2 * 120.0 } }
macro_rules! n_det { ($x: expr) => { $x / 120.0 } }
macro_rules! d_det { ($x: expr) => { $x * 120.0 } }
// Rounding function that does nothing
macro_rules! r_id { ($x: expr) => { $x } }
@ -344,9 +344,10 @@ macro_rules! node_list {
(2 offs n_id n_id r_id f_def 0.0, 1.0, 0.0)
(3 len n_id n_id r_id f_def 0.0, 1.0, 1.0)
(4 dcms n_declick d_declick r_id f_def 0.0, 1.0, 3.14)
{5 0 sample audio_unloaded("") f_def 0 0}
{6 1 pmode setting(0) fa_sampl_pmode 0 1}
{7 2 dclick setting(0) fa_sampl_dclick 0 1}
(5 det n_det d_det r_id f_det -1.0, 1.0, 0.0)
{6 0 sample audio_unloaded("") f_def 0 0}
{7 1 pmode setting(0) fa_sampl_pmode 0 1}
{8 2 dclick setting(0) fa_sampl_dclick 0 1}
[0 sig],
sin => Sin UIType::Generic UICategory::Osc
(0 freq n_pit d_pit r_id f_freq -1.0, 1.0, 440.0)
@ -857,6 +858,15 @@ macro_rules! make_node_info_enum {
})+
}
#[allow(non_snake_case)]
pub mod denorm_offs {
$(pub mod $variant {
$(#[inline] pub fn $para(buf: &crate::dsp::ProcBuf, offs_val: f32, frame: usize) -> f32 {
$d_fun!(buf.read(frame) + offs_val)
})*
})+
}
#[allow(non_snake_case)]
pub mod inp_dir {
$(pub mod $variant {

View file

@ -4,7 +4,7 @@
use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals};
use crate::dsp::{out, at, inp, denorm}; //, inp, denorm, denorm_v, inp_dir, at};
use crate::dsp::{out, at, inp, denorm, denorm_offs}; //, inp, denorm, denorm_v, inp_dir, at};
use super::helpers::Trigger;
#[macro_export]
@ -64,6 +64,14 @@ impl Sampl {
"Sampl len\nLength of the sample, after the offset has been applied.\nRange: (0..1)\n";
pub const dcms : &'static str =
"Sampl dcms\nDeclick fade time in milliseconds.\nNot audio rate!\nRange: (0..1)\n";
pub const det : &'static str =
"Sin det\nDetune the oscillator in semitones and cents. \
the input of this value is rounded to semitones on coarse input. \
Fine input lets you detune in cents (rounded). \
A signal sent to this port is not rounded.\n\
Note: The signal input allows detuning over +- 10 octaves.\
\n\nKnob Range: (-0.2 .. 0.2)\n\
Signal Range: (-1.0 .. 1.0)\n";
pub const sample : &'static str =
"Sampl sample\nThe audio sample that is played back.\nRange: (-1..1)\n";
@ -128,6 +136,7 @@ impl Sampl {
let offs = inp::Sampl::offs(inputs);
let len = inp::Sampl::len(inputs);
let dcms = inp::Sampl::dcms(inputs);
let det = inp::Sampl::det(inputs);
let sample_srate = sample_data[0] as f64;
let sample_data = &sample_data[1..];
@ -161,8 +170,10 @@ impl Sampl {
let s =
if is_playing {
let playback_speed =
denorm::Sampl::freq(freq, frame) / 440.0;
let freq =
denorm_offs::Sampl::freq(
freq, det.read(frame), frame);
let playback_speed = freq / 440.0;
let prev_phase = self.phase;

View file

@ -3,7 +3,10 @@
// See README.md and COPYING for details.
use crate::nodes::{NodeAudioContext, NodeExecContext};
use crate::dsp::{NodeId, SAtom, ProcBuf, denorm, out, inp, DspNode, LedPhaseVals};
use crate::dsp::{
NodeId, SAtom, ProcBuf, denorm, denorm_offs,
out, inp, DspNode, LedPhaseVals
};
use crate::dsp::helpers::fast_sin;
@ -31,8 +34,9 @@ impl Sin {
"Sin det\nDetune the oscillator in semitones and cents. \
the input of this value is rounded to semitones on coarse input. \
Fine input lets you detune in cents (rounded). \
A signal sent to this port is not rounded.\
\n\nRange: (-1..1)\n";
A signal sent to this port is not rounded.\n\
Note: The signal input allows detune +-10 octaves.\
\nRange: (Knob -0.2 .. 0.2) / (Signal -1.0 .. 1.0)\n";
pub const sig : &'static str =
"Sin sig\nOscillator signal output.\n\nRange: (-1..1)\n";
}
@ -56,11 +60,12 @@ impl DspNode for Sin {
{
let o = out::Sin::sig(outputs);
let freq = inp::Sin::freq(inputs);
let det = inp::Sin::det(inputs);
let isr = 1.0 / self.srate;
let mut last_val = 0.0;
for frame in 0..ctx.nframes() {
let freq = denorm::Sin::freq(freq, frame);
let freq = denorm_offs::Sampl::freq(freq, det.read(frame), frame);
last_val = fast_sin(self.phase * TWOPI);
o.write(frame, last_val);

View file

@ -137,6 +137,59 @@ fn check_sine_pitch_change() {
assert_eq!(fft_res[0], (4393, 251));
}
#[test]
fn check_detune_parameter() {
let sin = NodeId::Sin(0);
let det_param = sin.inp_param("det").unwrap();
assert_float_eq!(det_param.norm(12.0), 0.1);
assert_float_eq!(det_param.norm(-12.0), -0.1);
assert_float_eq!(det_param.norm(24.0), 0.2);
assert_float_eq!(det_param.norm(-24.0), -0.2);
}
#[test]
fn check_sine_freq_detune() {
let (node_conf, mut node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
let sin = NodeId::Sin(0);
let out = NodeId::Out(0);
matrix.place(0, 0, Cell::empty(sin)
.out(None, sin.out("sig"), None));
matrix.place(1, 0, Cell::empty(out)
.input(None, out.inp("ch1"), None));
matrix.sync().unwrap();
let freq_param = sin.inp_param("freq").unwrap();
let det_param = sin.inp_param("det").unwrap();
run_no_input(&mut node_exec, 50.0);
let cfreq = run_and_get_counted_freq(&mut node_exec, 100.0);
assert_float_eq!(cfreq.floor(), 440.0);
matrix.set_param(freq_param, SAtom::param(freq_param.norm(4400.0)));
run_no_input(&mut node_exec, 50.0);
let cfreq = run_and_get_counted_freq(&mut node_exec, 1000.0);
assert_float_eq!(cfreq.floor(), 4400.0);
matrix.set_param(freq_param, SAtom::param(freq_param.norm(50.0)));
run_no_input(&mut node_exec, 50.0);
let cfreq = run_and_get_counted_freq(&mut node_exec, 100.0);
assert_float_eq!(cfreq.floor(), 50.0);
matrix.set_param(freq_param, SAtom::param(freq_param.norm(440.0)));
matrix.set_param(det_param, SAtom::param(det_param.norm(12.0)));
run_no_input(&mut node_exec, 50.0);
let cfreq = run_and_get_counted_freq(&mut node_exec, 1000.0);
assert_float_eq!(cfreq.floor(), 880.0);
matrix.set_param(det_param, SAtom::param(det_param.norm(1.0)));
run_no_input(&mut node_exec, 50.0);
let cfreq = run_and_get_counted_freq(&mut node_exec, 1000.0);
assert_float_eq!(cfreq.floor(), 493.0);
}
#[test]
fn check_matrix_monitor() {
let (node_conf, mut node_exec) = new_node_engine();

View file

@ -201,6 +201,40 @@ pub fn run_and_get_l_rms_mimax(
rms_mimax[1]
}
pub fn run_and_get_counted_freq(
node_exec: &mut hexodsp::nodes::NodeExecutor, ms: f32)
-> f64
{
let (out_l, _out_r) =
// +0.1 here for some extra samples
// this is just for tuning the frequency counter, so that it detects
// the last swing correctly. It's probably wrong, but the results
// match up better this way.
run_no_input(node_exec, (ms + 0.1) / 1000.0);
let mut zero_trans = 0;
let mut last_val = 0.0;
for s in out_l.iter() {
if last_val > 0.0 && *s < 0.0 {
zero_trans += 1;
} else if last_val < 0.0 && *s > 0.0 {
zero_trans += 1;
}
last_val = *s;
}
//d// println!("SAMPLES: {}", out_l.len());
//d// println!("ZERO TRANS: {}", zero_trans);
let trans_per_sample =
// substract the extra samples applied earlier.
(zero_trans as f64) / ((out_l.len() - 4) as f64);
trans_per_sample * 44100.0 * 0.5
}
pub fn run_and_get_fft4096(
node_exec: &mut hexodsp::nodes::NodeExecutor,
thres: u32,

View file

@ -53,6 +53,28 @@ fn check_node_sampl_1() {
assert_eq!(fft[0], (7127, 1029));
}
#[test]
fn check_node_sampl_detune() {
let (node_conf, mut node_exec) = new_node_engine();
let mut matrix = Matrix::new(node_conf, 3, 3);
let smpl = NodeId::Sampl(0);
let out = NodeId::Out(0);
matrix.place(0, 0, Cell::empty(smpl)
.out(None, None, smpl.out("sig")));
matrix.place(0, 1, Cell::empty(out)
.input(out.inp("ch1"), None, None));
matrix.sync().unwrap();
let sample_p = smpl.inp_param("sample").unwrap();
let freq_p = smpl.inp_param("freq").unwrap();
let det_p = smpl.inp_param("det").unwrap();
matrix.set_param(sample_p, SAtom::audio_unloaded("tests/sample_sin.wav"));
let cfreq = run_and_get_counted_freq(&mut node_exec, 1000.0);
assert_float_eq!(cfreq, 1.0);
}
#[test]
fn check_node_sampl_reload() {
{