1use std::{
2 any::{Any, TypeId, type_name},
3 collections::BTreeMap,
4 f64,
5 fmt::{Debug, Display},
6 str::FromStr,
7};
8
9use cfg_if::cfg_if;
10use derive_new::new;
11use derive_wrapper::{AsRef, From};
12use fasteval::{Compiler as _, EvalNamespace, Evaler, Instruction, Slab};
13use log::{debug, trace};
14use thiserror::Error;
15
16cfg_if! {
17 if #[cfg(test)] {
18 pub const SAMPLE_RATE: u16 = 10;
20 } else {
21 pub const SAMPLE_RATE: u16 = 48000;
23 }
24}
25
26#[derive(Debug, From, AsRef, Default)]
28pub struct TokenVec(pub(crate) Vec<Box<dyn Token>>);
29
30impl IntoIterator for TokenVec {
31 type Item = Box<dyn Token>;
32 type IntoIter = <Vec<Box<(dyn Token + 'static)>> as IntoIterator>::IntoIter;
33 fn into_iter(self) -> Self::IntoIter {
34 self.0.into_iter()
35 }
36}
37
38impl Token for Box<dyn Token> {
39 fn apply(&self, context: Context) -> Result<Context, CompilerError> {
40 self.as_ref().apply(context)
41 }
42}
43
44impl Type for Box<dyn Token> {
45 fn type_id(&self) -> TypeId {
46 self.as_ref().type_id()
47 }
48}
49
50pub trait Type {
52 fn type_id(&self) -> TypeId;
54}
55
56impl<T> Type for T
57where
58 T: Default + 'static,
59{
60 fn type_id(&self) -> TypeId {
61 <Self as Any>::type_id(&Default::default())
62 }
63}
64
65pub trait Token: Debug + Type {
67 fn apply(&self, context: Context) -> Result<Context, CompilerError>;
69}
70
71#[cfg(test)]
72impl PartialEq for TokenVec {
73 fn eq(&self, other: &Self) -> bool {
74 format!("{self:?}") == format!("{other:?}")
75 }
76}
77
78#[derive(Debug, Clone, Copy, Default)]
80#[cfg_attr(test, derive(PartialEq))]
81pub struct Silence;
82
83impl Token for Silence {
84 fn apply(&self, context: Context) -> Result<Context, CompilerError> {
85 debug!("⚡ {}", type_name::<Self>());
86 let (mut context, mut next) = context.render(None)?;
87 context.result.append(&mut next);
88 Ok(context)
89 }
90}
91
92#[derive(Debug, Clone, Copy, Default)]
94#[cfg_attr(test, derive(PartialEq))]
95pub struct Marker;
96
97impl Token for Marker {
98 fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
99 debug!("⚡ {}", type_name::<Self>());
100 context.result.clear();
101 Ok(context)
102 }
103}
104
105#[derive(Debug, Clone, Copy, Default)]
107#[cfg_attr(test, derive(PartialEq))]
108pub struct Note(pub u8);
109
110impl Token for Note {
111 fn apply(&self, context: Context) -> Result<Context, CompilerError> {
112 debug!("⚡ {}", type_name::<Self>());
113 let (mut context, mut next) = context.render(Some(self.0))?;
114 context.result.append(&mut next);
115 Ok(context)
116 }
117}
118
119#[derive(Debug, Clone, Default)]
121#[cfg_attr(test, derive(PartialEq))]
122pub struct VariableChange(pub char, pub Expression);
123
124impl AsRef<VariableChange> for VariableChange {
125 fn as_ref(&self) -> &VariableChange {
126 self
127 }
128}
129
130impl Token for VariableChange {
131 fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
132 debug!("⚡ {}", type_name::<Self>());
133 *context.get_mut(self.0.to_string())? = context.eval(self.1.as_ref())?;
134 Ok(context)
135 }
136}
137
138#[derive(Debug, Default)]
140#[cfg_attr(test, derive(PartialEq))]
141pub struct Loop(pub LoopCount, pub TokenVec);
142
143#[derive(Debug)]
145#[cfg_attr(test, derive(PartialEq))]
146pub enum LoopCount {
147 Litteral(usize),
149 Variable(char),
151}
152
153impl Default for LoopCount {
154 fn default() -> Self {
155 LoopCount::Litteral(2)
156 }
157}
158
159impl Token for Loop {
160 fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
161 debug!("⚡ {}", type_name::<Self>());
162 let mut old_result = context.result.clone();
163 let count = match self.0 {
164 LoopCount::Litteral(n) => n,
165 LoopCount::Variable(v) => *context.get(v.to_string())? as usize,
166 };
167 context.result.clear();
168 let new_context = self
169 .1
170 .0
171 .iter()
172 .try_fold(context, |context, t| t.apply(context))?;
173 old_result.append(&mut new_context.result.repeat(count));
174 Ok(Context {
175 result: old_result,
176 ..new_context
177 })
178 }
179}
180
181#[derive(Debug, Default)]
183#[cfg_attr(test, derive(PartialEq))]
184pub struct Tuplet(pub TokenVec);
185
186impl Token for Tuplet {
187 fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
188 debug!("⚡ {}", type_name::<Self>());
189 if self.0.as_ref().is_empty() {
190 return Err(CompilerError::Nilplet);
191 }
192 let mut old_result = context.result.clone();
193 context.result.clear();
194 let mut new_context = self
195 .0
196 .0
197 .iter()
198 .try_fold(context, |context, t| t.apply(context))?;
199 let len = new_context.result.len();
200 new_context.result = new_context
201 .result
202 .into_iter()
203 .step_by(
204 len / self
205 .0
206 .0
207 .iter()
208 .filter(|t| {
209 t.as_ref().type_id() == Type::type_id(&Note(0u8))
210 || t.as_ref().type_id() == Type::type_id(&Silence)
211 })
212 .count(),
213 )
214 .collect();
215 old_result.append(&mut new_context.result);
216 Ok(Context {
217 result: old_result,
218 ..new_context
219 })
220 }
221}
222
223#[derive(Debug, new, Default)]
225#[cfg_attr(test, derive(PartialEq))]
226pub struct Slope(pub VariableChange, pub TokenVec);
227
228impl Token for Slope {
229 fn apply(&self, mut context: Context) -> Result<Context, CompilerError> {
230 debug!("⚡ {}", type_name::<Self>());
231 context.slopes.push((
232 self.0.as_ref().0.to_string(),
233 self.0.as_ref().1.as_ref().clone(),
234 ));
235 context = self
236 .1
237 .0
238 .iter()
239 .try_fold(context, |context, t| t.apply(context))?;
240 context.slopes.pop();
241 Ok(context)
242 }
243}
244
245#[derive(Debug, new, Default)]
247pub struct Expression {
248 from: String,
250 pub(crate) instruction: Instruction,
252 pub(crate) slab: Slab,
254}
255
256impl AsRef<Expression> for Expression {
257 fn as_ref(&self) -> &Expression {
258 self
259 }
260}
261
262impl Clone for Expression {
263 fn clone(&self) -> Self {
264 self.from
265 .parse()
266 .unwrap_or_else(|_| panic!("expression {self:?} have an invalid from"))
267 }
268}
269
270impl PartialEq for Expression {
271 fn eq(&self, other: &Self) -> bool {
272 format!("{self:?}") == format!("{other:?}")
273 }
274}
275
276impl FromStr for Expression {
277 type Err = fasteval::Error;
278 fn from_str(s: &str) -> Result<Self, Self::Err> {
279 let mut slab = Slab::new();
280 let instruction = fasteval::Parser::new()
281 .parse(s, &mut slab.ps)?
282 .from(&slab.ps)
283 .compile(&slab.ps, &mut slab.cs);
284 Ok(Expression::new(
285 s.trim_start().trim_end().to_string(),
286 instruction,
287 slab,
288 ))
289 }
290}
291
292impl Display for Expression {
293 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
294 Display::fmt(&self.from, f)
295 }
296}
297
298#[derive(Debug, Clone, new)]
300#[cfg_attr(test, derive(PartialEq))]
301pub struct Context {
302 note_length_variable: String,
303 note_index_variable: String,
304 #[new(default)]
306 pub result: Vec<f64>,
307 #[new(into_iter = "(String, f64)")]
309 pub variables: BTreeMap<String, f64>,
310 pub instrument: Expression,
312 #[new(into_iter = "(String, Expression)")]
314 pub slopes: Vec<(String, Expression)>,
315}
316
317#[derive(Debug, Error)]
319#[cfg_attr(test, derive(PartialEq))]
320#[error("variable not found: {0}")]
321pub struct VariableNotFoundError(String);
322
323#[derive(Debug, Error)]
325#[cfg_attr(test, derive(PartialEq))]
326#[error("expression not found: {0}")]
327pub struct SlopeNotFoundError(String);
328
329#[derive(Debug, Error)]
331#[cfg_attr(test, derive(PartialEq))]
332pub enum CompilerError {
333 #[error("expression evaluation: {0:?}")]
335 FastEval(#[from] fasteval::Error),
336 #[error(transparent)]
338 VariableNotFound(#[from] VariableNotFoundError),
339 #[error(transparent)]
341 SlopeNotFound(#[from] SlopeNotFoundError),
342 #[error(
344 "🎉 You successfully made a nilplet / noplet (and I don't know what to do with it)\nTo resume compilation, remove any occurrence of \"[]\" in your sheet music."
345 )]
346 Nilplet,
347}
348
349impl Context {
350 pub fn current_length(self) -> Result<(Self, f64), CompilerError> {
352 let Context {
353 note_length_variable,
354 note_index_variable,
355 result,
356 mut variables,
357 instrument,
358 slopes,
359 } = self;
360 let mut slopes_iter = slopes
361 .iter()
362 .filter_map(|(c, e)| (c == ¬e_length_variable).then_some(e))
363 .peekable();
364 if slopes_iter.peek().is_none() {
365 return Err(SlopeNotFoundError(note_length_variable.clone()).into());
366 }
367 for slope in slopes_iter {
368 *variables
369 .get_mut(¬e_length_variable)
370 .ok_or(VariableNotFoundError(note_length_variable.clone()))? =
371 slope.instruction.eval(&slope.slab, &mut variables)?;
372 }
373 let note_length = *variables
374 .get(¬e_length_variable)
375 .ok_or(VariableNotFoundError(note_length_variable.clone()))?;
376 Ok((
377 Context {
378 note_length_variable,
379 note_index_variable,
380 result,
381 variables,
382 instrument,
383 slopes,
384 },
385 note_length,
386 ))
387 }
388
389 pub fn get(&self, name: impl AsRef<str> + Into<String>) -> Result<&f64, VariableNotFoundError> {
391 self.variables
392 .get(name.as_ref())
393 .ok_or(VariableNotFoundError(name.into()))
394 }
395
396 pub fn get_mut(
398 &mut self,
399 name: impl AsRef<str> + Into<String>,
400 ) -> Result<&mut f64, VariableNotFoundError> {
401 self.variables
402 .get_mut(name.as_ref())
403 .ok_or(VariableNotFoundError(name.into()))
404 }
405
406 pub fn get_slopes_for(
408 &self,
409 var: impl for<'a> PartialEq<&'a String> + Into<String>,
410 ) -> Result<Vec<&Expression>, SlopeNotFoundError> {
411 let result: Vec<&Expression> = self
412 .slopes
413 .iter()
414 .filter_map(|(c, e)| (var == c).then_some(e))
415 .collect();
416 if result.is_empty() {
417 Err(SlopeNotFoundError(var.into()))
418 } else {
419 Ok(result)
420 }
421 }
422
423 fn tick(mut self) -> Result<Self, CompilerError> {
424 *self.get_mut("t")? += 1f64 / (SAMPLE_RATE as f64);
425 let Context {
426 note_length_variable,
427 note_index_variable,
428 result,
429 mut variables,
430 instrument,
431 slopes,
432 } = self;
433 for (var, expr) in slopes.iter() {
434 *variables
435 .get_mut(var)
436 .ok_or(VariableNotFoundError(var.clone()))? =
437 expr.instruction.eval(&expr.slab, &mut variables)?;
438 }
439 Ok(Context {
440 note_length_variable,
441 note_index_variable,
442 result,
443 variables,
444 instrument,
445 slopes,
446 })
447 }
448
449 pub fn eval(&mut self, expr: &Expression) -> Result<f64, fasteval::Error> {
451 Self::eval_with(expr, &mut self.variables)
452 }
453
454 pub fn eval_with(
456 Expression {
457 from,
458 instruction,
459 slab,
460 }: &Expression,
461 ns: &mut impl EvalNamespace,
462 ) -> Result<f64, fasteval::Error> {
463 instruction
464 .eval(slab, ns)
465 .inspect(|ok| trace!("{from} = {ok}"))
466 .inspect_err(|e| trace!("{from} = {e}"))
467 }
468
469 pub fn render(mut self, n: Option<u8>) -> Result<(Self, Vec<f64>), CompilerError> {
471 let curr_t = *self.get("t")?;
472 if let Some(note) = n {
473 let mut result = Vec::new();
474 self.variables
475 .insert(self.note_index_variable.clone(), note as f64);
476 while {
477 let (new_self, length) = self.current_length()?;
478 self = new_self;
479 length
480 } > *self.get("t")? - curr_t + (1f64 / SAMPLE_RATE as f64)
481 {
482 result.push(Self::eval_with(&self.instrument, &mut self.variables)?);
483 self = self.tick()?;
484 }
485 Ok((self, result))
486 } else {
487 while {
488 let (new_self, length) = self.current_length()?;
489 self = new_self;
490 length
491 } > *self.get("t")? - curr_t
492 {
493 self = self.tick()?;
494 }
495 let len = (*self.get("t")? - curr_t) * SAMPLE_RATE as f64;
496 Ok((self, vec![0.0; len as usize]))
497 }
498 }
499
500 pub fn finalize(self) -> Vec<f64> {
502 self.result
503 }
504}
505
506#[derive(From)]
508#[cfg_attr(test, derive(Debug, PartialEq))]
509pub struct Compiler(Context);
510
511impl Compiler {
512 pub fn step(self, token: impl Token) -> Result<Self, CompilerError> {
514 token.apply(self.0).map(Into::into)
515 }
516 fn apply_all(
517 self,
518 tokens: impl IntoIterator<Item = impl Token>,
519 ) -> Result<Self, CompilerError> {
520 tokens
521 .into_iter()
522 .try_fold(self, |acc, token| acc.step(token))
523 }
524 pub fn compile_all(
526 self,
527 tokens: impl IntoIterator<Item = impl Token>,
528 ) -> Result<Vec<f64>, CompilerError> {
529 self.apply_all(tokens).map(|c| c.0).map(Context::finalize)
530 }
531}
532
533#[cfg(test)]
534mod tests {
535 use crate::compiler::{Compiler, Expression, Note, SAMPLE_RATE, Silence};
536
537 use super::{CompilerError, Context};
538
539 #[test]
540 fn expression_is_clone() {
541 let expr: Expression = "1 + 5 / x".parse().unwrap();
542 assert_eq!(expr, expr.clone());
543 }
544
545 fn context_generator() -> Context {
546 Context::new(
547 'L'.to_string(),
548 'n'.to_string(),
549 [
550 ('a', 5.0),
551 ('t', 0.0),
552 ('n', 0.0),
553 ('N', 12.0),
554 ('L', 0.0),
555 ('l', 4.0),
556 ('T', 60.0),
557 ]
558 .map(|(c, f)| (c.to_string(), f)),
559 "sin(2*pi()*(442+442*((n+1)/N))*t)".parse().unwrap(),
560 [('L', "2^(2-log(2, l))*(60/T)")].map(|(c, e)| (c.to_string(), e.parse().unwrap())),
561 )
562 }
563
564 #[test]
565 fn silence_renders_correct_amount_of_samples() -> Result<(), CompilerError> {
566 assert_eq!(
567 SAMPLE_RATE as usize,
568 Compiler::from(context_generator())
569 .apply_all(vec![Silence])?
570 .0
571 .result
572 .len()
573 );
574 Ok(())
575 }
576
577 #[test]
578 fn silence_renders_zeros() -> Result<(), CompilerError> {
579 assert!(
580 Compiler::from(context_generator())
581 .apply_all(vec![Silence])?
582 .0
583 .result
584 .into_iter()
585 .all(|s| s == 0f64)
586 );
587 Ok(())
588 }
589
590 #[test]
591 fn note_renders_correct_amount_of_samples() -> Result<(), CompilerError> {
592 assert_eq!(
593 SAMPLE_RATE as usize,
594 Compiler::from(context_generator())
595 .apply_all(vec![Note(2)])?
596 .0
597 .result
598 .len()
599 );
600 Ok(())
601 }
602
603 #[test]
604 fn reproducible_note() -> Result<(), CompilerError> {
605 let note = Note(3);
606 let mut compiler = Compiler::from(context_generator());
607
608 compiler = compiler.step(note)?;
609 let first = compiler.0.result.clone();
610
611 *compiler.0.get_mut('t'.to_string())? = 0.0;
612 compiler.0.result.clear();
613 compiler = compiler.step(note)?;
614 let second = compiler.0.result.clone();
615
616 assert_eq!(first, second);
617 Ok(())
618 }
619}