diff --git a/src/dsp/mod.rs b/src/dsp/mod.rs index d0081ca..93da0c8 100644 --- a/src/dsp/mod.rs +++ b/src/dsp/mod.rs @@ -309,7 +309,13 @@ macro_rules! node_list { [2 trk3] [3 trk4] [4 trk5] - [5 trk6], + [5 trk6] + [6 gat1] + [7 gat2] + [8 gat3] + [9 gat4] + [10 gat5] + [11 gat6], sampl => Sampl UIType::Generic UICategory::Osc (0 freq n_pit d_pit r_id f_def -1.0, 1.0, 440.0) (1 trig n_id n_id r_id f_def -1.0, 1.0, 0.0) @@ -495,7 +501,7 @@ macro_rules! make_node_info_enum { } } - pub fn format(&self, f: &mut std::io::Write, v: f32) -> Option> { + pub fn format(&self, f: &mut dyn std::io::Write, v: f32) -> Option> { match self.node { NodeId::$v1 => None, $(NodeId::$variant(_) => { diff --git a/src/dsp/node_fbwr_fbrd.rs b/src/dsp/node_fbwr_fbrd.rs new file mode 100644 index 0000000..fd23cc0 --- /dev/null +++ b/src/dsp/node_fbwr_fbrd.rs @@ -0,0 +1,97 @@ +// Copyright (c) 2021 Weird Constructor +// This is a part of HexoDSP. Released under (A)GPLv3 or any later. +// See README.md and COPYING for details. + +use crate::nodes::{NodeAudioContext, NodeExecContext}; +use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals}; + +/// A simple amplifier +#[derive(Debug, Clone)] +pub struct FbWr { + fb_index: u8, +} + +impl FbWr { + pub fn new(nid: &NodeId) -> Self { + Self { + fb_index: nid.instance() as u8, + } + } + pub const inp : &'static str = + "FbWr inp\nSignal input\nRange: (-1..1)\n"; +} + +impl DspNode for FbWr { + 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, + atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], + outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) + { + use crate::dsp::{inp}; + + let inp = inp::FbWr::inp(inputs); + + for frame in 0..ctx.nframes() { + ectx.feedback_delay_buffers[self.fb_index as usize] + .write(inp.read(frame)); + } + + ctx_vals[0].set(inp.read(ctx.nframes() - 1)); + } +} + + +/// A simple amplifier +#[derive(Debug, Clone)] +pub struct FbRd { + fb_index: u8, +} + +impl FbRd { + pub fn new(nid: &NodeId) -> Self { + Self { + fb_index: nid.instance() as u8, + } + } + pub const atv : &'static str = + "FbRd atv\nAttenuate or invert input.\n\ + Use this to adjust the feedback amount.\nRange: (0..1)\n"; + pub const sig : &'static str = + "FbRd sig\nFeedback signal output.\nRange: (-1..1)\n"; +} + +impl DspNode for FbRd { + 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, + atoms: &[SAtom], _params: &[ProcBuf], inputs: &[ProcBuf], + outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) + { + use crate::dsp::{out, inp, denorm}; + + let atv = inp::FbRd::atv(inputs); + let sig = out::FbRd::sig(outputs); + + let mut last_val = 0.0; + for frame in 0..ctx.nframes() { + last_val = + ectx.feedback_delay_buffers[self.fb_index as usize] + .read(); + last_val *= denorm::FbRd::atv(atv, frame); + sig.write(frame, last_val); + } + + ctx_vals[0].set(last_val); + } +} diff --git a/src/dsp/node_tseq.rs b/src/dsp/node_tseq.rs index 9daa790..7291dcb 100644 --- a/src/dsp/node_tseq.rs +++ b/src/dsp/node_tseq.rs @@ -67,6 +67,19 @@ impl TSeq { "TSeq trk5\nTrack 5 signal output\nRange: (-1..1)\n"; pub const trk6 : &'static str = "TSeq trk6\nTrack 6 signal output\nRange: (-1..1)\n"; + + pub const gat1 : &'static str = + "TSeq gat1\nTrack 1 gate output\nRange: (-1..1)\n"; + pub const gat2 : &'static str = + "TSeq gat2\nTrack 2 gate output\nRange: (-1..1)\n"; + pub const gat3 : &'static str = + "TSeq gat3\nTrack 3 gate output\nRange: (-1..1)\n"; + pub const gat4 : &'static str = + "TSeq gat4\nTrack 4 gate output\nRange: (-1..1)\n"; + pub const gat5 : &'static str = + "TSeq gat5\nTrack 5 gate output\nRange: (-1..1)\n"; + pub const gat6 : &'static str = + "TSeq gat6\nTrack 6 gate output\nRange: (-1..1)\n"; } impl DspNode for TSeq { @@ -136,41 +149,62 @@ impl DspNode for TSeq { let mut col_out : [f32; MAX_BLOCK_SIZE] = [0.0; MAX_BLOCK_SIZE]; - let col_out_slice = &mut col_out[0..ctx.nframes()]; - let phase_out_slice = &phase_out[0..ctx.nframes()]; + let mut col_out_gate : [f32; MAX_BLOCK_SIZE] = + [0.0; MAX_BLOCK_SIZE]; + let col_out_slice = &mut col_out[ 0..ctx.nframes()]; + let col_out_gate_slice = &mut col_out_gate[0..ctx.nframes()]; + let phase_out_slice = &phase_out[ 0..ctx.nframes()]; - let out_t1 = out::TSeq::trk1(outputs); + let out_t1 = out::TSeq::trk1(outputs); backend.get_col_at_phase( - 0, phase_out_slice, col_out_slice); + 0, phase_out_slice, col_out_slice, col_out_gate_slice); out_t1.write_from(col_out_slice); + let out_g1 = out::TSeq::gat1(outputs); + out_g1.write_from(col_out_gate_slice); + ctx_vals[0].set(col_out_slice[col_out_slice.len() - 1]); - let out_t2 = out::TSeq::trk2(outputs); + let out_t2 = out::TSeq::trk2(outputs); backend.get_col_at_phase( - 1, phase_out_slice, col_out_slice); + 1, phase_out_slice, col_out_slice, col_out_gate_slice); out_t2.write_from(col_out_slice); - let out_t3 = out::TSeq::trk3(outputs); + let out_g2 = out::TSeq::gat2(outputs); + out_g2.write_from(col_out_gate_slice); + + let out_t3 = out::TSeq::trk3(outputs); backend.get_col_at_phase( - 2, phase_out_slice, col_out_slice); + 2, phase_out_slice, col_out_slice, col_out_gate_slice); out_t3.write_from(col_out_slice); - let out_t4 = out::TSeq::trk4(outputs); + let out_g3 = out::TSeq::gat3(outputs); + out_g3.write_from(col_out_gate_slice); + + let out_t4 = out::TSeq::trk4(outputs); backend.get_col_at_phase( - 3, phase_out_slice, col_out_slice); + 3, phase_out_slice, col_out_slice, col_out_gate_slice); out_t4.write_from(col_out_slice); - let out_t5 = out::TSeq::trk5(outputs); + let out_g4 = out::TSeq::gat4(outputs); + out_g4.write_from(col_out_gate_slice); + + let out_t5 = out::TSeq::trk5(outputs); backend.get_col_at_phase( - 4, phase_out_slice, col_out_slice); + 4, phase_out_slice, col_out_slice, col_out_gate_slice); out_t5.write_from(col_out_slice); - let out_t6 = out::TSeq::trk6(outputs); + let out_g5 = out::TSeq::gat5(outputs); + out_g5.write_from(col_out_gate_slice); + + let out_t6 = out::TSeq::trk6(outputs); backend.get_col_at_phase( - 5, phase_out_slice, col_out_slice); + 5, phase_out_slice, col_out_slice, col_out_gate_slice); out_t6.write_from(col_out_slice); + let out_g6 = out::TSeq::gat6(outputs); + out_g6.write_from(col_out_gate_slice); + ctx_vals[1].set(phase_out_slice[phase_out_slice.len() - 1]); } } diff --git a/src/dsp/tracker/mod.rs b/src/dsp/tracker/mod.rs index 07b130e..16828eb 100644 --- a/src/dsp/tracker/mod.rs +++ b/src/dsp/tracker/mod.rs @@ -31,7 +31,7 @@ pub enum PatternUpdateMsg { col: usize, col_type: PatternColType, pattern_len: usize, - data: [f32; MAX_PATTERN_LEN] + data: [(f32, u8); MAX_PATTERN_LEN] }, } @@ -143,17 +143,21 @@ impl TrackerBackend { pub fn pattern_len(&self) -> usize { self.seq.rows() } - pub fn get_col_at_phase(&mut self, col: usize, phase: &[f32], out: &mut [f32]) { + pub fn get_col_at_phase( + &mut self, col: usize, phase: &[f32], + out: &mut [f32], out_gate: &mut [f32]) + { if self.seq.rows() == 0 { return; } match self.col_types[col] { - PatternColType::Note | PatternColType::Step => { - self.seq.col_get_at_phase(col, phase, out) - }, - PatternColType::Value => self.seq.col_interpolate_at_phase(col, phase, out), - PatternColType::Gate => self.seq.col_gate_at_phase(col, phase, out), + PatternColType::Note | PatternColType::Step => + self.seq.col_get_at_phase( col, phase, out, out_gate), + PatternColType::Value => + self.seq.col_interpolate_at_phase(col, phase, out, out_gate), + PatternColType::Gate => + self.seq.col_gate_at_phase( col, phase, out, out_gate), } } } @@ -186,12 +190,18 @@ mod tests { while t.send_one_update() { } while backend.check_updates() { } - let mut out = [0.0; 16]; + let mut out = [0.0; 16]; + let mut out_gate = [0.0; 16]; + + backend.get_col_at_phase( + 0, &[0.2, 0.5, 0.99], &mut out[..], &mut out_gate[..]); - backend.get_col_at_phase(0, &[0.2, 0.5, 0.99], &mut out[..]); assert_float_eq!(out[0], 1.0); assert_float_eq!(out[1], 0.46666666); assert_float_eq!(out[2], 0.0); + assert_float_eq!(out_gate[0], 0.0); + assert_float_eq!(out_gate[1], 1.0); + assert_float_eq!(out_gate[2], 1.0); } #[test] @@ -208,12 +218,17 @@ mod tests { while t.send_one_update() { } while backend.check_updates() { } - let mut out = [0.0; 16]; + let mut out = [0.0; 16]; + let mut out_gate = [0.0; 16]; - backend.get_col_at_phase(0, &[0.2, 0.5, 0.999999], &mut out[..]); + backend.get_col_at_phase( + 0, &[0.2, 0.5, 0.999999], &mut out[..], &mut out_gate[..]); assert_float_eq!(out[0], 0.83238); assert_float_eq!(out[1], 0.46666666); assert_float_eq!(out[2], 0.0); + assert_float_eq!(out_gate[0], 0.0); + assert_float_eq!(out_gate[1], 0.0); + assert_float_eq!(out_gate[2], 1.0); } #[test] @@ -231,7 +246,8 @@ mod tests { while t.send_one_update() { } while backend.check_updates() { } - let mut out = [0.0; 64]; + let mut out = [0.0; 64]; + let mut out_gate = [0.0; 64]; let mut phase = [0.0; 64]; for (i, p) in phase.iter_mut().enumerate() { @@ -239,16 +255,23 @@ mod tests { } //d// println!("----"); - backend.get_col_at_phase(0, &phase[..], &mut out[..]); + backend.get_col_at_phase( + 0, &phase[..], &mut out[..], &mut out_gate[..]); //d// println!("out: {:?}", &out[16..32]); assert_eq!(out[0..8], [1.0; 8]); assert_eq!(out[8..16], [0.0; 8]); assert_eq!(out[16..32],[0.0; 16]); + assert_eq!(out_gate[0..8], [1.0; 8]); + assert_eq!(out_gate[8..16], [1.0; 8]); + assert_eq!(out_gate[16..32],[0.0; 16]); assert_float_eq!(out[32], 1.0); assert_eq!(out[33..48],[0.0; 15]); + assert_float_eq!(out_gate[32], 1.0); + assert_eq!(out_gate[33..48],[1.0; 15]); assert_eq!(out[48..64],[1.0; 16]); + assert_eq!(out_gate[48..64],[1.0; 16]); } } diff --git a/src/dsp/tracker/pattern.rs b/src/dsp/tracker/pattern.rs index 2463b84..b98c246 100644 --- a/src/dsp/tracker/pattern.rs +++ b/src/dsp/tracker/pattern.rs @@ -11,7 +11,7 @@ use crate::matrix_repr::PatternRepr; pub struct PatternData { col_types: [PatternColType; MAX_COLS], data: Vec>>, - out_data: Vec<[f32; MAX_PATTERN_LEN]>, + out_data: Vec<[(f32, u8); MAX_PATTERN_LEN]>, strings: Vec>>, cursor: (usize, usize), rows: usize, @@ -24,7 +24,7 @@ impl PatternData { Self { col_types: [PatternColType::Value; MAX_COLS], data: vec![vec![None; MAX_COLS]; MAX_PATTERN_LEN], - out_data: vec![[0.0; MAX_PATTERN_LEN]; MAX_COLS], + out_data: vec![[(0.0, 0); MAX_PATTERN_LEN]; MAX_COLS], strings: vec![vec![None; MAX_COLS]; MAX_PATTERN_LEN], cursor: (2, 2), edit_step: 4, @@ -106,7 +106,7 @@ impl PatternData { self.cursor = repr.cursor; } - pub fn get_out_data(&self) -> &[[f32; MAX_PATTERN_LEN]] { + pub fn get_out_data(&self) -> &[[(f32, u8); MAX_PATTERN_LEN]] { &self.out_data } @@ -160,8 +160,8 @@ impl PatternData { }; if let Some(end_value) = cur_value { - out_col[start_idx] = start_value; - out_col[end_idx] = end_value; + out_col[start_idx] = (start_value, 0); + out_col[end_idx] = (end_value, 1); let delta_rows = end_idx - start_idx; @@ -171,7 +171,7 @@ impl PatternData { (idx - start_idx) as f32 / (delta_rows as f32); out_col[idx] = - start_value * (1.0 - x) + end_value * x; + (start_value * (1.0 - x) + end_value * x, 0); } } @@ -189,23 +189,33 @@ impl PatternData { } }, PatternColType::Note => { - let mut cur_value = 0.0; + let mut cur_value = (0.0, 0); for row in 0..self.rows { if let Some(new_value) = self.data[row][col] { - cur_value = - ((new_value as i32 - 69) as f32 * 0.1) / 12.0; + cur_value = ( + ((new_value as i32 - 69) as f32 * 0.1) / 12.0, + 1 + ); + } else { + cur_value.1 = 0; } - out_col[row] = cur_value.clamp(-1.0, 1.0); + out_col[row] = + (cur_value.0.clamp(-1.0, 1.0), cur_value.1); } }, PatternColType::Step => { - let mut cur_value = 0.0; + let mut cur_value = (0.0, 0); for row in 0..self.rows { if let Some(new_value) = self.data[row][col] { - cur_value = ((new_value & 0xFFF) as f32) / (0xFFF as f32); + cur_value = ( + ((new_value & 0xFFF) as f32) / (0xFFF as f32), + 1 + ); + } else { + cur_value.1 = 0; } out_col[row] = cur_value; @@ -215,9 +225,9 @@ impl PatternData { for row in 0..self.rows { out_col[row] = if let Some(new_value) = self.data[row][col] { - f32::from_bits(new_value as u32) + (f32::from_bits(new_value as u32), 1) } else { - f32::from_bits(0xF000 as u32) + (f32::from_bits(0xF000 as u32), 0) }; } }, @@ -394,8 +404,8 @@ mod tests { let inc = 1.0 / 2.0; for i in 1..2 { let delta = - out_data[col][i] - - out_data[col][i - 1]; + out_data[col][i].0 + - out_data[col][i - 1].0; assert_float_eq!(delta, inc); } } @@ -416,8 +426,8 @@ mod tests { let inc = 1.0 / 3.0; for i in 1..3 { let delta = - out_data[col][i] - - out_data[col][i - 1]; + out_data[col][i].0 + - out_data[col][i - 1].0; assert_float_eq!(delta, inc); } } @@ -440,8 +450,8 @@ mod tests { //d// println!("out: {:?}", &out_data[col][0..16]); for i in 1..16 { let delta = - out_data[col][i] - - out_data[col][i - 1]; + out_data[col][i].0 + - out_data[col][i - 1].0; assert_float_eq!(delta, inc); } } @@ -462,8 +472,8 @@ mod tests { for i in 1..16 { let delta = - out_data[col][i] - - out_data[col][i - 1]; + out_data[col][i].0 + - out_data[col][i - 1].0; assert_float_eq!(delta.abs(), inc); } } @@ -484,8 +494,8 @@ mod tests { //d// println!("out: {:?}", &out_data[col][0..16]); for i in 0..8 { assert_float_eq!( - out_data[col][i], - out_data[col][15 - i]); + out_data[col][i].0, + out_data[col][15 - i].0); } } } @@ -505,8 +515,8 @@ mod tests { //d// println!("out: {:?}", &out_data[col][0..16]); for i in 0..8 { assert_float_eq!( - out_data[col][i], - out_data[col][15 - i]); + out_data[col][i].0, + out_data[col][15 - i].0); } } } @@ -528,8 +538,8 @@ mod tests { //d// println!("out: {:?}", &out_data[col][0..16]); for i in 0..8 { assert_float_eq!( - out_data[col][i], - out_data[col][15 - i]); + out_data[col][i].0, + out_data[col][15 - i].0); } } } @@ -550,13 +560,13 @@ mod tests { //d// println!("out: {:?}", &out_data[col][0..16]); - assert_float_eq!(0.5, out_data[col][6]); - assert_float_eq!(0.5, out_data[col][9]); + assert_float_eq!(0.5, out_data[col][6].0); + assert_float_eq!(0.5, out_data[col][9].0); for i in 0..8 { assert_float_eq!( - out_data[col][i], - out_data[col][15 - i]); + out_data[col][i].0, + out_data[col][15 - i].0); } } } @@ -575,14 +585,14 @@ mod tests { pats.sync_out_data(col); let out_data = pats.get_out_data(); - assert_float_eq!(out_data[col][0], 0.0); - assert_float_eq!(out_data[col][4], 0.26959708); - assert_float_eq!(out_data[col][5], 0.0); - assert_float_eq!(out_data[col][7], 0.4998779); - assert_float_eq!(out_data[col][8], 0.4998779); - assert_float_eq!(out_data[col][9], 0.50012213); - assert_float_eq!(out_data[col][10], 1.0); - assert_float_eq!(out_data[col][15], 1.0); + assert_float_eq!(out_data[col][0].0, 0.0); + assert_float_eq!(out_data[col][4].0, 0.26959708); + assert_float_eq!(out_data[col][5].0, 0.0); + assert_float_eq!(out_data[col][7].0, 0.4998779); + assert_float_eq!(out_data[col][8].0, 0.4998779); + assert_float_eq!(out_data[col][9].0, 0.50012213); + assert_float_eq!(out_data[col][10].0, 1.0); + assert_float_eq!(out_data[col][15].0, 1.0); } } @@ -599,13 +609,13 @@ mod tests { pats.sync_out_data(col); let out_data = pats.get_out_data(); - assert_float_eq!(out_data[col][0], 0.0); - assert_float_eq!(out_data[col][4], 0.0); - assert_float_eq!(out_data[col][5], -0.575); - assert_float_eq!(out_data[col][7], -0.1); - assert_float_eq!(out_data[col][9], -0.1); - assert_float_eq!(out_data[col][10], 0.1); - assert_float_eq!(out_data[col][15], 0.1); + assert_float_eq!(out_data[col][0].0, 0.0); + assert_float_eq!(out_data[col][4].0, 0.0); + assert_float_eq!(out_data[col][5].0, -0.575); + assert_float_eq!(out_data[col][7].0, -0.1); + assert_float_eq!(out_data[col][9].0, -0.1); + assert_float_eq!(out_data[col][10].0, 0.1); + assert_float_eq!(out_data[col][15].0, 0.1); } } diff --git a/src/dsp/tracker/sequencer.rs b/src/dsp/tracker/sequencer.rs index ed2548a..4e4065c 100644 --- a/src/dsp/tracker/sequencer.rs +++ b/src/dsp/tracker/sequencer.rs @@ -8,7 +8,7 @@ use crate::dsp::helpers::SplitMix64; pub struct PatternSequencer { rows: usize, - data: Vec>, + data: Vec>, rng: SplitMix64, rand_vals: [(usize, f64); MAX_COLS], } @@ -36,7 +36,7 @@ impl PatternSequencer { pub fn new_default_seed(rows: usize) -> Self { Self { rows, - data: vec![vec![0.0; MAX_PATTERN_LEN]; MAX_COLS], + data: vec![vec![(0.0, 0); MAX_PATTERN_LEN]; MAX_COLS], rng: SplitMix64::new(0x91234), rand_vals: [(99999, 0.0); MAX_COLS], } @@ -53,7 +53,7 @@ impl PatternSequencer { }; Self { rows, - data: vec![vec![0.0; MAX_PATTERN_LEN]; MAX_COLS], + data: vec![vec![(0.0, 0); MAX_PATTERN_LEN]; MAX_COLS], rng: SplitMix64::new_from_i64(seed), rand_vals: [(99999, 0.0); MAX_COLS], } @@ -65,7 +65,7 @@ impl PatternSequencer { pub fn rows(&self) -> usize { self.rows } - pub fn set_col(&mut self, col: usize, col_data: &[f32]) { + pub fn set_col(&mut self, col: usize, col_data: &[(f32, u8)]) { for (out_cell, in_cell) in self.data[col] .iter_mut() @@ -76,61 +76,78 @@ impl PatternSequencer { } pub fn col_interpolate_at_phase( - &self, col: usize, phase: &[f32], out: &mut [f32]) + &self, col: usize, phase: &[f32], out: &mut [f32], out_gate: &mut [f32]) { let col = &self.data[col][..]; let last_row_idx : f32 = (self.rows as f32) - 0.000001; let rows = self.rows; - for (phase, out) in phase.iter().zip(out.iter_mut()) { + for ((phase, out), out_gate) in + phase.iter() + .zip(out.iter_mut()) + .zip(out_gate.iter_mut()) + { let row_phase = phase * last_row_idx; let phase_frac = row_phase.fract(); let line = row_phase.floor() as usize % rows; let prev_line = if line == 0 { self.rows - 1 } else { line - 1 }; - let prev = col[prev_line]; - let next = col[line]; + let prev = col[prev_line].0; + let next = col[line].0; + let gate = col[line].1; // println!("INTERP: {}={:9.7}, {}={:9.7} | {:9.7}", // prev_line, prev, // line, next, // phase_frac); - *out = prev * (1.0 - phase_frac) + next * phase_frac; + *out = prev * (1.0 - phase_frac) + next * phase_frac; + *out_gate = gate as f32; } } pub fn col_get_at_phase( - &self, col: usize, phase: &[f32], out: &mut [f32]) + &self, col: usize, phase: &[f32], out: &mut [f32], out_gate: &mut [f32]) { let col = &self.data[col][..]; let last_row_idx : f32 = (self.rows as f32) - 0.000001; let rows = self.rows; - for (phase, out) in phase.iter().zip(out.iter_mut()) { + for ((phase, out), out_gate) in + phase.iter() + .zip(out.iter_mut()) + .zip(out_gate.iter_mut()) + { let row_phase = phase * last_row_idx; let line = row_phase.floor() as usize % rows; - *out = col[line]; + let (val, gate) = col[line]; + *out = val; + *out_gate = gate as f32; } } pub fn col_gate_at_phase( - &mut self, col_idx: usize, phase: &[f32], out: &mut [f32]) + &mut self, col_idx: usize, phase: &[f32], out: &mut [f32], out_gate: &mut [f32]) { let col = &self.data[col_idx][..]; let last_row_idx : f32 = (self.rows as f32) - 0.000001; let rows = self.rows; - for (phase, out) in phase.iter().zip(out.iter_mut()) { + for ((phase, out), out_gate) in + phase.iter() + .zip(out.iter_mut()) + .zip(out_gate.iter_mut()) + { let row_phase = phase.clamp(0.0, 1.0) * last_row_idx; let line = row_phase.floor() as usize % rows; let phase_frac = row_phase.fract(); - let gate : u32 = col[line].to_bits(); + let gate : u32 = col[line].0.to_bits(); + let ggate : u8 = col[line].1; // pulse_width: // 0xF - Gate is on for full row @@ -164,16 +181,21 @@ impl PatternSequencer { if rand_val > (FRACT_16THS[probability as usize] as f64) { *out = 0.0; + if (gate & 0xF000) > 0 { + *out_gate = 0.0; + } else { + *out_gate = ggate as f32; + } continue; } } - println!("GATE: {:0X}", gate); - if (gate & 0xF000) > 0 { - *out = 0.0; + *out = 0.0; + *out_gate = 0.0; } else { - *out = if sub_frac <= pulse_width { 1.0 } else { 0.0 }; + *out = if sub_frac <= pulse_width { 1.0 } else { 0.0 }; + *out_gate = ggate as f32; } } } @@ -196,74 +218,109 @@ mod tests { #[test] fn check_seq_interpolate_1() { let mut ps = PatternSequencer::new(2); - ps.set_col(0, &[0.0, 1.0]); + ps.set_col(0, &[(0.0, 0), (1.0, 1)]); - let mut out = [0.0; 6]; - ps.col_interpolate_at_phase(0, &[0.0, 0.1, 0.50, 0.51, 0.9, 0.99999], &mut out[..]); + let mut out = [0.0; 6]; + let mut out_gate = [0.0; 6]; + ps.col_interpolate_at_phase( + 0, &[0.0, 0.1, 0.50, 0.51, 0.9, 0.99999], + &mut out[..], &mut out_gate[..]); assert_float_eq!(out[0], 1.0); assert_float_eq!(out[1], 0.8); assert_float_eq!(out[2], 0.0); assert_float_eq!(out[3], 0.02); assert_float_eq!(out[4], 0.8); assert_float_eq!(out[5], 0.99999); + + assert_float_eq!(out_gate[0], 0.0); + assert_float_eq!(out_gate[1], 0.0); + assert_float_eq!(out_gate[2], 0.0); + assert_float_eq!(out_gate[3], 1.0); + assert_float_eq!(out_gate[4], 1.0); + assert_float_eq!(out_gate[5], 1.0); } #[test] fn check_seq_interpolate_buffer_end() { let mut ps = PatternSequencer::new(256); - ps.set_col(0, &[f32::from_bits(0xF000); 256]); + ps.set_col(0, &[(f32::from_bits(0xF000), 0); 256]); - let mut out = [0.0; 1]; - ps.col_gate_at_phase(0, &[0.9999999999], &mut out[..]); - assert_float_eq!(out[0], 0.0); + let mut out = [0.0; 1]; + let mut out_gate = [0.0; 1]; + ps.col_gate_at_phase( + 0, &[0.9999999999], &mut out[..], &mut out_gate[..]); + assert_float_eq!(out[0], 0.0); + assert_float_eq!(out_gate[0], 0.0); let mut ps = PatternSequencer::new(256); - ps.set_col(0, &[0.0; 256]); + ps.set_col(0, &[(0.0, 0); 256]); - ps.col_get_at_phase(0, &[0.9999999999], &mut out[..]); - assert_float_eq!(out[0], 0.0); + ps.col_get_at_phase( + 0, &[0.9999999999], &mut out[..], &mut out_gate[..]); + assert_float_eq!(out[0], 0.0); + assert_float_eq!(out_gate[0], 0.0); - ps.col_interpolate_at_phase(0, &[0.9999999999], &mut out[..]); - assert_float_eq!(out[0], 0.0); + ps.col_interpolate_at_phase( + 0, &[0.9999999999], &mut out[..], &mut out_gate[..]); + assert_float_eq!(out[0], 0.0); + assert_float_eq!(out_gate[0], 0.0); } #[test] fn check_seq_step_1() { let mut ps = PatternSequencer::new(2); - ps.set_col(0, &[0.0, 1.0]); + ps.set_col(0, &[(0.0, 0), (1.0, 1)]); - let mut out = [0.0; 3]; - ps.col_get_at_phase(0, &[0.1, 0.51, 0.9], &mut out[..]); + let mut out = [0.0; 3]; + let mut out_gate = [0.0; 3]; + ps.col_get_at_phase( + 0, &[0.1, 0.51, 0.9], &mut out[..], &mut out_gate[..]); assert_float_eq!(out[0], 0.0); assert_float_eq!(out[1], 1.0); assert_float_eq!(out[2], 1.0); + assert_float_eq!(out_gate[0], 0.0); + assert_float_eq!(out_gate[1], 1.0); + assert_float_eq!(out_gate[2], 1.0); } #[test] fn check_seq_step_2() { let mut ps = PatternSequencer::new(3); - ps.set_col(0, &[0.0, 0.3, 1.0]); + ps.set_col(0, &[(0.0, 0), (0.3, 1), (1.0, 1)]); - let mut out = [0.0; 6]; - ps.col_get_at_phase(0, &[0.1, 0.5, 0.51, 0.6, 0.9, 0.99], &mut out[..]); + let mut out = [0.0; 6]; + let mut out_gate = [0.0; 6]; + ps.col_get_at_phase( + 0, &[0.1, 0.5, 0.51, 0.6, 0.9, 0.99], + &mut out[..], &mut out_gate[..]); assert_float_eq!(out[0], 0.0); assert_float_eq!(out[1], 0.3); assert_float_eq!(out[2], 0.3); assert_float_eq!(out[3], 0.3); assert_float_eq!(out[4], 1.0); assert_float_eq!(out[5], 1.0); + + assert_float_eq!(out_gate[0], 0.0); + assert_float_eq!(out_gate[1], 1.0); + assert_float_eq!(out_gate[2], 1.0); + assert_float_eq!(out_gate[3], 1.0); + assert_float_eq!(out_gate[4], 1.0); + assert_float_eq!(out_gate[5], 1.0); } #[test] fn check_seq_gate_1() { let mut ps = PatternSequencer::new(2); ps.set_col(0, &[ - f32::from_bits(0x0FFF), - f32::from_bits(0xF000), + (f32::from_bits(0x0FFF), 1), + (f32::from_bits(0xF000), 0), ]); - let mut out = [0.0; 6]; - ps.col_gate_at_phase(0, &[0.1, 0.5, 0.5001, 0.6, 0.9, 0.99], &mut out[..]); + let mut out = [0.0; 6]; + let mut out_gate = [0.0; 6]; + ps.col_gate_at_phase( + 0, &[0.1, 0.5, 0.5001, 0.6, 0.9, 0.99], + &mut out[..], &mut out_gate[..]); //d// println!("out: {:?}", out); assert_float_eq!(out[0], 1.0); @@ -272,6 +329,13 @@ mod tests { assert_float_eq!(out[3], 0.0); assert_float_eq!(out[4], 0.0); assert_float_eq!(out[5], 0.0); + + assert_float_eq!(out_gate[0], 1.0); + assert_float_eq!(out_gate[1], 1.0); + assert_float_eq!(out_gate[2], 0.0); + assert_float_eq!(out_gate[3], 0.0); + assert_float_eq!(out_gate[4], 0.0); + assert_float_eq!(out_gate[5], 0.0); } fn count_high(slice: &[f32]) -> usize { @@ -298,9 +362,9 @@ mod tests { fn check_seq_gate_2() { let mut ps = PatternSequencer::new(3); ps.set_col(0, &[ - f32::from_bits(0x0FF0), - f32::from_bits(0x0FF7), - f32::from_bits(0x0FFF), + (f32::from_bits(0x0FF0), 1), + (f32::from_bits(0x0FF7), 0), + (f32::from_bits(0x0FFF), 1), ]); let mut phase = vec![0.0; 96]; @@ -313,26 +377,34 @@ mod tests { //d// println!("PHASE: {:?}", phase); - let mut out = [0.0; 96]; - ps.col_gate_at_phase(0, &phase[..], &mut out[..]); + let mut out = [0.0; 96]; + let mut out_gate = [0.0; 96]; + ps.col_gate_at_phase( + 0, &phase[..], &mut out[..], &mut out_gate[..]); //d// println!("out: {:?}", &out[0..32]); assert_eq!(count_high(&out[0..32]), 2); assert_eq!(count_high(&out[32..64]), 16); assert_eq!(count_high(&out[64..96]), 32); + assert_eq!(count_high(&out_gate[0..32]), 32); + assert_eq!(count_high(&out_gate[32..64]), 0); + assert_eq!(count_high(&out_gate[64..96]), 32); assert_eq!(count_up(&out[0..32]), 1); assert_eq!(count_up(&out[32..64]), 1); assert_eq!(count_up(&out[64..96]), 1); + assert_eq!(count_up(&out_gate[0..32]), 1); + assert_eq!(count_up(&out_gate[32..64]), 0); + assert_eq!(count_up(&out_gate[64..96]), 1); } #[test] fn check_seq_gate_div_1() { let mut ps = PatternSequencer::new(3); ps.set_col(0, &[ - f32::from_bits(0x0F80), - f32::from_bits(0x0F87), - f32::from_bits(0x0F8F), + (f32::from_bits(0x0F80), 1), + (f32::from_bits(0x0F87), 0), + (f32::from_bits(0x0F8F), 1), ]); let mut phase = vec![0.0; 3 * 64]; @@ -345,26 +417,34 @@ mod tests { //d// println!("PHASE: {:?}", phase); - let mut out = [0.0; 3 * 64]; - ps.col_gate_at_phase(0, &phase[..], &mut out[..]); + let mut out = [0.0; 3 * 64]; + let mut out_gate = [0.0; 3 * 64]; + ps.col_gate_at_phase( + 0, &phase[..], &mut out[..], &mut out_gate[..]); assert_eq!(count_high(&out[0..64]), 8); assert_eq!(count_up( &out[0..64]), 8); + assert_eq!(count_high(&out_gate[0..64]), 64); + assert_eq!(count_up( &out_gate[0..64]), 1); assert_eq!(count_high(&out[64..128]), 32); assert_eq!(count_up( &out[64..128]), 8); + assert_eq!(count_high(&out_gate[64..128]), 0); + assert_eq!(count_up( &out_gate[64..128]), 0); assert_eq!(count_high(&out[128..192]), 64); assert_eq!(count_up( &out[128..192]), 1); + assert_eq!(count_high(&out_gate[128..192]), 64); + assert_eq!(count_up( &out_gate[128..192]), 1); } #[test] fn check_seq_gate_div_2() { let mut ps = PatternSequencer::new(3); ps.set_col(0, &[ - f32::from_bits(0x0F00), - f32::from_bits(0x0F07), - f32::from_bits(0x0F0F), + (f32::from_bits(0x0F00), 1), + (f32::from_bits(0x0F07), 0), + (f32::from_bits(0x0F0F), 1), ]); let mut phase = vec![0.0; 6 * 64]; @@ -377,26 +457,33 @@ mod tests { //d// println!("PHASE: {:?}", phase); - let mut out = [0.0; 6 * 64]; - ps.col_gate_at_phase(0, &phase[..], &mut out[..]); + let mut out = [0.0; 6 * 64]; + let mut out_gate = [0.0; 6 * 64]; + ps.col_gate_at_phase(0, &phase[..], &mut out[..], &mut out_gate[..]); assert_eq!(count_high(&out[0..128]), 16); assert_eq!(count_up( &out[0..128]), 16); + assert_eq!(count_high(&out_gate[0..128]), 128); + assert_eq!(count_up( &out_gate[0..128]), 1); assert_eq!(count_high(&out[128..256]), 64); assert_eq!(count_up( &out[128..256]), 16); + assert_eq!(count_high(&out_gate[128..256]), 0); + assert_eq!(count_up( &out_gate[128..256]), 0); assert_eq!(count_high(&out[256..384]), 128); assert_eq!(count_up( &out[256..384]), 1); + assert_eq!(count_high(&out_gate[256..384]), 128); + assert_eq!(count_up( &out_gate[256..384]), 1); } #[test] fn check_seq_gate_div_3() { let mut ps = PatternSequencer::new(3); ps.set_col(0, &[ - f32::from_bits(0x0FE0), - f32::from_bits(0x0FE7), - f32::from_bits(0x0FEF), + (f32::from_bits(0x0FE0), 1), + (f32::from_bits(0x0FE7), 0), + (f32::from_bits(0x0FEF), 1), ]); let mut phase = vec![0.0; 6 * 64]; @@ -409,26 +496,33 @@ mod tests { //d// println!("PHASE: {:?}", phase); - let mut out = [0.0; 6 * 64]; - ps.col_gate_at_phase(0, &phase[..], &mut out[..]); + let mut out = [0.0; 6 * 64]; + let mut out_gate = [0.0; 6 * 64]; + ps.col_gate_at_phase(0, &phase[..], &mut out[..], &mut out_gate[..]); assert_eq!(count_high(&out[0..128]), 8); assert_eq!(count_up( &out[0..128]), 2); + assert_eq!(count_high(&out_gate[0..128]), 128); + assert_eq!(count_up( &out_gate[0..128]), 1); assert_eq!(count_high(&out[128..256]), 64); assert_eq!(count_up( &out[128..256]), 2); + assert_eq!(count_high(&out_gate[128..256]), 0); + assert_eq!(count_up( &out_gate[128..256]), 0); assert_eq!(count_high(&out[256..384]), 128); assert_eq!(count_up( &out[256..384]), 1); + assert_eq!(count_high(&out_gate[256..384]), 128); + assert_eq!(count_up( &out_gate[256..384]), 1); } fn run_probability_test_for(prob: u32) -> (usize, usize) { let rows = 100; let mut ps = PatternSequencer::new_default_seed(rows); - let mut coldata = vec![0.0; rows]; + let mut coldata = vec![(0.0, 0); rows]; for i in 0..coldata.len() { - coldata[i] = f32::from_bits(0x00FF | prob); + coldata[i] = (f32::from_bits(0x00FF | prob), 1); } ps.set_col(0, &coldata[..]); @@ -441,8 +535,9 @@ mod tests { phase_run += inc; } - let mut out = vec![0.0; samples]; - ps.col_gate_at_phase(0, &phase[..], &mut out[..]); + let mut out = vec![0.0; samples]; + let mut out_gate = vec![0.0; samples]; + ps.col_gate_at_phase(0, &phase[..], &mut out[..], &mut out_gate[..]); (count_high(&out[..]), count_up(&out[..])) }