1use std::collections::BTreeMap;
2
3use sim_kernel::{Error, Expr, Result, Symbol};
4
5use crate::{
6 MusicCapability, MusicComponentDescriptor, arpeggio_lab_player_descriptor,
7 automation_curve_modulator_descriptor, bassline_player_descriptor, beat_map_player_descriptor,
8 chord_sequencer_player_descriptor, default_instrument_descriptor,
9 drum_key_map_player_descriptor, dual_arpeggio_player_descriptor, envelope_modulator_descriptor,
10 euclid_player_descriptor, keyboard_performance_source_descriptor, lfo_modulator_descriptor,
11 note_echo_player_descriptor, oscillator_modulator_descriptor,
12 pattern_mutator_player_descriptor, polystep_player_descriptor, quad_note_player_descriptor,
13 random_walk_modulator_descriptor, scales_chords_player_descriptor, tempo_lfo_descriptor,
14};
15
16#[derive(Clone, Debug, PartialEq, Eq)]
21pub struct MusicComponentRegistryEntry {
22 descriptor: MusicComponentDescriptor,
23}
24
25impl MusicComponentRegistryEntry {
26 pub fn new(descriptor: MusicComponentDescriptor) -> Self {
28 Self { descriptor }
29 }
30
31 pub fn id(&self) -> &Symbol {
33 &self.descriptor.id
34 }
35
36 pub fn descriptor(&self) -> &MusicComponentDescriptor {
38 &self.descriptor
39 }
40
41 pub fn has_capability(&self, capability: MusicCapability) -> bool {
43 self.descriptor.has_capability(capability)
44 }
45
46 pub fn to_expr(&self) -> Expr {
48 self.descriptor.to_expr()
49 }
50}
51
52#[derive(Clone, Debug, Default, PartialEq, Eq)]
56pub struct MusicComponentRegistry {
57 entries: BTreeMap<String, MusicComponentRegistryEntry>,
58}
59
60impl MusicComponentRegistry {
61 pub fn new() -> Self {
63 Self::default()
64 }
65
66 pub fn register(&mut self, entry: MusicComponentRegistryEntry) -> Result<()> {
68 let key = entry.id().as_qualified_str();
69 if self.entries.contains_key(&key) {
70 return Err(Error::Eval(format!(
71 "duplicate music component registry id: {key}"
72 )));
73 }
74 self.entries.insert(key, entry);
75 Ok(())
76 }
77
78 pub fn get(&self, id: &Symbol) -> Option<&MusicComponentRegistryEntry> {
80 self.entries.get(&id.as_qualified_str())
81 }
82
83 pub fn entries(&self) -> impl Iterator<Item = &MusicComponentRegistryEntry> {
85 self.entries.values()
86 }
87
88 pub fn by_capability(&self, capability: MusicCapability) -> Vec<&MusicComponentRegistryEntry> {
90 self.entries
91 .values()
92 .filter(|entry| entry.has_capability(capability))
93 .collect()
94 }
95
96 pub fn require_capability(
101 &self,
102 id: &Symbol,
103 capability: MusicCapability,
104 ) -> Result<&MusicComponentRegistryEntry> {
105 let entry = self
106 .get(id)
107 .ok_or_else(|| Error::Eval(format!("music component not registered: {id}")))?;
108 if !entry.has_capability(capability) {
109 return Err(Error::Eval(format!(
110 "music component {id} missing capability {}",
111 capability.wire_label()
112 )));
113 }
114 Ok(entry)
115 }
116
117 pub fn inventory_expr(&self) -> Expr {
119 Expr::Map(vec![
120 (
121 field("tag"),
122 Expr::Symbol(Symbol::qualified("music", "component-registry")),
123 ),
124 (
125 field("entries"),
126 Expr::Vector(
127 self.entries()
128 .map(MusicComponentRegistryEntry::to_expr)
129 .collect(),
130 ),
131 ),
132 ])
133 }
134}
135
136pub fn default_music_component_registry() -> MusicComponentRegistry {
138 let mut registry = MusicComponentRegistry::new();
139 for descriptor in [
140 scales_chords_player_descriptor(),
141 dual_arpeggio_player_descriptor(),
142 arpeggio_lab_player_descriptor(),
143 note_echo_player_descriptor(),
144 beat_map_player_descriptor(),
145 euclid_player_descriptor(),
146 drum_key_map_player_descriptor(),
147 chord_sequencer_player_descriptor(),
148 bassline_player_descriptor(),
149 polystep_player_descriptor(),
150 quad_note_player_descriptor(),
151 pattern_mutator_player_descriptor(),
152 default_instrument_descriptor(),
153 keyboard_performance_source_descriptor(),
154 tempo_lfo_descriptor(),
155 lfo_modulator_descriptor(),
156 envelope_modulator_descriptor(),
157 oscillator_modulator_descriptor(),
158 random_walk_modulator_descriptor(),
159 automation_curve_modulator_descriptor(),
160 ] {
161 registry
162 .register(MusicComponentRegistryEntry::new(
163 descriptor.expect("default music component descriptors are valid"),
164 ))
165 .expect("default music component registry ids are unique");
166 }
167 registry
168}
169
170pub fn dual_arpeggio_player_id() -> Symbol {
172 Symbol::qualified("music/player-family", "dual-arpeggio")
173}
174
175pub fn arpeggio_lab_player_id() -> Symbol {
177 Symbol::qualified("music/player-family", "arpeggio-lab")
178}
179
180pub fn scales_chords_player_id() -> Symbol {
182 Symbol::qualified("music/player-family", "scales-chords")
183}
184
185pub fn note_echo_player_id() -> Symbol {
187 Symbol::qualified("music/player-family", "note-echo")
188}
189
190pub fn beat_map_player_id() -> Symbol {
192 Symbol::qualified("music/player-family", "beat-map")
193}
194
195pub fn euclid_player_id() -> Symbol {
197 Symbol::qualified("music/player-family", "euclid")
198}
199
200pub fn drum_key_map_player_id() -> Symbol {
202 Symbol::qualified("music/player-family", "drum-key-map")
203}
204
205pub fn chord_sequencer_player_id() -> Symbol {
207 Symbol::qualified("music/player-family", "chord-sequencer")
208}
209
210pub fn bassline_player_id() -> Symbol {
212 Symbol::qualified("music/player-family", "bassline-generator")
213}
214
215pub fn polystep_player_id() -> Symbol {
217 Symbol::qualified("music/player-family", "polystep")
218}
219
220pub fn quad_note_player_id() -> Symbol {
222 Symbol::qualified("music/player-family", "quad-note-generator")
223}
224
225pub fn pattern_mutator_player_id() -> Symbol {
227 Symbol::qualified("music/player-family", "pattern-mutator")
228}
229
230pub fn lfo_modulator_id() -> Symbol {
232 Symbol::qualified("music/modulator", "lfo")
233}
234
235pub fn envelope_modulator_id() -> Symbol {
237 Symbol::qualified("music/modulator", "envelope")
238}
239
240pub fn oscillator_modulator_id() -> Symbol {
242 Symbol::qualified("music/modulator", "oscillator")
243}
244
245pub fn random_walk_modulator_id() -> Symbol {
247 Symbol::qualified("music/modulator", "random-walk")
248}
249
250pub fn automation_curve_modulator_id() -> Symbol {
252 Symbol::qualified("music/modulator", "automation-curve")
253}
254
255fn field(name: &'static str) -> Expr {
256 sim_value::build::qsym("music/component-registry", name)
257}