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
#![warn(nonstandard_style, rust_2018_idioms, future_incompatible)]
use bit_set::BitSet;
pub trait Voice {
type Configuration: ?Sized;
fn note_on(&mut self, _: &Self::Configuration, note_number: u8, velocity: u8);
fn note_off(&mut self, _: &Self::Configuration, velocity: u8);
fn is_running(&self) -> bool;
}
pub struct Manager {
num_voices: usize,
used_voices: Vec<(usize, u8)>,
free_voices: BitSet,
}
impl Manager {
pub fn new(num_voices: usize) -> Manager {
Manager {
num_voices,
used_voices: Vec::with_capacity(num_voices),
free_voices: BitSet::with_capacity(num_voices),
}
}
pub fn note_on<C: Default, V: Voice<Configuration = C>>(
&mut self,
voices: &mut [V],
note_number: u8,
velocity: u8,
) {
self.note_on_with_config(voices, &V::Configuration::default(), note_number, velocity);
}
pub fn note_off<C: Default, V: Voice<Configuration = C>>(
&mut self,
voices: &mut [V],
note_number: u8,
velocity: u8,
) {
self.note_off_with_config(voices, &V::Configuration::default(), note_number, velocity);
}
pub fn note_on_with_config<V: Voice>(
&mut self,
voices: &mut [V],
config: &V::Configuration,
note_number: u8,
velocity: u8,
) {
assert_eq!(voices.iter().len(), self.num_voices);
self.used_voices
.retain(|voice_note| voices[voice_note.0].is_running());
for (i, v) in voices.iter().enumerate() {
if !v.is_running() {
self.free_voices.insert(i);
}
}
let first_free_voice = self.free_voices.iter().next();
if let Some(i) = first_free_voice {
self.free_voices.remove(&i);
voices[i].note_on(config, note_number, velocity);
self.used_voices.push((i, note_number));
}
}
pub fn note_off_with_config<V: Voice>(
&mut self,
voices: &mut [V],
config: &V::Configuration,
note_number: u8,
velocity: u8,
) {
assert_eq!(voices.iter().len(), self.num_voices);
self.used_voices.retain(|voice_note| {
if voice_note.1 != note_number {
true
} else {
if voices[voice_note.0].is_running() {
voices[voice_note.0].note_off(config, velocity);
}
false
}
});
}
}