1use crate::{atom, Pattern, Rational};
4
5pub type Controls = std::collections::BTreeMap<String, Value>;
7
8pub const SOUND: &str = "s";
10pub const NOTE: &str = "n";
11
12#[derive(Clone, Debug, PartialEq)]
14pub enum Value {
15 String(String),
16 F64(f64),
17 Rational(Rational),
18}
19
20impl From<Rational> for Value {
21 fn from(r: Rational) -> Self {
22 Self::Rational(r)
23 }
24}
25
26impl From<f64> for Value {
27 fn from(f: f64) -> Self {
28 Self::F64(f)
29 }
30}
31
32impl From<String> for Value {
33 fn from(s: String) -> Self {
34 Self::String(s)
35 }
36}
37
38impl std::fmt::Display for Value {
39 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
40 match self {
41 Value::String(val) => val.fmt(f),
42 Value::Rational(val) => val.fmt(f),
43 Value::F64(val) => val.fmt(f),
44 }
45 }
46}
47
48pub fn sound<P>(pattern: P) -> impl Pattern<Value = Controls>
50where
51 P: 'static + Pattern,
52 P::Value: Clone + Into<String>,
53{
54 let f = |s: P::Value| std::iter::once((SOUND.to_string(), Value::String(s.into()))).collect();
55 pattern.app(atom(f))
56}
57
58pub fn note<P>(pattern: P) -> impl Pattern<Value = Controls>
60where
61 P: 'static + Pattern<Value = f64>,
62{
63 let f = |n| std::iter::once((NOTE.to_string(), Value::F64(n))).collect();
64 pattern.app(atom(f))
65}