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 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#[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 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}