More robust midi implementation

This commit is contained in:
2026-01-31 23:58:57 +01:00
parent dfd024cab7
commit 96e7fb6bc4
12 changed files with 393 additions and 201 deletions

View File

@@ -811,51 +811,94 @@ impl Forth {
let chan = get_int("chan")
.map(|c| (c.clamp(1, 16) - 1) as u8)
.unwrap_or(0);
let dev = get_int("dev")
.map(|d| d.clamp(0, 3) as u8)
.unwrap_or(0);
if let (Some(cc), Some(val)) = (get_int("ccnum"), get_int("ccout")) {
let cc = cc.clamp(0, 127) as u8;
let val = val.clamp(0, 127) as u8;
outputs.push(format!("/midi/cc/{cc}/{val}/chan/{chan}"));
outputs.push(format!("/midi/cc/{cc}/{val}/chan/{chan}/dev/{dev}"));
} else if let Some(bend) = get_float("bend") {
let bend_clamped = bend.clamp(-1.0, 1.0);
let bend_14bit = ((bend_clamped + 1.0) * 8191.5) as u16;
outputs.push(format!("/midi/bend/{bend_14bit}/chan/{chan}"));
outputs.push(format!("/midi/bend/{bend_14bit}/chan/{chan}/dev/{dev}"));
} else if let Some(pressure) = get_int("pressure") {
let pressure = pressure.clamp(0, 127) as u8;
outputs.push(format!("/midi/pressure/{pressure}/chan/{chan}"));
outputs.push(format!("/midi/pressure/{pressure}/chan/{chan}/dev/{dev}"));
} else if let Some(program) = get_int("program") {
let program = program.clamp(0, 127) as u8;
outputs.push(format!("/midi/program/{program}/chan/{chan}"));
outputs.push(format!("/midi/program/{program}/chan/{chan}/dev/{dev}"));
} else {
let note = get_int("note").unwrap_or(60).clamp(0, 127) as u8;
let velocity = get_int("velocity").unwrap_or(100).clamp(0, 127) as u8;
let dur = get_float("dur").unwrap_or(1.0);
let dur_secs = dur * ctx.step_duration();
outputs.push(format!("/midi/note/{note}/vel/{velocity}/chan/{chan}/dur/{dur_secs}"));
outputs.push(format!("/midi/note/{note}/vel/{velocity}/chan/{chan}/dur/{dur_secs}/dev/{dev}"));
}
}
Op::MidiClock => {
outputs.push("/midi/clock".to_string());
let (_, params) = cmd.snapshot().unwrap_or((None, &[]));
let dev = params
.iter()
.rev()
.find(|(k, _)| k == "dev")
.and_then(|(_, v)| v.as_int().ok())
.map(|d| d.clamp(0, 3) as u8)
.unwrap_or(0);
outputs.push(format!("/midi/clock/dev/{dev}"));
}
Op::MidiStart => {
outputs.push("/midi/start".to_string());
let (_, params) = cmd.snapshot().unwrap_or((None, &[]));
let dev = params
.iter()
.rev()
.find(|(k, _)| k == "dev")
.and_then(|(_, v)| v.as_int().ok())
.map(|d| d.clamp(0, 3) as u8)
.unwrap_or(0);
outputs.push(format!("/midi/start/dev/{dev}"));
}
Op::MidiStop => {
outputs.push("/midi/stop".to_string());
let (_, params) = cmd.snapshot().unwrap_or((None, &[]));
let dev = params
.iter()
.rev()
.find(|(k, _)| k == "dev")
.and_then(|(_, v)| v.as_int().ok())
.map(|d| d.clamp(0, 3) as u8)
.unwrap_or(0);
outputs.push(format!("/midi/stop/dev/{dev}"));
}
Op::MidiContinue => {
outputs.push("/midi/continue".to_string());
let (_, params) = cmd.snapshot().unwrap_or((None, &[]));
let dev = params
.iter()
.rev()
.find(|(k, _)| k == "dev")
.and_then(|(_, v)| v.as_int().ok())
.map(|d| d.clamp(0, 3) as u8)
.unwrap_or(0);
outputs.push(format!("/midi/continue/dev/{dev}"));
}
Op::GetMidiCC => {
let chan = stack.pop().ok_or("stack underflow")?.as_int()?;
let cc = stack.pop().ok_or("stack underflow")?.as_int()?;
let cc_clamped = (cc.clamp(0, 127)) as usize;
let chan_clamped = (chan.clamp(1, 16) - 1) as usize;
let (_, params) = cmd.snapshot().unwrap_or((None, &[]));
let dev = params
.iter()
.rev()
.find(|(k, _)| k == "dev")
.and_then(|(_, v)| v.as_int().ok())
.map(|d| d.clamp(0, 3) as usize)
.unwrap_or(0);
let val = ctx
.cc_memory
.as_ref()
.and_then(|mem| mem.lock().ok())
.map(|mem| mem[chan_clamped][cc_clamped])
.map(|mem| mem[dev][chan_clamped][cc_clamped])
.unwrap_or(0);
stack.push(Value::Int(val as i64, None));
}