A ton of bug fixes

This commit is contained in:
2026-01-28 01:09:23 +01:00
parent a9ce70d292
commit 322885b908
13 changed files with 400 additions and 130 deletions

View File

@@ -28,6 +28,7 @@ pub struct StepContext {
pub iter: usize,
pub speed: f64,
pub fill: bool,
pub nudge_secs: f64,
}
impl StepContext {

View File

@@ -86,7 +86,7 @@ impl Forth {
// Resolve root scope at end of script
if let Some(scope) = scope_stack.pop() {
resolve_scope(&scope, ctx.step_duration(), &mut outputs);
resolve_scope(&scope, ctx.step_duration(), ctx.nudge_secs, &mut outputs);
}
Ok(outputs)
@@ -281,10 +281,20 @@ impl Forth {
Op::Add => binary_op(stack, |a, b| a + b)?,
Op::Sub => binary_op(stack, |a, b| a - b)?,
Op::Mul => binary_op(stack, |a, b| a * b)?,
Op::Div => binary_op(stack, |a, b| a / b)?,
Op::Div => {
let b = stack.pop().ok_or("stack underflow")?;
let a = stack.pop().ok_or("stack underflow")?;
if b.as_float().map_or(true, |v| v == 0.0) {
return Err("division by zero".into());
}
stack.push(lift_binary(a, b, |x, y| x / y)?);
}
Op::Mod => {
let b = stack.pop().ok_or("stack underflow")?;
let a = stack.pop().ok_or("stack underflow")?;
if b.as_float().map_or(true, |v| v == 0.0) {
return Err("modulo by zero".into());
}
let result = lift_binary(a, b, |x, y| (x as i64 % y as i64) as f64)?;
stack.push(result);
}
@@ -448,17 +458,19 @@ impl Forth {
}
Op::Rand => {
let max = stack.pop().ok_or("stack underflow")?;
let min = stack.pop().ok_or("stack underflow")?;
match (&min, &max) {
(Value::Int(min_i, _), Value::Int(max_i, _)) => {
let val = self.rng.lock().unwrap().gen_range(*min_i..=*max_i);
let b = stack.pop().ok_or("stack underflow")?;
let a = stack.pop().ok_or("stack underflow")?;
match (&a, &b) {
(Value::Int(a_i, _), Value::Int(b_i, _)) => {
let (lo, hi) = if a_i <= b_i { (*a_i, *b_i) } else { (*b_i, *a_i) };
let val = self.rng.lock().unwrap().gen_range(lo..=hi);
stack.push(Value::Int(val, None));
}
_ => {
let min_f = min.as_float()?;
let max_f = max.as_float()?;
let val = self.rng.lock().unwrap().gen_range(min_f..max_f);
let a_f = a.as_float()?;
let b_f = b.as_float()?;
let (lo, hi) = if a_f <= b_f { (a_f, b_f) } else { (b_f, a_f) };
let val = self.rng.lock().unwrap().gen_range(lo..hi);
stack.push(Value::Float(val, None));
}
}
@@ -545,7 +557,11 @@ impl Forth {
}
Op::Pick => {
let idx = stack.pop().ok_or("stack underflow")?.as_int()? as usize;
let idx_i = stack.pop().ok_or("stack underflow")?.as_int()?;
if idx_i < 0 {
return Err(format!("pick index must be >= 0, got {}", idx_i));
}
let idx = idx_i as usize;
let mut quots: Vec<Value> = Vec::new();
while let Some(val) = stack.pop() {
match &val {
@@ -580,6 +596,9 @@ impl Forth {
}
Op::Degree(pattern) => {
if pattern.is_empty() {
return Err("empty scale pattern".into());
}
let val = stack.pop().ok_or("stack underflow")?;
let len = pattern.len() as i64;
let result = lift_unary_int(val, |degree| {
@@ -623,6 +642,9 @@ impl Forth {
Op::Loop => {
let beats = stack.pop().ok_or("stack underflow")?.as_float()?;
if ctx.tempo == 0.0 || ctx.speed == 0.0 {
return Err("tempo and speed must be non-zero".into());
}
let dur = beats * 60.0 / ctx.tempo / ctx.speed;
cmd.set_param("fit".into(), Value::Float(dur, None));
cmd.set_param("dur".into(), Value::Float(dur, None));
@@ -726,7 +748,7 @@ impl Forth {
let child = scope_stack.pop().unwrap();
if child.stacked {
resolve_scope(&child, ctx.step_duration(), outputs);
resolve_scope(&child, ctx.step_duration(), ctx.nudge_secs, outputs);
} else {
let parent = scope_stack.last_mut().ok_or("scope stack underflow")?;
let parent_slot = parent.claim_slot();
@@ -763,7 +785,12 @@ impl Forth {
}
}
fn resolve_scope(scope: &ScopeContext, step_duration: f64, outputs: &mut Vec<String>) {
fn resolve_scope(
scope: &ScopeContext,
step_duration: f64,
nudge_secs: f64,
outputs: &mut Vec<String>,
) {
let slot_dur = if scope.slot_count == 0 {
scope.duration * scope.weight
} else {
@@ -814,6 +841,7 @@ fn resolve_scope(scope: &ScopeContext, step_duration: f64, outputs: &mut Vec<Str
em.delta,
em.dur,
step_duration,
nudge_secs,
outputs,
);
}
@@ -889,12 +917,14 @@ fn emit_output(
delta: f64,
dur: f64,
step_duration: f64,
nudge_secs: f64,
outputs: &mut Vec<String>,
) {
let nudged_delta = delta + nudge_secs;
let mut pairs = vec![("sound".into(), sound.to_string())];
pairs.extend(params.iter().cloned());
if delta > 0.0 {
pairs.push(("delta".into(), delta.to_string()));
if nudged_delta > 0.0 {
pairs.push(("delta".into(), nudged_delta.to_string()));
}
if !pairs.iter().any(|(k, _)| k == "dur") {
pairs.push(("dur".into(), dur.to_string()));