second_music_system/
lib.rs

1#![allow(clippy::useless_format)] // DELETEME
2
3use std::{
4    cmp::{Ordering, PartialOrd},
5    collections::HashMap,
6    sync::Arc,
7};
8
9use arcow::Arcow;
10use compact_str::{CompactString, ToCompactString};
11use crossbeam::channel::{unbounded, Receiver, Sender};
12
13#[macro_use]
14pub(crate) mod din;
15
16mod data;
17mod delegate;
18mod engine;
19mod fader;
20mod posfloat;
21pub mod query;
22mod reader;
23mod runtime;
24
25#[doc(inline)]
26pub use data::StringOrNumber;
27use data::*;
28#[doc(inline)]
29pub use delegate::*;
30#[doc(inline)]
31pub use engine::*;
32#[doc(inline)]
33pub use fader::*;
34#[doc(inline)]
35pub use posfloat::*;
36#[doc(inline)]
37pub use reader::*;
38#[doc(inline)]
39pub use runtime::*;
40
41/// Encapsulates all the information about a soundtrack: what files to play,
42/// how to play them, etc. This is purely inert data. It can be built up
43/// incrementally, or replaced entirely, cleanly and efficiently.
44#[derive(Clone, Debug)]
45pub struct Soundtrack {
46    flows: Arcow<HashMap<CompactString, Arc<Flow>>>,
47    sequences: Arcow<HashMap<CompactString, Arc<Sequence>>>,
48    sounds: Arcow<HashMap<CompactString, Arc<Sound>>>,
49}
50
51impl Soundtrack {
52    pub fn new() -> Soundtrack {
53        Soundtrack {
54            flows: Arcow::new(HashMap::new()),
55            sequences: Arcow::new(HashMap::new()),
56            sounds: Arcow::new(HashMap::new()),
57        }
58    }
59    pub fn from_source(source: &str) -> Result<Soundtrack, String> {
60        Soundtrack::new().parse_source(source)
61    }
62}
63
64impl Default for Soundtrack {
65    fn default() -> Soundtrack {
66        Soundtrack::new()
67    }
68}
69
70mod private {
71    pub trait Sealed {}
72}
73
74pub trait Sample:
75    private::Sealed + Send + Sync + Copy + Clone + 'static
76{
77    fn to_float_sample(&self) -> f32;
78    fn make_formatted_sound_reader_from(
79        value: Box<dyn SoundReader<Self>>,
80    ) -> FormattedSoundReader;
81}
82
83impl private::Sealed for u8 {}
84impl Sample for u8 {
85    fn to_float_sample(&self) -> f32 {
86        (*self - 128) as f32 * (1.0 / 128.0)
87    }
88    fn make_formatted_sound_reader_from(
89        value: Box<dyn SoundReader<u8>>,
90    ) -> FormattedSoundReader {
91        FormattedSoundReader::U8(value)
92    }
93}
94
95impl private::Sealed for u16 {}
96impl Sample for u16 {
97    fn to_float_sample(&self) -> f32 {
98        (*self - 32768) as f32 * (1.0 / 32768.0)
99    }
100    fn make_formatted_sound_reader_from(
101        value: Box<dyn SoundReader<u16>>,
102    ) -> FormattedSoundReader {
103        FormattedSoundReader::U16(value)
104    }
105}
106
107impl private::Sealed for i8 {}
108impl Sample for i8 {
109    fn to_float_sample(&self) -> f32 {
110        *self as f32 * (1.0 / 128.0)
111    }
112    fn make_formatted_sound_reader_from(
113        value: Box<dyn SoundReader<i8>>,
114    ) -> FormattedSoundReader {
115        FormattedSoundReader::I8(value)
116    }
117}
118
119impl private::Sealed for i16 {}
120impl Sample for i16 {
121    fn to_float_sample(&self) -> f32 {
122        *self as f32 * (1.0 / 32768.0)
123    }
124    fn make_formatted_sound_reader_from(
125        value: Box<dyn SoundReader<i16>>,
126    ) -> FormattedSoundReader {
127        FormattedSoundReader::I16(value)
128    }
129}
130
131impl private::Sealed for f32 {}
132impl Sample for f32 {
133    fn to_float_sample(&self) -> f32 {
134        *self
135    }
136    fn make_formatted_sound_reader_from(
137        value: Box<dyn SoundReader<f32>>,
138    ) -> FormattedSoundReader {
139        FormattedSoundReader::F32(value)
140    }
141}