chain word and better save/load UI

This commit is contained in:
2026-01-23 23:36:23 +01:00
parent a1ddb4a170
commit f75ea4bb97
20 changed files with 775 additions and 132 deletions

View File

@@ -79,4 +79,5 @@ pub enum Op {
Ramp,
Range,
Noise,
Chain,
}

View File

@@ -19,6 +19,7 @@ pub struct ExecutionTrace {
pub struct StepContext {
pub step: usize,
pub beat: f64,
pub bank: usize,
pub pattern: usize,
pub tempo: f64,
pub phase: f64,

View File

@@ -299,6 +299,7 @@ impl Forth {
let val = match name.as_str() {
"step" => Value::Int(ctx.step as i64, None),
"beat" => Value::Float(ctx.beat, None),
"bank" => Value::Int(ctx.bank as i64, None),
"pattern" => Value::Int(ctx.pattern as i64, None),
"tempo" => Value::Float(ctx.tempo, None),
"phase" => Value::Float(ctx.phase, None),
@@ -628,6 +629,24 @@ impl Forth {
.insert("__tempo__".to_string(), Value::Float(clamped, None));
}
Op::Chain => {
let pattern = stack.pop().ok_or("stack underflow")?.as_int()? - 1;
let bank = stack.pop().ok_or("stack underflow")?.as_int()? - 1;
if bank < 0 || pattern < 0 {
return Err("chain: bank and pattern must be >= 1".into());
}
if bank as usize == ctx.bank && pattern as usize == ctx.pattern {
// chaining to self is a no-op
} else {
let key = format!("__chain_{}_{}__", ctx.bank, ctx.pattern);
let val = format!("{bank}:{pattern}");
self.vars
.lock()
.unwrap()
.insert(key, Value::Str(val, None));
}
}
Op::ListStart => {
stack.push(Value::Marker);
}

View File

@@ -428,6 +428,13 @@ pub const WORDS: &[Word] = &[
example: "pattern => 0",
compile: Context("pattern"),
},
Word {
name: "pbank",
stack: "(-- n)",
desc: "Current pattern's bank index",
example: "pbank => 0",
compile: Context("bank"),
},
Word {
name: "tempo",
stack: "(-- f)",
@@ -621,6 +628,13 @@ pub const WORDS: &[Word] = &[
example: "140 tempo!",
compile: Simple,
},
Word {
name: "chain",
stack: "(bank pattern --)",
desc: "Chain to bank/pattern (1-indexed) when current pattern ends",
example: "1 4 chain",
compile: Simple,
},
// Lists
Word {
name: "[",
@@ -1550,6 +1564,7 @@ pub(super) fn simple_op(name: &str) -> Option<Op> {
"ramp" => Op::Ramp,
"range" => Op::Range,
"noise" => Op::Noise,
"chain" => Op::Chain,
_ => return None,
})
}