Feat: all and noall words
This commit is contained in:
@@ -126,6 +126,9 @@ pub enum Op {
|
||||
ModSlide(u8),
|
||||
ModRnd(u8),
|
||||
ModEnv,
|
||||
// Global params
|
||||
EmitAll,
|
||||
ClearGlobal,
|
||||
// MIDI
|
||||
MidiEmit,
|
||||
GetMidiCC,
|
||||
|
||||
@@ -160,6 +160,7 @@ pub(super) struct CmdRegister {
|
||||
sound: Option<Value>,
|
||||
params: Vec<(&'static str, Value)>,
|
||||
deltas: Vec<Value>,
|
||||
global_params: Vec<(&'static str, Value)>,
|
||||
}
|
||||
|
||||
impl CmdRegister {
|
||||
@@ -168,6 +169,7 @@ impl CmdRegister {
|
||||
sound: None,
|
||||
params: Vec::with_capacity(16),
|
||||
deltas: Vec::with_capacity(4),
|
||||
global_params: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,6 +205,28 @@ impl CmdRegister {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn global_params(&self) -> &[(&'static str, Value)] {
|
||||
&self.global_params
|
||||
}
|
||||
|
||||
pub(super) fn commit_global(&mut self) {
|
||||
self.global_params.append(&mut self.params);
|
||||
self.sound = None;
|
||||
self.deltas.clear();
|
||||
}
|
||||
|
||||
pub(super) fn clear_global(&mut self) {
|
||||
self.global_params.clear();
|
||||
}
|
||||
|
||||
pub fn set_global(&mut self, params: Vec<(&'static str, Value)>) {
|
||||
self.global_params = params;
|
||||
}
|
||||
|
||||
pub fn take_global(&mut self) -> Vec<(&'static str, Value)> {
|
||||
std::mem::take(&mut self.global_params)
|
||||
}
|
||||
|
||||
pub(super) fn clear(&mut self) {
|
||||
self.sound = None;
|
||||
self.params.clear();
|
||||
|
||||
@@ -19,6 +19,7 @@ pub struct Forth {
|
||||
vars: Variables,
|
||||
dict: Dictionary,
|
||||
rng: Rng,
|
||||
global_params: Mutex<Vec<(&'static str, Value)>>,
|
||||
}
|
||||
|
||||
impl Forth {
|
||||
@@ -28,6 +29,7 @@ impl Forth {
|
||||
vars,
|
||||
dict,
|
||||
rng,
|
||||
global_params: Mutex::new(Vec::new()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +41,10 @@ impl Forth {
|
||||
self.stack.lock().clear();
|
||||
}
|
||||
|
||||
pub fn clear_global_params(&self) {
|
||||
self.global_params.lock().clear();
|
||||
}
|
||||
|
||||
pub fn evaluate(&self, script: &str, ctx: &StepContext) -> Result<Vec<String>, String> {
|
||||
let (outputs, var_writes) = self.evaluate_impl(script, ctx, None)?;
|
||||
self.apply_var_writes(var_writes);
|
||||
@@ -102,6 +108,8 @@ impl Forth {
|
||||
let vars_snapshot = self.vars.load_full();
|
||||
let mut var_writes: HashMap<String, Value> = HashMap::new();
|
||||
|
||||
cmd.set_global(self.global_params.lock().clone());
|
||||
|
||||
self.execute_ops(
|
||||
ops,
|
||||
ctx,
|
||||
@@ -113,6 +121,8 @@ impl Forth {
|
||||
&mut var_writes,
|
||||
)?;
|
||||
|
||||
*self.global_params.lock() = cmd.take_global();
|
||||
|
||||
Ok((outputs, var_writes))
|
||||
}
|
||||
|
||||
@@ -214,8 +224,9 @@ impl Forth {
|
||||
_ => 1,
|
||||
};
|
||||
let param_max = cmd
|
||||
.params()
|
||||
.global_params()
|
||||
.iter()
|
||||
.chain(cmd.params().iter())
|
||||
.map(|(_, v)| match v {
|
||||
Value::CycleList(items) => items.len(),
|
||||
_ => 1,
|
||||
@@ -227,7 +238,8 @@ impl Forth {
|
||||
|
||||
let has_arp_list = |cmd: &CmdRegister| -> bool {
|
||||
matches!(cmd.sound(), Some(Value::ArpList(_)))
|
||||
|| cmd.params().iter().any(|(_, v)| matches!(v, Value::ArpList(_)))
|
||||
|| cmd.global_params().iter().chain(cmd.params().iter())
|
||||
.any(|(_, v)| matches!(v, Value::ArpList(_)))
|
||||
};
|
||||
|
||||
let compute_arp_count = |cmd: &CmdRegister| -> usize {
|
||||
@@ -253,15 +265,21 @@ impl Forth {
|
||||
delta_secs: f64,
|
||||
outputs: &mut Vec<String>|
|
||||
-> Result<Option<Value>, String> {
|
||||
let (sound_opt, params) = cmd.snapshot().ok_or("nothing to emit")?;
|
||||
let has_sound = cmd.sound().is_some();
|
||||
let has_params = !cmd.params().is_empty();
|
||||
let has_global = !cmd.global_params().is_empty();
|
||||
if !has_sound && !has_params && !has_global {
|
||||
return Err("nothing to emit".into());
|
||||
}
|
||||
let resolved_sound_val =
|
||||
sound_opt.map(|sv| resolve_value(sv, arp_idx, poly_idx));
|
||||
cmd.sound().map(|sv| resolve_value(sv, arp_idx, poly_idx));
|
||||
let sound_str = match &resolved_sound_val {
|
||||
Some(v) => Some(v.as_str()?.to_string()),
|
||||
None => None,
|
||||
};
|
||||
let resolved_params: Vec<(&str, String)> = params
|
||||
let resolved_params: Vec<(&str, String)> = cmd.global_params()
|
||||
.iter()
|
||||
.chain(cmd.params().iter())
|
||||
.map(|(k, v)| {
|
||||
let resolved = resolve_value(v, arp_idx, poly_idx);
|
||||
if let Value::CycleList(_) | Value::ArpList(_) = v {
|
||||
@@ -1194,6 +1212,37 @@ impl Forth {
|
||||
cmd.clear();
|
||||
}
|
||||
|
||||
Op::EmitAll => {
|
||||
// Retroactive: patch existing sound outputs with current params
|
||||
if !cmd.params().is_empty() {
|
||||
let step_duration = ctx.step_duration();
|
||||
for output in outputs.iter_mut() {
|
||||
if output.starts_with("/sound/") {
|
||||
use std::fmt::Write;
|
||||
for (k, v) in cmd.params() {
|
||||
let val_str = v.to_param_string();
|
||||
if !output.ends_with('/') {
|
||||
output.push('/');
|
||||
}
|
||||
if is_tempo_scaled_param(k) {
|
||||
if let Ok(val) = val_str.parse::<f64>() {
|
||||
let _ = write!(output, "{k}/{}", val * step_duration);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let _ = write!(output, "{k}/{val_str}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Prospective: store for future emits
|
||||
cmd.commit_global();
|
||||
}
|
||||
|
||||
Op::ClearGlobal => {
|
||||
cmd.clear_global();
|
||||
}
|
||||
|
||||
Op::IntRange => {
|
||||
let end = pop_int(stack)?;
|
||||
let start = pop_int(stack)?;
|
||||
|
||||
@@ -94,6 +94,8 @@ pub(super) fn simple_op(name: &str) -> Option<Op> {
|
||||
"loop" => Op::Loop,
|
||||
"oct" => Op::Oct,
|
||||
"clear" => Op::ClearCmd,
|
||||
"all" => Op::EmitAll,
|
||||
"noall" => Op::ClearGlobal,
|
||||
".." => Op::IntRange,
|
||||
".," => Op::StepRange,
|
||||
"gen" => Op::Generate,
|
||||
|
||||
@@ -43,6 +43,26 @@ pub(super) const WORDS: &[Word] = &[
|
||||
compile: Simple,
|
||||
varargs: false,
|
||||
},
|
||||
Word {
|
||||
name: "all",
|
||||
aliases: &[],
|
||||
category: "Sound",
|
||||
stack: "(--)",
|
||||
desc: "Apply current params to all sounds",
|
||||
example: "500 lpf 0.5 verb all",
|
||||
compile: Simple,
|
||||
varargs: false,
|
||||
},
|
||||
Word {
|
||||
name: "noall",
|
||||
aliases: &[],
|
||||
category: "Sound",
|
||||
stack: "(--)",
|
||||
desc: "Clear global params",
|
||||
example: "noall",
|
||||
compile: Simple,
|
||||
varargs: false,
|
||||
},
|
||||
// Sample
|
||||
Word {
|
||||
name: "bank",
|
||||
|
||||
Reference in New Issue
Block a user