added missing file and implemented gate output ports to the sequencer

This commit is contained in:
Weird Constructor 2021-06-04 20:24:55 +02:00
parent d069c4aafa
commit 1b22ab623a
6 changed files with 406 additions and 141 deletions

View file

@ -309,7 +309,13 @@ macro_rules! node_list {
[2 trk3] [2 trk3]
[3 trk4] [3 trk4]
[4 trk5] [4 trk5]
[5 trk6], [5 trk6]
[6 gat1]
[7 gat2]
[8 gat3]
[9 gat4]
[10 gat5]
[11 gat6],
sampl => Sampl UIType::Generic UICategory::Osc sampl => Sampl UIType::Generic UICategory::Osc
(0 freq n_pit d_pit r_id f_def -1.0, 1.0, 440.0) (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) (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<std::io::Result<()>> { pub fn format(&self, f: &mut dyn std::io::Write, v: f32) -> Option<std::io::Result<()>> {
match self.node { match self.node {
NodeId::$v1 => None, NodeId::$v1 => None,
$(NodeId::$variant(_) => { $(NodeId::$variant(_) => {

97
src/dsp/node_fbwr_fbrd.rs Normal file
View file

@ -0,0 +1,97 @@
// Copyright (c) 2021 Weird Constructor <weirdconstructor@gmail.com>
// 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<T: NodeAudioContext>(
&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<T: NodeAudioContext>(
&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);
}
}

View file

@ -67,6 +67,19 @@ impl TSeq {
"TSeq trk5\nTrack 5 signal output\nRange: (-1..1)\n"; "TSeq trk5\nTrack 5 signal output\nRange: (-1..1)\n";
pub const trk6 : &'static str = pub const trk6 : &'static str =
"TSeq trk6\nTrack 6 signal output\nRange: (-1..1)\n"; "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 { impl DspNode for TSeq {
@ -136,41 +149,62 @@ impl DspNode for TSeq {
let mut col_out : [f32; MAX_BLOCK_SIZE] = let mut col_out : [f32; MAX_BLOCK_SIZE] =
[0.0; MAX_BLOCK_SIZE]; [0.0; MAX_BLOCK_SIZE];
let col_out_slice = &mut col_out[0..ctx.nframes()]; let mut col_out_gate : [f32; MAX_BLOCK_SIZE] =
let phase_out_slice = &phase_out[0..ctx.nframes()]; [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( 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); 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]); 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( 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); 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( 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); 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( 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); 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( 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); 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( 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); 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]); ctx_vals[1].set(phase_out_slice[phase_out_slice.len() - 1]);
} }
} }

View file

@ -31,7 +31,7 @@ pub enum PatternUpdateMsg {
col: usize, col: usize,
col_type: PatternColType, col_type: PatternColType,
pattern_len: usize, 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 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 { if self.seq.rows() == 0 {
return; return;
} }
match self.col_types[col] { match self.col_types[col] {
PatternColType::Note | PatternColType::Step => { PatternColType::Note | PatternColType::Step =>
self.seq.col_get_at_phase(col, phase, out) self.seq.col_get_at_phase( col, phase, out, out_gate),
}, PatternColType::Value =>
PatternColType::Value => self.seq.col_interpolate_at_phase(col, phase, out), self.seq.col_interpolate_at_phase(col, phase, out, out_gate),
PatternColType::Gate => self.seq.col_gate_at_phase(col, phase, out), 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 t.send_one_update() { }
while backend.check_updates() { } 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[0], 1.0);
assert_float_eq!(out[1], 0.46666666); assert_float_eq!(out[1], 0.46666666);
assert_float_eq!(out[2], 0.0); 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] #[test]
@ -208,12 +218,17 @@ mod tests {
while t.send_one_update() { } while t.send_one_update() { }
while backend.check_updates() { } 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[0], 0.83238);
assert_float_eq!(out[1], 0.46666666); assert_float_eq!(out[1], 0.46666666);
assert_float_eq!(out[2], 0.0); 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] #[test]
@ -231,7 +246,8 @@ mod tests {
while t.send_one_update() { } while t.send_one_update() { }
while backend.check_updates() { } 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]; let mut phase = [0.0; 64];
for (i, p) in phase.iter_mut().enumerate() { for (i, p) in phase.iter_mut().enumerate() {
@ -239,16 +255,23 @@ mod tests {
} }
//d// println!("----"); //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]); //d// println!("out: {:?}", &out[16..32]);
assert_eq!(out[0..8], [1.0; 8]); assert_eq!(out[0..8], [1.0; 8]);
assert_eq!(out[8..16], [0.0; 8]); assert_eq!(out[8..16], [0.0; 8]);
assert_eq!(out[16..32],[0.0; 16]); 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_float_eq!(out[32], 1.0);
assert_eq!(out[33..48],[0.0; 15]); 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[48..64],[1.0; 16]);
assert_eq!(out_gate[48..64],[1.0; 16]);
} }
} }

View file

@ -11,7 +11,7 @@ use crate::matrix_repr::PatternRepr;
pub struct PatternData { pub struct PatternData {
col_types: [PatternColType; MAX_COLS], col_types: [PatternColType; MAX_COLS],
data: Vec<Vec<Option<u16>>>, data: Vec<Vec<Option<u16>>>,
out_data: Vec<[f32; MAX_PATTERN_LEN]>, out_data: Vec<[(f32, u8); MAX_PATTERN_LEN]>,
strings: Vec<Vec<Option<String>>>, strings: Vec<Vec<Option<String>>>,
cursor: (usize, usize), cursor: (usize, usize),
rows: usize, rows: usize,
@ -24,7 +24,7 @@ impl PatternData {
Self { Self {
col_types: [PatternColType::Value; MAX_COLS], col_types: [PatternColType::Value; MAX_COLS],
data: vec![vec![None; MAX_COLS]; MAX_PATTERN_LEN], 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], strings: vec![vec![None; MAX_COLS]; MAX_PATTERN_LEN],
cursor: (2, 2), cursor: (2, 2),
edit_step: 4, edit_step: 4,
@ -106,7 +106,7 @@ impl PatternData {
self.cursor = repr.cursor; 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 &self.out_data
} }
@ -160,8 +160,8 @@ impl PatternData {
}; };
if let Some(end_value) = cur_value { if let Some(end_value) = cur_value {
out_col[start_idx] = start_value; out_col[start_idx] = (start_value, 0);
out_col[end_idx] = end_value; out_col[end_idx] = (end_value, 1);
let delta_rows = end_idx - start_idx; let delta_rows = end_idx - start_idx;
@ -171,7 +171,7 @@ impl PatternData {
(idx - start_idx) as f32 (idx - start_idx) as f32
/ (delta_rows as f32); / (delta_rows as f32);
out_col[idx] = 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 => { PatternColType::Note => {
let mut cur_value = 0.0; let mut cur_value = (0.0, 0);
for row in 0..self.rows { for row in 0..self.rows {
if let Some(new_value) = self.data[row][col] { if let Some(new_value) = self.data[row][col] {
cur_value = cur_value = (
((new_value as i32 - 69) as f32 * 0.1) / 12.0; ((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 => { PatternColType::Step => {
let mut cur_value = 0.0; let mut cur_value = (0.0, 0);
for row in 0..self.rows { for row in 0..self.rows {
if let Some(new_value) = self.data[row][col] { 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; out_col[row] = cur_value;
@ -215,9 +225,9 @@ impl PatternData {
for row in 0..self.rows { for row in 0..self.rows {
out_col[row] = out_col[row] =
if let Some(new_value) = self.data[row][col] { 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 { } 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; let inc = 1.0 / 2.0;
for i in 1..2 { for i in 1..2 {
let delta = let delta =
out_data[col][i] out_data[col][i].0
- out_data[col][i - 1]; - out_data[col][i - 1].0;
assert_float_eq!(delta, inc); assert_float_eq!(delta, inc);
} }
} }
@ -416,8 +426,8 @@ mod tests {
let inc = 1.0 / 3.0; let inc = 1.0 / 3.0;
for i in 1..3 { for i in 1..3 {
let delta = let delta =
out_data[col][i] out_data[col][i].0
- out_data[col][i - 1]; - out_data[col][i - 1].0;
assert_float_eq!(delta, inc); assert_float_eq!(delta, inc);
} }
} }
@ -440,8 +450,8 @@ mod tests {
//d// println!("out: {:?}", &out_data[col][0..16]); //d// println!("out: {:?}", &out_data[col][0..16]);
for i in 1..16 { for i in 1..16 {
let delta = let delta =
out_data[col][i] out_data[col][i].0
- out_data[col][i - 1]; - out_data[col][i - 1].0;
assert_float_eq!(delta, inc); assert_float_eq!(delta, inc);
} }
} }
@ -462,8 +472,8 @@ mod tests {
for i in 1..16 { for i in 1..16 {
let delta = let delta =
out_data[col][i] out_data[col][i].0
- out_data[col][i - 1]; - out_data[col][i - 1].0;
assert_float_eq!(delta.abs(), inc); assert_float_eq!(delta.abs(), inc);
} }
} }
@ -484,8 +494,8 @@ mod tests {
//d// println!("out: {:?}", &out_data[col][0..16]); //d// println!("out: {:?}", &out_data[col][0..16]);
for i in 0..8 { for i in 0..8 {
assert_float_eq!( assert_float_eq!(
out_data[col][i], out_data[col][i].0,
out_data[col][15 - i]); out_data[col][15 - i].0);
} }
} }
} }
@ -505,8 +515,8 @@ mod tests {
//d// println!("out: {:?}", &out_data[col][0..16]); //d// println!("out: {:?}", &out_data[col][0..16]);
for i in 0..8 { for i in 0..8 {
assert_float_eq!( assert_float_eq!(
out_data[col][i], out_data[col][i].0,
out_data[col][15 - i]); out_data[col][15 - i].0);
} }
} }
} }
@ -528,8 +538,8 @@ mod tests {
//d// println!("out: {:?}", &out_data[col][0..16]); //d// println!("out: {:?}", &out_data[col][0..16]);
for i in 0..8 { for i in 0..8 {
assert_float_eq!( assert_float_eq!(
out_data[col][i], out_data[col][i].0,
out_data[col][15 - i]); out_data[col][15 - i].0);
} }
} }
} }
@ -550,13 +560,13 @@ mod tests {
//d// println!("out: {:?}", &out_data[col][0..16]); //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][6].0);
assert_float_eq!(0.5, out_data[col][9]); assert_float_eq!(0.5, out_data[col][9].0);
for i in 0..8 { for i in 0..8 {
assert_float_eq!( assert_float_eq!(
out_data[col][i], out_data[col][i].0,
out_data[col][15 - i]); out_data[col][15 - i].0);
} }
} }
} }
@ -575,14 +585,14 @@ mod tests {
pats.sync_out_data(col); pats.sync_out_data(col);
let out_data = pats.get_out_data(); let out_data = pats.get_out_data();
assert_float_eq!(out_data[col][0], 0.0); assert_float_eq!(out_data[col][0].0, 0.0);
assert_float_eq!(out_data[col][4], 0.26959708); assert_float_eq!(out_data[col][4].0, 0.26959708);
assert_float_eq!(out_data[col][5], 0.0); assert_float_eq!(out_data[col][5].0, 0.0);
assert_float_eq!(out_data[col][7], 0.4998779); assert_float_eq!(out_data[col][7].0, 0.4998779);
assert_float_eq!(out_data[col][8], 0.4998779); assert_float_eq!(out_data[col][8].0, 0.4998779);
assert_float_eq!(out_data[col][9], 0.50012213); assert_float_eq!(out_data[col][9].0, 0.50012213);
assert_float_eq!(out_data[col][10], 1.0); assert_float_eq!(out_data[col][10].0, 1.0);
assert_float_eq!(out_data[col][15], 1.0); assert_float_eq!(out_data[col][15].0, 1.0);
} }
} }
@ -599,13 +609,13 @@ mod tests {
pats.sync_out_data(col); pats.sync_out_data(col);
let out_data = pats.get_out_data(); let out_data = pats.get_out_data();
assert_float_eq!(out_data[col][0], 0.0); assert_float_eq!(out_data[col][0].0, 0.0);
assert_float_eq!(out_data[col][4], 0.0); assert_float_eq!(out_data[col][4].0, 0.0);
assert_float_eq!(out_data[col][5], -0.575); assert_float_eq!(out_data[col][5].0, -0.575);
assert_float_eq!(out_data[col][7], -0.1); assert_float_eq!(out_data[col][7].0, -0.1);
assert_float_eq!(out_data[col][9], -0.1); assert_float_eq!(out_data[col][9].0, -0.1);
assert_float_eq!(out_data[col][10], 0.1); assert_float_eq!(out_data[col][10].0, 0.1);
assert_float_eq!(out_data[col][15], 0.1); assert_float_eq!(out_data[col][15].0, 0.1);
} }
} }

View file

@ -8,7 +8,7 @@ use crate::dsp::helpers::SplitMix64;
pub struct PatternSequencer { pub struct PatternSequencer {
rows: usize, rows: usize,
data: Vec<Vec<f32>>, data: Vec<Vec<(f32, u8)>>,
rng: SplitMix64, rng: SplitMix64,
rand_vals: [(usize, f64); MAX_COLS], rand_vals: [(usize, f64); MAX_COLS],
} }
@ -36,7 +36,7 @@ impl PatternSequencer {
pub fn new_default_seed(rows: usize) -> Self { pub fn new_default_seed(rows: usize) -> Self {
Self { Self {
rows, 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), rng: SplitMix64::new(0x91234),
rand_vals: [(99999, 0.0); MAX_COLS], rand_vals: [(99999, 0.0); MAX_COLS],
} }
@ -53,7 +53,7 @@ impl PatternSequencer {
}; };
Self { Self {
rows, 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), rng: SplitMix64::new_from_i64(seed),
rand_vals: [(99999, 0.0); MAX_COLS], rand_vals: [(99999, 0.0); MAX_COLS],
} }
@ -65,7 +65,7 @@ impl PatternSequencer {
pub fn rows(&self) -> usize { self.rows } 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 for (out_cell, in_cell) in
self.data[col] self.data[col]
.iter_mut() .iter_mut()
@ -76,61 +76,78 @@ impl PatternSequencer {
} }
pub fn col_interpolate_at_phase( 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 col = &self.data[col][..];
let last_row_idx : f32 = (self.rows as f32) - 0.000001; let last_row_idx : f32 = (self.rows as f32) - 0.000001;
let rows = self.rows; 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 row_phase = phase * last_row_idx;
let phase_frac = row_phase.fract(); let phase_frac = row_phase.fract();
let line = row_phase.floor() as usize % rows; let line = row_phase.floor() as usize % rows;
let prev_line = if line == 0 { self.rows - 1 } else { line - 1 }; let prev_line = if line == 0 { self.rows - 1 } else { line - 1 };
let prev = col[prev_line]; let prev = col[prev_line].0;
let next = col[line]; let next = col[line].0;
let gate = col[line].1;
// println!("INTERP: {}={:9.7}, {}={:9.7} | {:9.7}", // println!("INTERP: {}={:9.7}, {}={:9.7} | {:9.7}",
// prev_line, prev, // prev_line, prev,
// line, next, // line, next,
// phase_frac); // 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( 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 col = &self.data[col][..];
let last_row_idx : f32 = (self.rows as f32) - 0.000001; let last_row_idx : f32 = (self.rows as f32) - 0.000001;
let rows = self.rows; 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 row_phase = phase * last_row_idx;
let line = row_phase.floor() as usize % rows; 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( 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 col = &self.data[col_idx][..];
let last_row_idx : f32 = (self.rows as f32) - 0.000001; let last_row_idx : f32 = (self.rows as f32) - 0.000001;
let rows = self.rows; 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 row_phase = phase.clamp(0.0, 1.0) * last_row_idx;
let line = row_phase.floor() as usize % rows; let line = row_phase.floor() as usize % rows;
let phase_frac = row_phase.fract(); 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: // pulse_width:
// 0xF - Gate is on for full row // 0xF - Gate is on for full row
@ -164,16 +181,21 @@ impl PatternSequencer {
if rand_val > (FRACT_16THS[probability as usize] as f64) { if rand_val > (FRACT_16THS[probability as usize] as f64) {
*out = 0.0; *out = 0.0;
if (gate & 0xF000) > 0 {
*out_gate = 0.0;
} else {
*out_gate = ggate as f32;
}
continue; continue;
} }
} }
println!("GATE: {:0X}", gate);
if (gate & 0xF000) > 0 { if (gate & 0xF000) > 0 {
*out = 0.0; *out = 0.0;
*out_gate = 0.0;
} else { } 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] #[test]
fn check_seq_interpolate_1() { fn check_seq_interpolate_1() {
let mut ps = PatternSequencer::new(2); 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]; 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_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[0], 1.0);
assert_float_eq!(out[1], 0.8); assert_float_eq!(out[1], 0.8);
assert_float_eq!(out[2], 0.0); assert_float_eq!(out[2], 0.0);
assert_float_eq!(out[3], 0.02); assert_float_eq!(out[3], 0.02);
assert_float_eq!(out[4], 0.8); assert_float_eq!(out[4], 0.8);
assert_float_eq!(out[5], 0.99999); 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] #[test]
fn check_seq_interpolate_buffer_end() { fn check_seq_interpolate_buffer_end() {
let mut ps = PatternSequencer::new(256); 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]; let mut out = [0.0; 1];
ps.col_gate_at_phase(0, &[0.9999999999], &mut out[..]); let mut out_gate = [0.0; 1];
assert_float_eq!(out[0], 0.0); 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); 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[..]); ps.col_get_at_phase(
assert_float_eq!(out[0], 0.0); 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[..]); ps.col_interpolate_at_phase(
assert_float_eq!(out[0], 0.0); 0, &[0.9999999999], &mut out[..], &mut out_gate[..]);
assert_float_eq!(out[0], 0.0);
assert_float_eq!(out_gate[0], 0.0);
} }
#[test] #[test]
fn check_seq_step_1() { fn check_seq_step_1() {
let mut ps = PatternSequencer::new(2); 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]; let mut out = [0.0; 3];
ps.col_get_at_phase(0, &[0.1, 0.51, 0.9], &mut out[..]); 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[0], 0.0);
assert_float_eq!(out[1], 1.0); assert_float_eq!(out[1], 1.0);
assert_float_eq!(out[2], 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] #[test]
fn check_seq_step_2() { fn check_seq_step_2() {
let mut ps = PatternSequencer::new(3); 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]; 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_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[0], 0.0);
assert_float_eq!(out[1], 0.3); assert_float_eq!(out[1], 0.3);
assert_float_eq!(out[2], 0.3); assert_float_eq!(out[2], 0.3);
assert_float_eq!(out[3], 0.3); assert_float_eq!(out[3], 0.3);
assert_float_eq!(out[4], 1.0); assert_float_eq!(out[4], 1.0);
assert_float_eq!(out[5], 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] #[test]
fn check_seq_gate_1() { fn check_seq_gate_1() {
let mut ps = PatternSequencer::new(2); let mut ps = PatternSequencer::new(2);
ps.set_col(0, &[ ps.set_col(0, &[
f32::from_bits(0x0FFF), (f32::from_bits(0x0FFF), 1),
f32::from_bits(0xF000), (f32::from_bits(0xF000), 0),
]); ]);
let mut out = [0.0; 6]; 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_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); //d// println!("out: {:?}", out);
assert_float_eq!(out[0], 1.0); assert_float_eq!(out[0], 1.0);
@ -272,6 +329,13 @@ mod tests {
assert_float_eq!(out[3], 0.0); assert_float_eq!(out[3], 0.0);
assert_float_eq!(out[4], 0.0); assert_float_eq!(out[4], 0.0);
assert_float_eq!(out[5], 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 { fn count_high(slice: &[f32]) -> usize {
@ -298,9 +362,9 @@ mod tests {
fn check_seq_gate_2() { fn check_seq_gate_2() {
let mut ps = PatternSequencer::new(3); let mut ps = PatternSequencer::new(3);
ps.set_col(0, &[ ps.set_col(0, &[
f32::from_bits(0x0FF0), (f32::from_bits(0x0FF0), 1),
f32::from_bits(0x0FF7), (f32::from_bits(0x0FF7), 0),
f32::from_bits(0x0FFF), (f32::from_bits(0x0FFF), 1),
]); ]);
let mut phase = vec![0.0; 96]; let mut phase = vec![0.0; 96];
@ -313,26 +377,34 @@ mod tests {
//d// println!("PHASE: {:?}", phase); //d// println!("PHASE: {:?}", phase);
let mut out = [0.0; 96]; let mut out = [0.0; 96];
ps.col_gate_at_phase(0, &phase[..], &mut out[..]); 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]); //d// println!("out: {:?}", &out[0..32]);
assert_eq!(count_high(&out[0..32]), 2); assert_eq!(count_high(&out[0..32]), 2);
assert_eq!(count_high(&out[32..64]), 16); assert_eq!(count_high(&out[32..64]), 16);
assert_eq!(count_high(&out[64..96]), 32); 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[0..32]), 1);
assert_eq!(count_up(&out[32..64]), 1); assert_eq!(count_up(&out[32..64]), 1);
assert_eq!(count_up(&out[64..96]), 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] #[test]
fn check_seq_gate_div_1() { fn check_seq_gate_div_1() {
let mut ps = PatternSequencer::new(3); let mut ps = PatternSequencer::new(3);
ps.set_col(0, &[ ps.set_col(0, &[
f32::from_bits(0x0F80), (f32::from_bits(0x0F80), 1),
f32::from_bits(0x0F87), (f32::from_bits(0x0F87), 0),
f32::from_bits(0x0F8F), (f32::from_bits(0x0F8F), 1),
]); ]);
let mut phase = vec![0.0; 3 * 64]; let mut phase = vec![0.0; 3 * 64];
@ -345,26 +417,34 @@ mod tests {
//d// println!("PHASE: {:?}", phase); //d// println!("PHASE: {:?}", phase);
let mut out = [0.0; 3 * 64]; let mut out = [0.0; 3 * 64];
ps.col_gate_at_phase(0, &phase[..], &mut out[..]); 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_high(&out[0..64]), 8);
assert_eq!(count_up( &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_high(&out[64..128]), 32);
assert_eq!(count_up( &out[64..128]), 8); 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_high(&out[128..192]), 64);
assert_eq!(count_up( &out[128..192]), 1); 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] #[test]
fn check_seq_gate_div_2() { fn check_seq_gate_div_2() {
let mut ps = PatternSequencer::new(3); let mut ps = PatternSequencer::new(3);
ps.set_col(0, &[ ps.set_col(0, &[
f32::from_bits(0x0F00), (f32::from_bits(0x0F00), 1),
f32::from_bits(0x0F07), (f32::from_bits(0x0F07), 0),
f32::from_bits(0x0F0F), (f32::from_bits(0x0F0F), 1),
]); ]);
let mut phase = vec![0.0; 6 * 64]; let mut phase = vec![0.0; 6 * 64];
@ -377,26 +457,33 @@ mod tests {
//d// println!("PHASE: {:?}", phase); //d// println!("PHASE: {:?}", phase);
let mut out = [0.0; 6 * 64]; let mut out = [0.0; 6 * 64];
ps.col_gate_at_phase(0, &phase[..], &mut out[..]); 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_high(&out[0..128]), 16);
assert_eq!(count_up( &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_high(&out[128..256]), 64);
assert_eq!(count_up( &out[128..256]), 16); 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_high(&out[256..384]), 128);
assert_eq!(count_up( &out[256..384]), 1); 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] #[test]
fn check_seq_gate_div_3() { fn check_seq_gate_div_3() {
let mut ps = PatternSequencer::new(3); let mut ps = PatternSequencer::new(3);
ps.set_col(0, &[ ps.set_col(0, &[
f32::from_bits(0x0FE0), (f32::from_bits(0x0FE0), 1),
f32::from_bits(0x0FE7), (f32::from_bits(0x0FE7), 0),
f32::from_bits(0x0FEF), (f32::from_bits(0x0FEF), 1),
]); ]);
let mut phase = vec![0.0; 6 * 64]; let mut phase = vec![0.0; 6 * 64];
@ -409,26 +496,33 @@ mod tests {
//d// println!("PHASE: {:?}", phase); //d// println!("PHASE: {:?}", phase);
let mut out = [0.0; 6 * 64]; let mut out = [0.0; 6 * 64];
ps.col_gate_at_phase(0, &phase[..], &mut out[..]); 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_high(&out[0..128]), 8);
assert_eq!(count_up( &out[0..128]), 2); 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_high(&out[128..256]), 64);
assert_eq!(count_up( &out[128..256]), 2); 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_high(&out[256..384]), 128);
assert_eq!(count_up( &out[256..384]), 1); 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) { fn run_probability_test_for(prob: u32) -> (usize, usize) {
let rows = 100; let rows = 100;
let mut ps = PatternSequencer::new_default_seed(rows); 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() { 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[..]); ps.set_col(0, &coldata[..]);
@ -441,8 +535,9 @@ mod tests {
phase_run += inc; phase_run += inc;
} }
let mut out = vec![0.0; samples]; let mut out = vec![0.0; samples];
ps.col_gate_at_phase(0, &phase[..], &mut out[..]); 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[..])) (count_high(&out[..]), count_up(&out[..]))
} }