ffmml/
channel.rs

1use crate::{
2    commands::Command,
3    comment::{Comment, CommentsOrWhitespaces},
4    oscillators::Oscillator,
5    ParseMusicError,
6};
7use std::{
8    collections::{BTreeMap, BTreeSet},
9    sync::Arc,
10};
11use textparse::{
12    components::{Either, Whitespace},
13    Parse, Parser, Position, Span,
14};
15
16#[derive(Debug, Clone)]
17pub struct Channels(BTreeMap<ChannelName, Channel>);
18
19impl Channels {
20    pub fn new() -> Self {
21        let channels = [
22            (ChannelName::A, Channel::new(Oscillator::pulse_wave())),
23            (ChannelName::B, Channel::new(Oscillator::pulse_wave())),
24            (ChannelName::C, Channel::new(Oscillator::triangle_wave())),
25            (ChannelName::D, Channel::new(Oscillator::noise())),
26        ]
27        .into_iter()
28        .collect();
29        Self(channels)
30    }
31
32    pub fn add_channel(&mut self, name: ChannelName, oscillator: Oscillator) {
33        self.0.insert(name, Channel::new(oscillator));
34    }
35
36    pub fn parse(&mut self, parser: &mut Parser) -> Option<Result<(), ParseMusicError>> {
37        let mut channels: BTreeMap<_, Vec<Command>> =
38            self.0.keys().copied().map(|k| (k, Vec::new())).collect();
39        while !parser.is_eos() {
40            let names = parser.parse::<ChannelNames>()?;
41            if let Some(i) = names.names.iter().position(|n| !channels.contains_key(n)) {
42                let error_position = Position::new(names.start_position().get() + i);
43                return Some(Err(ParseMusicError::new(
44                    error_position,
45                    "undefined channel",
46                )));
47            }
48            let names = names.names;
49
50            let _: Space = parser.parse()?;
51            let _: CommentsOrWhitespaces = parser.parse()?;
52
53            let mut has_space = false;
54            while let Some(command) = parser.parse::<Command>() {
55                for name in &names {
56                    channels
57                        .get_mut(name)
58                        .expect("unreachable")
59                        .push(command.clone());
60                }
61
62                let space: CommentsOrWhitespaces = parser.parse()?;
63                has_space = !space.is_empty();
64            }
65
66            if !has_space && !parser.is_eos() {
67                // Needs spaces before channel names.
68                return None;
69            }
70        }
71        for (key, channel) in &mut self.0 {
72            channel.commands = Arc::new(channels.remove(key).expect("unreachable"));
73        }
74        Some(Ok(()))
75    }
76
77    pub fn iter(&self) -> impl '_ + Iterator<Item = (ChannelName, Channel)> {
78        self.0.iter().map(|(k, v)| (*k, v.clone()))
79    }
80}
81
82/// Channel name.
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
84#[allow(missing_docs)]
85pub enum ChannelName {
86    A,
87    B,
88    C,
89    D,
90    E,
91    F,
92    G,
93    H,
94    I,
95    J,
96    K,
97    L,
98    M,
99    N,
100    O,
101    P,
102    Q,
103    R,
104    S,
105    T,
106    U,
107    V,
108    W,
109    X,
110    Y,
111    Z,
112}
113
114impl ChannelName {
115    fn from_char(c: char) -> Option<Self> {
116        Some(match c {
117            'A' => ChannelName::A,
118            'B' => ChannelName::B,
119            'C' => ChannelName::C,
120            'D' => ChannelName::D,
121            'E' => ChannelName::E,
122            'F' => ChannelName::F,
123            'G' => ChannelName::G,
124            'H' => ChannelName::H,
125            'I' => ChannelName::I,
126            'J' => ChannelName::J,
127            'K' => ChannelName::K,
128            'L' => ChannelName::L,
129            'M' => ChannelName::M,
130            'N' => ChannelName::N,
131            'O' => ChannelName::O,
132            'P' => ChannelName::P,
133            'Q' => ChannelName::Q,
134            'R' => ChannelName::R,
135            'S' => ChannelName::S,
136            'T' => ChannelName::T,
137            'U' => ChannelName::U,
138            'V' => ChannelName::V,
139            'W' => ChannelName::W,
140            'X' => ChannelName::X,
141            'Y' => ChannelName::Y,
142            'Z' => ChannelName::Z,
143            _ => return None,
144        })
145    }
146
147    /// Returns the channel name as `char`.
148    pub const fn as_char(self) -> char {
149        match self {
150            ChannelName::A => 'A',
151            ChannelName::B => 'B',
152            ChannelName::C => 'C',
153            ChannelName::D => 'D',
154            ChannelName::E => 'E',
155            ChannelName::F => 'F',
156            ChannelName::G => 'G',
157            ChannelName::H => 'H',
158            ChannelName::I => 'I',
159            ChannelName::J => 'J',
160            ChannelName::K => 'K',
161            ChannelName::L => 'L',
162            ChannelName::M => 'M',
163            ChannelName::N => 'N',
164            ChannelName::O => 'O',
165            ChannelName::P => 'P',
166            ChannelName::Q => 'Q',
167            ChannelName::R => 'R',
168            ChannelName::S => 'S',
169            ChannelName::T => 'T',
170            ChannelName::U => 'U',
171            ChannelName::V => 'V',
172            ChannelName::W => 'W',
173            ChannelName::X => 'X',
174            ChannelName::Y => 'Y',
175            ChannelName::Z => 'Z',
176        }
177    }
178}
179
180#[derive(Debug, Clone, Span)]
181pub struct ChannelNames {
182    start: Position,
183    names: BTreeSet<ChannelName>,
184    end: Position,
185}
186
187impl ChannelNames {
188    pub fn names(&self) -> &BTreeSet<ChannelName> {
189        &self.names
190    }
191}
192
193impl Parse for ChannelNames {
194    fn parse(parser: &mut Parser) -> Option<Self> {
195        let start = parser.current_position();
196        let mut names = BTreeSet::new();
197        while let Some(name) = parser.peek_char().and_then(ChannelName::from_char) {
198            names.insert(name);
199            parser.read_char();
200        }
201        if names.is_empty() {
202            return None;
203        }
204        let end = parser.current_position();
205        Some(Self { start, names, end })
206    }
207
208    fn name() -> Option<fn() -> String> {
209        Some(|| "channel name".to_owned())
210    }
211}
212
213#[derive(Debug, Clone, Span, Parse)]
214#[parse(name = "a space")]
215struct Space(Either<Whitespace, Comment>);
216
217#[derive(Debug, Clone)]
218pub struct Channel {
219    pub oscillator: Oscillator,
220    pub commands: Arc<Vec<Command>>,
221}
222
223impl Channel {
224    fn new(oscillator: Oscillator) -> Self {
225        Self {
226            oscillator,
227            commands: Arc::new(Vec::new()),
228        }
229    }
230}