Feat: improve 'at' in cagire grammar
This commit is contained in:
@@ -241,31 +241,7 @@ impl Forth {
|
||||
sound_len.max(param_max)
|
||||
};
|
||||
|
||||
let has_arp_list = |cmd: &CmdRegister| -> bool {
|
||||
matches!(cmd.sound(), Some(Value::ArpList(_)))
|
||||
|| cmd.global_params().iter().chain(cmd.params().iter())
|
||||
.any(|(_, v)| matches!(v, Value::ArpList(_)))
|
||||
};
|
||||
|
||||
let compute_arp_count = |cmd: &CmdRegister| -> usize {
|
||||
let sound_len = match cmd.sound() {
|
||||
Some(Value::ArpList(items)) => items.len(),
|
||||
_ => 0,
|
||||
};
|
||||
let param_max = cmd
|
||||
.params()
|
||||
.iter()
|
||||
.map(|(_, v)| match v {
|
||||
Value::ArpList(items) => items.len(),
|
||||
_ => 0,
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(0);
|
||||
sound_len.max(param_max).max(1)
|
||||
};
|
||||
|
||||
let emit_with_cycling = |cmd: &CmdRegister,
|
||||
arp_idx: usize,
|
||||
poly_idx: usize,
|
||||
delta_secs: f64,
|
||||
outputs: &mut Vec<String>|
|
||||
@@ -277,7 +253,7 @@ impl Forth {
|
||||
return Err("nothing to emit".into());
|
||||
}
|
||||
let resolved_sound_val =
|
||||
cmd.sound().map(|sv| resolve_value(sv, arp_idx, poly_idx));
|
||||
cmd.sound().map(|sv| resolve_value(sv, poly_idx));
|
||||
let sound_str = match &resolved_sound_val {
|
||||
Some(v) => Some(v.as_str()?.to_string()),
|
||||
None => None,
|
||||
@@ -286,8 +262,8 @@ impl Forth {
|
||||
.iter()
|
||||
.chain(cmd.params().iter())
|
||||
.map(|(k, v)| {
|
||||
let resolved = resolve_value(v, arp_idx, poly_idx);
|
||||
if let Value::CycleList(_) | Value::ArpList(_) = v {
|
||||
let resolved = resolve_value(v, poly_idx);
|
||||
if let Value::CycleList(_) = v {
|
||||
if let Some(span) = resolved.span() {
|
||||
if let Some(trace) = trace_cell.borrow_mut().as_mut() {
|
||||
trace.selected_spans.push(span);
|
||||
@@ -595,47 +571,17 @@ impl Forth {
|
||||
}
|
||||
|
||||
Op::Emit => {
|
||||
if has_arp_list(cmd) {
|
||||
let arp_count = compute_arp_count(cmd);
|
||||
if let Some(dsecs) = cmd.take_delta_secs() {
|
||||
let poly_count = compute_poly_count(cmd);
|
||||
let explicit_deltas = !cmd.deltas().is_empty();
|
||||
let delta_list: Vec<Value> = if explicit_deltas {
|
||||
cmd.deltas().to_vec()
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let count = if explicit_deltas {
|
||||
arp_count.max(delta_list.len())
|
||||
} else {
|
||||
arp_count
|
||||
};
|
||||
|
||||
for i in 0..count {
|
||||
let delta_secs = if explicit_deltas {
|
||||
let dv = &delta_list[i % delta_list.len()];
|
||||
let frac = dv.as_float()?;
|
||||
if let Some(span) = dv.span() {
|
||||
for poly_idx in 0..poly_count {
|
||||
if let Some(sound_val) =
|
||||
emit_with_cycling(cmd, poly_idx, dsecs, outputs)?
|
||||
{
|
||||
if let Some(span) = sound_val.span() {
|
||||
if let Some(trace) = trace_cell.borrow_mut().as_mut() {
|
||||
trace.selected_spans.push(span);
|
||||
}
|
||||
}
|
||||
ctx.nudge_secs + frac * ctx.step_duration()
|
||||
} else {
|
||||
ctx.nudge_secs
|
||||
+ (i as f64 / count as f64) * ctx.step_duration()
|
||||
};
|
||||
for poly_i in 0..poly_count {
|
||||
if let Some(sound_val) =
|
||||
emit_with_cycling(cmd, i, poly_i, delta_secs, outputs)?
|
||||
{
|
||||
if let Some(span) = sound_val.span() {
|
||||
if let Some(trace) =
|
||||
trace_cell.borrow_mut().as_mut()
|
||||
{
|
||||
trace.selected_spans.push(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -657,7 +603,7 @@ impl Forth {
|
||||
}
|
||||
}
|
||||
if let Some(sound_val) =
|
||||
emit_with_cycling(cmd, 0, poly_idx, delta_secs, outputs)?
|
||||
emit_with_cycling(cmd, poly_idx, delta_secs, outputs)?
|
||||
{
|
||||
if let Some(span) = sound_val.span() {
|
||||
if let Some(trace) =
|
||||
@@ -1196,12 +1142,60 @@ impl Forth {
|
||||
cmd.set_deltas(deltas);
|
||||
}
|
||||
|
||||
Op::Arp => {
|
||||
Op::AtLoop(body_ops) => {
|
||||
ensure(stack, 1)?;
|
||||
let values = std::mem::take(stack);
|
||||
stack.push(Value::ArpList(Arc::from(values)));
|
||||
let deltas = std::mem::take(stack);
|
||||
let n = deltas.len();
|
||||
|
||||
for (i, delta_val) in deltas.iter().enumerate() {
|
||||
let frac = delta_val.as_float()?;
|
||||
let delta_secs = ctx.nudge_secs + frac * ctx.step_duration();
|
||||
|
||||
let iter_ctx = StepContext {
|
||||
step: ctx.step,
|
||||
beat: ctx.beat,
|
||||
bank: ctx.bank,
|
||||
pattern: ctx.pattern,
|
||||
tempo: ctx.tempo,
|
||||
phase: ctx.phase,
|
||||
slot: ctx.slot,
|
||||
runs: ctx.runs * n + i,
|
||||
iter: ctx.iter,
|
||||
speed: ctx.speed,
|
||||
fill: ctx.fill,
|
||||
nudge_secs: ctx.nudge_secs,
|
||||
sr: ctx.sr,
|
||||
cc_access: ctx.cc_access,
|
||||
speed_key: ctx.speed_key,
|
||||
mouse_x: ctx.mouse_x,
|
||||
mouse_y: ctx.mouse_y,
|
||||
mouse_down: ctx.mouse_down,
|
||||
};
|
||||
|
||||
cmd.set_delta_secs(delta_secs);
|
||||
|
||||
let mut trace_opt = trace_cell.borrow_mut().take();
|
||||
let mut var_writes_guard = var_writes_cell.borrow_mut();
|
||||
let vw = var_writes_guard.as_mut().expect("var_writes taken");
|
||||
self.execute_ops(
|
||||
body_ops,
|
||||
&iter_ctx,
|
||||
stack,
|
||||
outputs,
|
||||
cmd,
|
||||
trace_opt.as_deref_mut(),
|
||||
vars_snapshot,
|
||||
vw,
|
||||
)?;
|
||||
drop(var_writes_guard);
|
||||
*trace_cell.borrow_mut() = trace_opt;
|
||||
|
||||
cmd.clear_params();
|
||||
cmd.clear_sound();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Op::Adsr => {
|
||||
let r = pop(stack)?;
|
||||
let s = pop(stack)?;
|
||||
@@ -1499,35 +1493,13 @@ impl Forth {
|
||||
|
||||
// MIDI operations
|
||||
Op::MidiEmit => {
|
||||
let at_loop_delta = cmd.take_delta_secs();
|
||||
let (_, params) = cmd.snapshot().unwrap_or((None, &[]));
|
||||
|
||||
// Build schedule: (arp_idx, poly_idx, delta_secs)
|
||||
let schedule: Vec<(usize, usize, f64)> = if has_arp_list(cmd) {
|
||||
let arp_count = compute_arp_count(cmd);
|
||||
// Build schedule: (poly_idx, delta_secs)
|
||||
let schedule: Vec<(usize, f64)> = if let Some(dsecs) = at_loop_delta {
|
||||
let poly_count = compute_poly_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
|
||||
};
|
||||
let mut sched = Vec::with_capacity(count * poly_count);
|
||||
for i in 0..count {
|
||||
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()
|
||||
};
|
||||
for poly_i in 0..poly_count {
|
||||
sched.push((i, poly_i, delta_secs));
|
||||
}
|
||||
}
|
||||
sched
|
||||
(0..poly_count).map(|pi| (pi, dsecs)).collect()
|
||||
} else {
|
||||
let poly_count = compute_poly_count(cmd);
|
||||
let deltas: Vec<f64> = if cmd.deltas().is_empty() {
|
||||
@@ -1542,7 +1514,6 @@ impl Forth {
|
||||
for poly_idx in 0..poly_count {
|
||||
for &frac in &deltas {
|
||||
sched.push((
|
||||
0,
|
||||
poly_idx,
|
||||
ctx.nudge_secs + frac * ctx.step_duration(),
|
||||
));
|
||||
@@ -1551,14 +1522,14 @@ impl Forth {
|
||||
sched
|
||||
};
|
||||
|
||||
for (arp_idx, poly_idx, delta_secs) in schedule {
|
||||
for (poly_idx, delta_secs) in schedule {
|
||||
let get_int = |name: &str| -> Option<i64> {
|
||||
params
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|(k, _)| *k == name)
|
||||
.and_then(|(_, v)| {
|
||||
resolve_value(v, arp_idx, poly_idx).as_int().ok()
|
||||
resolve_value(v, poly_idx).as_int().ok()
|
||||
})
|
||||
};
|
||||
let get_float = |name: &str| -> Option<f64> {
|
||||
@@ -1567,7 +1538,7 @@ impl Forth {
|
||||
.rev()
|
||||
.find(|(k, _)| *k == name)
|
||||
.and_then(|(_, v)| {
|
||||
resolve_value(v, arp_idx, poly_idx).as_float().ok()
|
||||
resolve_value(v, poly_idx).as_float().ok()
|
||||
})
|
||||
};
|
||||
let chan = get_int("chan")
|
||||
@@ -1960,10 +1931,6 @@ where
|
||||
F: Fn(f64) -> f64 + Copy,
|
||||
{
|
||||
match val {
|
||||
Value::ArpList(items) => {
|
||||
let mapped: Result<Vec<_>, _> = items.iter().map(|x| lift_unary(x, f)).collect();
|
||||
Ok(Value::ArpList(Arc::from(mapped?)))
|
||||
}
|
||||
Value::CycleList(items) => {
|
||||
let mapped: Result<Vec<_>, _> = items.iter().map(|x| lift_unary(x, f)).collect();
|
||||
Ok(Value::CycleList(Arc::from(mapped?)))
|
||||
@@ -1977,11 +1944,6 @@ where
|
||||
F: Fn(i64) -> i64 + Copy,
|
||||
{
|
||||
match val {
|
||||
Value::ArpList(items) => {
|
||||
let mapped: Result<Vec<_>, _> =
|
||||
items.iter().map(|x| lift_unary_int(x, f)).collect();
|
||||
Ok(Value::ArpList(Arc::from(mapped?)))
|
||||
}
|
||||
Value::CycleList(items) => {
|
||||
let mapped: Result<Vec<_>, _> =
|
||||
items.iter().map(|x| lift_unary_int(x, f)).collect();
|
||||
@@ -1996,16 +1958,6 @@ where
|
||||
F: Fn(f64, f64) -> f64 + Copy,
|
||||
{
|
||||
match (a, b) {
|
||||
(Value::ArpList(items), b) => {
|
||||
let mapped: Result<Vec<_>, _> =
|
||||
items.iter().map(|x| lift_binary(x, b, f)).collect();
|
||||
Ok(Value::ArpList(Arc::from(mapped?)))
|
||||
}
|
||||
(a, Value::ArpList(items)) => {
|
||||
let mapped: Result<Vec<_>, _> =
|
||||
items.iter().map(|x| lift_binary(a, x, f)).collect();
|
||||
Ok(Value::ArpList(Arc::from(mapped?)))
|
||||
}
|
||||
(Value::CycleList(items), b) => {
|
||||
let mapped: Result<Vec<_>, _> =
|
||||
items.iter().map(|x| lift_binary(x, b, f)).collect();
|
||||
@@ -2045,11 +1997,8 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resolve_value(val: &Value, arp_idx: usize, poly_idx: usize) -> Cow<'_, Value> {
|
||||
fn resolve_value(val: &Value, poly_idx: usize) -> Cow<'_, Value> {
|
||||
match val {
|
||||
Value::ArpList(items) if !items.is_empty() => {
|
||||
Cow::Owned(items[arp_idx % items.len()].clone())
|
||||
}
|
||||
Value::CycleList(items) if !items.is_empty() => {
|
||||
Cow::Owned(items[poly_idx % items.len()].clone())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user