generalize default variables

This commit is contained in:
brevalferrari 2025-06-02 23:27:51 +02:00
parent bd40b124b0
commit 25f4eb1b13
2 changed files with 21 additions and 7 deletions

View file

@ -1,5 +1,5 @@
mod cli;
use std::io::read_to_string;
use std::{collections::HashMap, io::read_to_string};
use anyhow::{Context as _, anyhow};
use bliplib::{
@ -20,12 +20,17 @@ fn main() -> anyhow::Result<()> {
.context("Failed to find (or use) default audio device")?;
let sink = Sink::try_new(&stream_handle).context("Epic audio playback failure")?;
let default_variables = HashMap::from([('l', 4f64), ('L', 0.0), ('t', 0.0)]);
let parser = Parser::new(
opts.notes(),
opts.slopes()
.map(|(s, (v, e))| (s, VariableChange(*v, e.clone())))
.collect::<Vec<_>>(),
opts.variables().map(|(v, _)| *v).collect::<Vec<_>>(),
opts.variables()
.chain(default_variables.iter())
.map(|(v, _)| *v)
.collect::<Vec<_>>(),
);
let input = read_to_string(opts.input().get()).context("Failed to read input")?;
let tokens = parser
@ -34,7 +39,11 @@ fn main() -> anyhow::Result<()> {
.context("Failed to parse input")?;
let compiler = Compiler::from(Context::new(
opts.variables().map(|(a, b)| (*a, *b)),
'n',
'L',
opts.variables()
.map(|(a, b)| (*a, *b))
.chain(default_variables.into_iter()),
opts.instrument().clone(),
opts.slopes().map(|(_, (a, b))| (*a, b.clone())),
));

View file

@ -266,6 +266,8 @@ impl FromStr for Expression {
#[derive(Clone, new)]
#[cfg_attr(test, derive(Debug, PartialEq))]
pub struct Context {
note_length_variable: char,
note_index_variable: char,
#[new(default)]
pub result: Vec<f64>,
#[new(into_iter = "(char, f64)")]
@ -298,18 +300,19 @@ pub enum CompilerError {
impl Context {
pub fn current_length(&self) -> Result<f64, CompilerError> {
self.get_slopes_for('L')
self.get_slopes_for(self.note_length_variable)
.map_err(CompilerError::from)?
.iter()
.try_fold(
self.clone(),
|mut acc, slope| -> Result<Context, CompilerError> {
// just in case next slopes use L too
*acc.get_mut('L')? = self.eval(slope).map_err(Into::<CompilerError>::into)?;
*acc.get_mut(self.note_length_variable)? =
self.eval(slope).map_err(Into::<CompilerError>::into)?;
Ok(acc)
},
)?
.get('L')
.get(self.note_length_variable)
.map_err(Into::into)
.cloned()
}
@ -377,7 +380,7 @@ impl Context {
if let Some(note) = n {
let mut result = Vec::new();
let mut map = self.namespace_generator().collect::<BTreeMap<_, _>>();
map.insert('n'.to_string(), note as f64);
map.insert(self.note_index_variable.to_string(), note as f64);
while self.current_length()? > *self.get('t')? - curr_t + (1f64 / SAMPLE_RATE as f64) {
result.push(self.eval_with(&self.instrument, &mut map)? * f64::MAX);
self.tick()?;
@ -442,6 +445,8 @@ mod tests {
fn context_generator() -> Context {
Context::new(
'n',
'L',
[
('a', 5.0),
('t', 0.0),