Feat: new euclidean words and sugar for floating point numbers
Some checks failed
Deploy Website / deploy (push) Failing after 4m47s
Some checks failed
Deploy Website / deploy (push) Failing after 4m47s
This commit is contained in:
@@ -1025,6 +1025,29 @@ impl Forth {
|
||||
}
|
||||
}
|
||||
|
||||
Op::Euclid => {
|
||||
let n = stack.pop().ok_or("stack underflow")?.as_int()?;
|
||||
let k = stack.pop().ok_or("stack underflow")?.as_int()?;
|
||||
if k < 0 || n < 0 {
|
||||
return Err("euclid: k and n must be >= 0".into());
|
||||
}
|
||||
for idx in euclidean_rhythm(k as usize, n as usize, 0) {
|
||||
stack.push(Value::Int(idx, None));
|
||||
}
|
||||
}
|
||||
|
||||
Op::EuclidRot => {
|
||||
let r = stack.pop().ok_or("stack underflow")?.as_int()?;
|
||||
let n = stack.pop().ok_or("stack underflow")?.as_int()?;
|
||||
let k = stack.pop().ok_or("stack underflow")?.as_int()?;
|
||||
if k < 0 || n < 0 || r < 0 {
|
||||
return Err("euclidrot: k, n, and r must be >= 0".into());
|
||||
}
|
||||
for idx in euclidean_rhythm(k as usize, n as usize, r as usize) {
|
||||
stack.push(Value::Int(idx, None));
|
||||
}
|
||||
}
|
||||
|
||||
// MIDI operations
|
||||
Op::MidiEmit => {
|
||||
let (_, params) = cmd.snapshot().unwrap_or((None, &[]));
|
||||
@@ -1216,6 +1239,58 @@ fn emit_output(
|
||||
outputs.push(out);
|
||||
}
|
||||
|
||||
fn euclidean_rhythm(k: usize, n: usize, rotation: usize) -> Vec<i64> {
|
||||
if k == 0 || n == 0 {
|
||||
return Vec::new();
|
||||
}
|
||||
if k >= n {
|
||||
return (0..n as i64).collect();
|
||||
}
|
||||
|
||||
let mut groups: Vec<Vec<bool>> = (0..k).map(|_| vec![true]).collect();
|
||||
groups.extend((0..(n - k)).map(|_| vec![false]));
|
||||
|
||||
while groups.len() > 1 {
|
||||
let ones_count = groups.iter().filter(|g| g[0]).count();
|
||||
let zeros_count = groups.len() - ones_count;
|
||||
|
||||
if zeros_count == 0 || ones_count == 0 {
|
||||
break;
|
||||
}
|
||||
|
||||
let min_count = ones_count.min(zeros_count);
|
||||
let mut new_groups = Vec::with_capacity(groups.len() - min_count);
|
||||
|
||||
let (mut ones, mut zeros): (Vec<_>, Vec<_>) =
|
||||
groups.into_iter().partition(|g| g[0]);
|
||||
|
||||
for _ in 0..min_count {
|
||||
let mut one = ones.pop().unwrap();
|
||||
one.extend(zeros.pop().unwrap());
|
||||
new_groups.push(one);
|
||||
}
|
||||
new_groups.extend(ones);
|
||||
new_groups.extend(zeros);
|
||||
|
||||
groups = new_groups;
|
||||
}
|
||||
|
||||
let pattern: Vec<bool> = groups.into_iter().flatten().collect();
|
||||
|
||||
let rotated = if rotation > 0 && !pattern.is_empty() {
|
||||
let r = rotation % pattern.len();
|
||||
pattern.iter().cycle().skip(r).take(pattern.len()).copied().collect()
|
||||
} else {
|
||||
pattern
|
||||
};
|
||||
|
||||
rotated
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.filter_map(|(i, hit)| if hit { Some(i as i64) } else { None })
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn perlin_grad(hash_input: i64) -> f64 {
|
||||
let mut h = (hash_input as u64)
|
||||
.wrapping_mul(6364136223846793005)
|
||||
|
||||
Reference in New Issue
Block a user