Feat: improving MIDI
This commit is contained in:
@@ -1231,47 +1231,115 @@ impl Forth {
|
||||
// MIDI operations
|
||||
Op::MidiEmit => {
|
||||
let (_, params) = cmd.snapshot().unwrap_or((None, &[]));
|
||||
let get_int = |name: &str| -> Option<i64> {
|
||||
params
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|(k, _)| *k == name)
|
||||
.and_then(|(_, v)| v.as_int().ok())
|
||||
};
|
||||
let get_float = |name: &str| -> Option<f64> {
|
||||
params
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|(k, _)| *k == name)
|
||||
.and_then(|(_, v)| v.as_float().ok())
|
||||
};
|
||||
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}/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}/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}/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}/dev/{dev}"));
|
||||
// Build schedule: (emit_idx, delta_secs) — same logic as Op::Emit
|
||||
let schedule: Vec<(usize, f64)> = if has_arp_list(cmd) {
|
||||
let arp_count = compute_arp_count(cmd);
|
||||
let explicit = !cmd.deltas().is_empty();
|
||||
let delta_list = cmd.deltas();
|
||||
let count = if explicit {
|
||||
arp_count.max(delta_list.len())
|
||||
} else {
|
||||
arp_count
|
||||
};
|
||||
(0..count)
|
||||
.map(|i| {
|
||||
let delta_secs = if explicit {
|
||||
let frac = delta_list[i % delta_list.len()]
|
||||
.as_float()
|
||||
.unwrap_or(0.0);
|
||||
ctx.nudge_secs + frac * ctx.step_duration()
|
||||
} else {
|
||||
ctx.nudge_secs
|
||||
+ (i as f64 / count as f64) * ctx.step_duration()
|
||||
};
|
||||
(i, delta_secs)
|
||||
})
|
||||
.collect()
|
||||
} 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}/dev/{dev}"
|
||||
));
|
||||
let poly_count = compute_poly_count(cmd);
|
||||
let deltas: Vec<f64> = if cmd.deltas().is_empty() {
|
||||
vec![0.0]
|
||||
} else {
|
||||
cmd.deltas()
|
||||
.iter()
|
||||
.filter_map(|v| v.as_float().ok())
|
||||
.collect()
|
||||
};
|
||||
let mut sched = Vec::with_capacity(poly_count * deltas.len());
|
||||
for poly_idx in 0..poly_count {
|
||||
for &frac in &deltas {
|
||||
sched.push((
|
||||
poly_idx,
|
||||
ctx.nudge_secs + frac * ctx.step_duration(),
|
||||
));
|
||||
}
|
||||
}
|
||||
sched
|
||||
};
|
||||
|
||||
for (emit_idx, delta_secs) in schedule {
|
||||
let get_int = |name: &str| -> Option<i64> {
|
||||
params
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|(k, _)| *k == name)
|
||||
.and_then(|(_, v)| {
|
||||
resolve_cycling(v, emit_idx).as_int().ok()
|
||||
})
|
||||
};
|
||||
let get_float = |name: &str| -> Option<f64> {
|
||||
params
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|(k, _)| *k == name)
|
||||
.and_then(|(_, v)| {
|
||||
resolve_cycling(v, emit_idx).as_float().ok()
|
||||
})
|
||||
};
|
||||
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);
|
||||
let delta_suffix = if delta_secs > 0.0 {
|
||||
format!("/delta/{delta_secs}")
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
|
||||
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}/dev/{dev}{delta_suffix}"
|
||||
));
|
||||
} 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}/dev/{dev}{delta_suffix}"
|
||||
));
|
||||
} else if let Some(pressure) = get_int("pressure") {
|
||||
let pressure = pressure.clamp(0, 127) as u8;
|
||||
outputs.push(format!(
|
||||
"/midi/pressure/{pressure}/chan/{chan}/dev/{dev}{delta_suffix}"
|
||||
));
|
||||
} else if let Some(program) = get_int("program") {
|
||||
let program = program.clamp(0, 127) as u8;
|
||||
outputs.push(format!(
|
||||
"/midi/program/{program}/chan/{chan}/dev/{dev}{delta_suffix}"
|
||||
));
|
||||
} 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}/dev/{dev}{delta_suffix}"
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
Op::MidiClock => {
|
||||
|
||||
Reference in New Issue
Block a user