1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
mod aot;
mod jit;
mod midi;
use std::hash::Hash;
use crate::{
note::{Note, NoteLetter},
pitch::Ratio,
};
pub use self::{aot::*, jit::*, midi::*};
pub trait TunableSynth {
type Result: IsErr;
type NoteAttr: Clone + Default;
type GlobalAttr;
fn num_channels(&self) -> usize;
fn group_by(&self) -> GroupBy;
fn notes_detune(&mut self, channel: usize, detuned_notes: &[(Note, Ratio)]) -> Self::Result;
fn note_on(&mut self, channel: usize, started_note: Note, attr: Self::NoteAttr)
-> Self::Result;
fn note_off(
&mut self,
channel: usize,
stopped_note: Note,
attr: Self::NoteAttr,
) -> Self::Result;
fn note_attr(
&mut self,
channel: usize,
affected_note: Note,
attr: Self::NoteAttr,
) -> Self::Result;
fn global_attr(&mut self, attr: Self::GlobalAttr) -> Self::Result;
}
pub trait IsErr {
fn is_err(&self) -> bool;
fn ok() -> Self;
}
impl<T: Default, E> IsErr for Result<T, E> {
fn is_err(&self) -> bool {
self.is_err()
}
fn ok() -> Self {
Ok(T::default())
}
}
impl IsErr for () {
fn is_err(&self) -> bool {
false
}
fn ok() -> Self {}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum GroupBy {
Note,
NoteLetter,
Channel,
}
impl GroupBy {
pub fn group(self, note: Note) -> Group {
match self {
GroupBy::Note => Group::Note(note),
GroupBy::NoteLetter => Group::NoteLetter(note.letter_and_octave().0),
GroupBy::Channel => Group::Channel,
}
}
}
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
pub enum Group {
Note(Note),
NoteLetter(NoteLetter),
Channel,
}
impl Group {
pub fn ungroup(self) -> Note {
match self {
Group::Note(note) => note,
Group::NoteLetter(note_letter) => note_letter.in_octave(0),
Group::Channel => Note::from_midi_number(0),
}
}
}