1use std::collections::BTreeSet;
2
3use sim_kernel::{Expr, Symbol};
4use sim_lib_stream_core::RateContract;
5
6use crate::{LaneDescriptor, LaneKind};
7
8const DESCRIPTOR_NS: &str = "music/component-descriptor";
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
16pub enum MusicCapability {
17 Playable,
19 Player,
21 Modulator,
23 Oscillator,
25 PerformanceSource,
27 Renderable,
29}
30
31impl MusicCapability {
32 pub fn wire_label(self) -> &'static str {
43 match self {
44 Self::Playable => "playable",
45 Self::Player => "player",
46 Self::Modulator => "modulator",
47 Self::Oscillator => "oscillator",
48 Self::PerformanceSource => "performance-source",
49 Self::Renderable => "renderable",
50 }
51 }
52
53 pub fn symbol(self) -> Symbol {
55 Symbol::qualified("music/capability", self.wire_label())
56 }
57}
58
59#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
64pub enum MusicComponentCategory {
65 PlayerFamily,
67 Instrument,
69 Control,
71}
72
73impl MusicComponentCategory {
74 pub fn wire_label(self) -> &'static str {
76 match self {
77 Self::PlayerFamily => "player-family",
78 Self::Instrument => "instrument",
79 Self::Control => "control",
80 }
81 }
82
83 pub fn symbol(self) -> Symbol {
85 Symbol::qualified("music/component-category", self.wire_label())
86 }
87}
88
89#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
94pub enum MusicPortDirection {
95 Input,
97 Output,
99 Sidechain,
101}
102
103impl MusicPortDirection {
104 pub fn wire_label(self) -> &'static str {
106 match self {
107 Self::Input => "input",
108 Self::Output => "output",
109 Self::Sidechain => "sidechain",
110 }
111 }
112
113 pub fn symbol(self) -> Symbol {
115 Symbol::qualified("music/port-direction", self.wire_label())
116 }
117}
118
119#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
124pub enum MusicUnit {
125 None,
127 Beats,
129 Ticks,
131 Percent,
133 Semitone,
135 Hertz,
137}
138
139impl MusicUnit {
140 pub fn wire_label(self) -> &'static str {
151 match self {
152 Self::None => "none",
153 Self::Beats => "beats",
154 Self::Ticks => "ticks",
155 Self::Percent => "percent",
156 Self::Semitone => "semitone",
157 Self::Hertz => "hertz",
158 }
159 }
160
161 pub fn symbol(self) -> Symbol {
163 Symbol::qualified("music/unit", self.wire_label())
164 }
165}
166
167#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
172pub enum DeterminismPolicy {
173 Deterministic,
175 Seeded,
177 LiveInput,
179}
180
181impl DeterminismPolicy {
182 pub fn wire_label(self) -> &'static str {
184 match self {
185 Self::Deterministic => "deterministic",
186 Self::Seeded => "seeded",
187 Self::LiveInput => "live-input",
188 }
189 }
190
191 pub fn symbol(self) -> Symbol {
193 Symbol::qualified("music/determinism", self.wire_label())
194 }
195}
196
197#[derive(Clone, Debug, PartialEq, Eq)]
199pub struct MusicPortDescriptor {
200 pub id: Symbol,
202 pub label: String,
204 pub direction: MusicPortDirection,
206 pub rate: RateContract,
208 pub accepted_event_families: Vec<LaneKind>,
210 pub output_families: Vec<LaneKind>,
212}
213
214impl MusicPortDescriptor {
215 pub fn new(
217 id: Symbol,
218 label: impl Into<String>,
219 direction: MusicPortDirection,
220 rate: RateContract,
221 ) -> Self {
222 Self {
223 id,
224 label: label.into(),
225 direction,
226 rate,
227 accepted_event_families: Vec::new(),
228 output_families: Vec::new(),
229 }
230 }
231
232 pub fn with_events(mut self, accepted: Vec<LaneKind>, output: Vec<LaneKind>) -> Self {
234 self.accepted_event_families = stable_lane_kinds(accepted);
235 self.output_families = stable_lane_kinds(output);
236 self
237 }
238
239 pub fn to_expr(&self) -> Expr {
241 Expr::Map(vec![
242 field("id", Expr::Symbol(self.id.clone())),
243 field("label", Expr::String(self.label.clone())),
244 field("direction", Expr::Symbol(self.direction.symbol())),
245 field("rate", rate_expr(self.rate)),
246 field("accepted", lane_kind_list(&self.accepted_event_families)),
247 field("output", lane_kind_list(&self.output_families)),
248 ])
249 }
250}
251
252#[derive(Clone, Debug, PartialEq, Eq)]
254pub struct MusicParamDescriptor {
255 pub id: Symbol,
257 pub label: String,
259 pub unit: MusicUnit,
261 pub rate: RateContract,
263 pub default: Expr,
265}
266
267impl MusicParamDescriptor {
268 pub fn new(
270 id: Symbol,
271 label: impl Into<String>,
272 unit: MusicUnit,
273 rate: RateContract,
274 default: Expr,
275 ) -> Self {
276 Self {
277 id,
278 label: label.into(),
279 unit,
280 rate,
281 default,
282 }
283 }
284
285 pub fn to_expr(&self) -> Expr {
287 Expr::Map(vec![
288 field("id", Expr::Symbol(self.id.clone())),
289 field("label", Expr::String(self.label.clone())),
290 field("unit", Expr::Symbol(self.unit.symbol())),
291 field("rate", rate_expr(self.rate)),
292 field("default", self.default.clone()),
293 ])
294 }
295}
296
297#[derive(Clone, Debug, PartialEq, Eq)]
304pub struct MusicComponentDescriptor {
305 pub id: Symbol,
307 pub label: String,
309 pub category: MusicComponentCategory,
311 pub capabilities: BTreeSet<MusicCapability>,
313 pub ports: Vec<MusicPortDescriptor>,
315 pub lanes: Vec<LaneDescriptor>,
317 pub params: Vec<MusicParamDescriptor>,
319 pub rate: RateContract,
321 pub determinism: DeterminismPolicy,
323 pub accepted_event_families: Vec<LaneKind>,
325 pub output_families: Vec<LaneKind>,
327 pub latency: Symbol,
329 pub implemented: bool,
331}
332
333impl MusicComponentDescriptor {
334 pub fn new(
339 id: Symbol,
340 label: impl Into<String>,
341 category: MusicComponentCategory,
342 rate: RateContract,
343 ) -> Self {
344 let latency = rate.latency_class().symbol();
345 Self {
346 id,
347 label: label.into(),
348 category,
349 capabilities: BTreeSet::new(),
350 ports: Vec::new(),
351 lanes: Vec::new(),
352 params: Vec::new(),
353 rate,
354 determinism: DeterminismPolicy::Deterministic,
355 accepted_event_families: Vec::new(),
356 output_families: Vec::new(),
357 latency,
358 implemented: true,
359 }
360 }
361
362 pub fn with_capability(mut self, capability: MusicCapability) -> Self {
364 self.capabilities.insert(capability);
365 self
366 }
367
368 pub fn with_port(mut self, port: MusicPortDescriptor) -> Self {
370 self.ports.push(port);
371 self.ports.sort_by(|left, right| left.id.cmp(&right.id));
372 self
373 }
374
375 pub fn with_lane(mut self, lane: LaneDescriptor) -> Self {
377 self.lanes.push(lane);
378 self.lanes = crate::stable_lane_order(self.lanes);
379 self
380 }
381
382 pub fn with_param(mut self, param: MusicParamDescriptor) -> Self {
384 self.params.push(param);
385 self.params.sort_by(|left, right| left.id.cmp(&right.id));
386 self
387 }
388
389 pub fn with_events(mut self, accepted: Vec<LaneKind>, output: Vec<LaneKind>) -> Self {
391 self.accepted_event_families = stable_lane_kinds(accepted);
392 self.output_families = stable_lane_kinds(output);
393 self
394 }
395
396 pub fn with_determinism(mut self, determinism: DeterminismPolicy) -> Self {
398 self.determinism = determinism;
399 self
400 }
401
402 pub fn with_implemented(mut self, implemented: bool) -> Self {
404 self.implemented = implemented;
405 self
406 }
407
408 pub fn has_capability(&self, capability: MusicCapability) -> bool {
410 self.capabilities.contains(&capability)
411 }
412
413 pub fn to_expr(&self) -> Expr {
415 Expr::Map(vec![
416 field("id", Expr::Symbol(self.id.clone())),
417 field("label", Expr::String(self.label.clone())),
418 field("category", Expr::Symbol(self.category.symbol())),
419 field(
420 "capabilities",
421 Expr::Vector(
422 self.capabilities
423 .iter()
424 .map(|capability| Expr::Symbol(capability.symbol()))
425 .collect(),
426 ),
427 ),
428 field(
429 "ports",
430 Expr::Vector(
431 self.ports
432 .iter()
433 .map(MusicPortDescriptor::to_expr)
434 .collect(),
435 ),
436 ),
437 field(
438 "lanes",
439 Expr::Vector(self.lanes.iter().map(lane_expr).collect()),
440 ),
441 field(
442 "params",
443 Expr::Vector(
444 self.params
445 .iter()
446 .map(MusicParamDescriptor::to_expr)
447 .collect(),
448 ),
449 ),
450 field("rate", rate_expr(self.rate)),
451 field("determinism", Expr::Symbol(self.determinism.symbol())),
452 field("accepted", lane_kind_list(&self.accepted_event_families)),
453 field("output", lane_kind_list(&self.output_families)),
454 field("latency", Expr::Symbol(self.latency.clone())),
455 field("implemented", Expr::Bool(self.implemented)),
456 ])
457 }
458}
459
460fn stable_lane_kinds(mut kinds: Vec<LaneKind>) -> Vec<LaneKind> {
461 kinds.sort();
462 kinds.dedup();
463 kinds
464}
465
466fn lane_kind_list(kinds: &[LaneKind]) -> Expr {
467 Expr::Vector(
468 kinds
469 .iter()
470 .map(|kind| Expr::Symbol(kind.symbol()))
471 .collect(),
472 )
473}
474
475fn lane_expr(lane: &LaneDescriptor) -> Expr {
476 Expr::Map(vec![
477 field("id", Expr::String(lane.id.0.clone())),
478 field("kind", Expr::Symbol(lane.kind.symbol())),
479 field("target", Expr::Symbol(lane.target.symbol())),
480 field("order", Expr::String(lane.order.to_string())),
481 ])
482}
483
484pub(crate) fn rate_expr(rate: RateContract) -> Expr {
485 Expr::Map(vec![
486 field("clock-domain", Expr::Symbol(rate.clock_domain().symbol())),
487 field("latency-class", Expr::Symbol(rate.latency_class().symbol())),
488 field(
489 "nominal-rate-hz",
490 Expr::String(
491 rate.nominal_rate_hz()
492 .map(|rate| rate.to_string())
493 .unwrap_or_else(|| "none".to_owned()),
494 ),
495 ),
496 ])
497}
498
499fn field(name: &'static str, value: Expr) -> (Expr, Expr) {
500 (Expr::Symbol(Symbol::qualified(DESCRIPTOR_NS, name)), value)
501}