Try to optimize
This commit is contained in:
@@ -83,4 +83,7 @@ pub enum Op {
|
||||
ClearCmd,
|
||||
SetSpeed,
|
||||
At,
|
||||
IntRange,
|
||||
Generate,
|
||||
GeomRange,
|
||||
}
|
||||
|
||||
@@ -140,10 +140,8 @@ impl CmdRegister {
|
||||
&self.deltas
|
||||
}
|
||||
|
||||
pub(super) fn snapshot(&self) -> Option<(Value, Vec<(String, Value)>)> {
|
||||
self.sound
|
||||
.as_ref()
|
||||
.map(|s| (s.clone(), self.params.clone()))
|
||||
pub(super) fn snapshot(&self) -> Option<(&Value, &[(String, Value)])> {
|
||||
self.sound.as_ref().map(|s| (s, self.params.as_slice()))
|
||||
}
|
||||
|
||||
pub(super) fn clear(&mut self) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use rand::rngs::StdRng;
|
||||
use rand::{Rng as RngTrait, SeedableRng};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use super::compiler::compile_script;
|
||||
use super::ops::Op;
|
||||
@@ -147,13 +148,11 @@ impl Forth {
|
||||
|
||||
let emit_with_cycling = |cmd: &CmdRegister, emit_idx: usize, delta_secs: f64, outputs: &mut Vec<String>| -> Result<Option<Value>, String> {
|
||||
let (sound_val, params) = cmd.snapshot().ok_or("no sound set")?;
|
||||
let resolved_sound_val = resolve_cycling(&sound_val, emit_idx);
|
||||
// Note: sound span is recorded by Op::Emit, not here
|
||||
let resolved_sound_val = resolve_cycling(sound_val, emit_idx);
|
||||
let sound = resolved_sound_val.as_str()?.to_string();
|
||||
let resolved_params: Vec<(String, String)> =
|
||||
params.iter().map(|(k, v)| {
|
||||
let resolved = resolve_cycling(v, emit_idx);
|
||||
// Record selected span for params if they came from a CycleList
|
||||
if let Value::CycleList(_) = v {
|
||||
if let Some(span) = resolved.span() {
|
||||
if let Some(trace) = trace_cell.borrow_mut().as_mut() {
|
||||
@@ -164,7 +163,7 @@ impl Forth {
|
||||
(k.clone(), resolved.to_param_string())
|
||||
}).collect();
|
||||
emit_output(&sound, &resolved_params, ctx.step_duration(), delta_secs, outputs);
|
||||
Ok(Some(resolved_sound_val))
|
||||
Ok(Some(resolved_sound_val.into_owned()))
|
||||
};
|
||||
|
||||
while pc < ops.len() {
|
||||
@@ -630,8 +629,15 @@ impl Forth {
|
||||
let top = stack.pop().ok_or("stack underflow")?;
|
||||
let deltas = match &top {
|
||||
Value::Float(..) => vec![top],
|
||||
Value::Int(n, _) if *n > 0 && stack.len() >= *n as usize => {
|
||||
Value::Int(n, _) => {
|
||||
let count = *n as usize;
|
||||
if stack.len() < count {
|
||||
return Err(format!(
|
||||
"at: stack underflow, expected {} values but got {}",
|
||||
count,
|
||||
stack.len()
|
||||
));
|
||||
}
|
||||
let mut vals = Vec::with_capacity(count);
|
||||
for _ in 0..count {
|
||||
vals.push(stack.pop().ok_or("stack underflow")?);
|
||||
@@ -639,8 +645,7 @@ impl Forth {
|
||||
vals.reverse();
|
||||
vals
|
||||
}
|
||||
Value::Int(..) => vec![top],
|
||||
_ => return Err("at expects number or list".into()),
|
||||
_ => return Err("at expects float or int count".into()),
|
||||
};
|
||||
cmd.set_deltas(deltas);
|
||||
}
|
||||
@@ -709,6 +714,50 @@ impl Forth {
|
||||
emit_with_cycling(cmd, i, ctx.nudge_secs, outputs)?;
|
||||
}
|
||||
}
|
||||
|
||||
Op::IntRange => {
|
||||
let end = stack.pop().ok_or("stack underflow")?.as_int()?;
|
||||
let start = stack.pop().ok_or("stack underflow")?.as_int()?;
|
||||
if start <= end {
|
||||
for i in start..=end {
|
||||
stack.push(Value::Int(i, None));
|
||||
}
|
||||
} else {
|
||||
for i in (end..=start).rev() {
|
||||
stack.push(Value::Int(i, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Op::Generate => {
|
||||
let count = stack.pop().ok_or("stack underflow")?.as_int()?;
|
||||
let quot = stack.pop().ok_or("stack underflow")?;
|
||||
if count < 0 {
|
||||
return Err("gen count must be >= 0".into());
|
||||
}
|
||||
let mut results = Vec::with_capacity(count as usize);
|
||||
for _ in 0..count {
|
||||
run_quotation(quot.clone(), stack, outputs, cmd)?;
|
||||
results.push(stack.pop().ok_or("gen: quotation must produce a value")?);
|
||||
}
|
||||
for val in results {
|
||||
stack.push(val);
|
||||
}
|
||||
}
|
||||
|
||||
Op::GeomRange => {
|
||||
let count = stack.pop().ok_or("stack underflow")?.as_int()?;
|
||||
let ratio = stack.pop().ok_or("stack underflow")?.as_float()?;
|
||||
let start = stack.pop().ok_or("stack underflow")?.as_float()?;
|
||||
if count < 0 {
|
||||
return Err("geom.. count must be >= 0".into());
|
||||
}
|
||||
let mut val = start;
|
||||
for _ in 0..count {
|
||||
stack.push(float_to_value(val));
|
||||
val *= ratio;
|
||||
}
|
||||
}
|
||||
}
|
||||
pc += 1;
|
||||
}
|
||||
@@ -717,31 +766,34 @@ impl Forth {
|
||||
}
|
||||
}
|
||||
|
||||
const TEMPO_SCALED_PARAMS: &[&str] = &[
|
||||
"attack",
|
||||
"decay",
|
||||
"release",
|
||||
"lpa",
|
||||
"lpd",
|
||||
"lpr",
|
||||
"hpa",
|
||||
"hpd",
|
||||
"hpr",
|
||||
"bpa",
|
||||
"bpd",
|
||||
"bpr",
|
||||
"patt",
|
||||
"pdec",
|
||||
"prel",
|
||||
"fma",
|
||||
"fmd",
|
||||
"fmr",
|
||||
"glide",
|
||||
"verbdecay",
|
||||
"verbpredelay",
|
||||
"chorusdelay",
|
||||
"duration",
|
||||
];
|
||||
fn is_tempo_scaled_param(name: &str) -> bool {
|
||||
matches!(
|
||||
name,
|
||||
"attack"
|
||||
| "decay"
|
||||
| "release"
|
||||
| "lpa"
|
||||
| "lpd"
|
||||
| "lpr"
|
||||
| "hpa"
|
||||
| "hpd"
|
||||
| "hpr"
|
||||
| "bpa"
|
||||
| "bpd"
|
||||
| "bpr"
|
||||
| "patt"
|
||||
| "pdec"
|
||||
| "prel"
|
||||
| "fma"
|
||||
| "fmd"
|
||||
| "fmr"
|
||||
| "glide"
|
||||
| "verbdecay"
|
||||
| "verbpredelay"
|
||||
| "chorusdelay"
|
||||
| "duration"
|
||||
)
|
||||
}
|
||||
|
||||
fn emit_output(
|
||||
sound: &str,
|
||||
@@ -765,7 +817,7 @@ fn emit_output(
|
||||
pairs.push(("delaytime".into(), step_duration.to_string()));
|
||||
}
|
||||
for pair in &mut pairs {
|
||||
if TEMPO_SCALED_PARAMS.contains(&pair.0.as_str()) {
|
||||
if is_tempo_scaled_param(&pair.0) {
|
||||
if let Ok(val) = pair.1.parse::<f64>() {
|
||||
pair.1 = (val * step_duration).to_string();
|
||||
}
|
||||
@@ -853,11 +905,11 @@ fn format_cmd(pairs: &[(String, String)]) -> String {
|
||||
format!("/{}", parts.join("/"))
|
||||
}
|
||||
|
||||
fn resolve_cycling(val: &Value, emit_idx: usize) -> Value {
|
||||
fn resolve_cycling(val: &Value, emit_idx: usize) -> Cow<'_, Value> {
|
||||
match val {
|
||||
Value::CycleList(items) if !items.is_empty() => {
|
||||
items[emit_idx % items.len()].clone()
|
||||
Cow::Owned(items[emit_idx % items.len()].clone())
|
||||
}
|
||||
other => other.clone(),
|
||||
other => Cow::Borrowed(other),
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user