abc_parser/datatypes/
mod.rs

1//! Structures representing parsed ABC music.
2
3pub mod writer;
4
5#[derive(Clone, Debug, PartialEq)]
6pub struct TuneBook {
7    pub header: Option<FileHeader>,
8    pub tunes: Vec<Tune>,
9}
10impl TuneBook {
11    pub fn new(header: Option<FileHeader>, tunes: Vec<Tune>) -> TuneBook {
12        TuneBook { header, tunes }
13    }
14}
15
16#[derive(Clone, Debug, Eq, PartialEq)]
17pub struct FileHeader {
18    pub info: Vec<InfoField>,
19}
20impl FileHeader {
21    pub fn new(info: Vec<InfoField>) -> FileHeader {
22        FileHeader { info }
23    }
24}
25
26#[derive(Clone, Debug, PartialEq)]
27pub struct Tune {
28    pub header: TuneHeader,
29    pub body: Option<TuneBody>,
30}
31impl Tune {
32    pub fn new(header: TuneHeader, body: Option<TuneBody>) -> Tune {
33        Tune { header, body }
34    }
35}
36
37#[derive(Clone, Debug, Eq, PartialEq)]
38pub struct TuneHeader {
39    pub info: Vec<InfoField>,
40}
41impl TuneHeader {
42    pub fn new(info: Vec<InfoField>) -> TuneHeader {
43        TuneHeader { info }
44    }
45}
46
47#[derive(Clone, Debug, Eq, PartialEq)]
48pub struct InfoField(pub char, pub String);
49impl InfoField {
50    pub fn new(c: char, s: String) -> InfoField {
51        InfoField(c, s)
52    }
53}
54
55#[derive(Clone, Debug, PartialEq)]
56pub struct TuneBody {
57    pub music: Vec<MusicLine>,
58}
59impl TuneBody {
60    pub fn new(music: Vec<MusicLine>) -> TuneBody {
61        TuneBody { music }
62    }
63}
64
65#[derive(Clone, Debug, PartialEq)]
66pub struct MusicLine {
67    pub symbols: Vec<MusicSymbol>,
68}
69impl MusicLine {
70    pub fn new(symbols: Vec<MusicSymbol>) -> MusicLine {
71        MusicLine { symbols }
72    }
73}
74
75#[derive(Clone, Debug, PartialEq)]
76pub enum MusicSymbol {
77    Note {
78        decorations: Vec<Decoration>,
79        accidental: Option<Accidental>,
80        note: Note,
81        octave: i8,
82        length: f32,
83        tie: Option<Tie>,
84    },
85    Chord {
86        decorations: Vec<Decoration>,
87        notes: Vec<MusicSymbol>,
88        length: f32,
89    },
90    GraceNotes {
91        acciaccatura: Option<()>,
92        notes: Vec<MusicSymbol>,
93    },
94    /// An `r` value of 0 indicates that the parser does not have enough information and it must
95    /// be determined from the time signature.
96    Tuplet {
97        p: u32,
98        q: u32,
99        r: u32,
100        notes: Vec<MusicSymbol>,
101    },
102    Bar(String),
103    Rest(Rest),
104    Ending(u32),
105    VisualBreak,
106}
107
108/// A tie which may apply between a note and the following note of the same pitch.
109#[derive(Copy, Clone, Debug, Eq, PartialEq)]
110pub enum Tie {
111    /// A normal tie.
112    Solid,
113    /// A dotted tie.
114    Dotted,
115}
116
117static TUPLET_Q: [u32; 8] = [3, 2, 3, 0, 2, 0, 3, 0];
118impl MusicSymbol {
119    pub fn new_note(
120        decorations: Vec<Decoration>,
121        accidental: Option<Accidental>,
122        note: Note,
123        octave: i8,
124        length: f32,
125        tie: Option<Tie>,
126    ) -> MusicSymbol {
127        MusicSymbol::Note {
128            decorations,
129            accidental,
130            note,
131            octave,
132            length,
133            tie,
134        }
135    }
136
137    pub fn note(note: Note) -> MusicSymbol {
138        MusicSymbol::Note {
139            decorations: vec![],
140            accidental: None,
141            note,
142            octave: 1,
143            length: 1.0,
144            tie: None,
145        }
146    }
147
148    pub fn note_from_length(note: Note, length: f32) -> MusicSymbol {
149        MusicSymbol::Note {
150            decorations: vec![],
151            accidental: None,
152            note,
153            octave: 1,
154            length,
155            tie: None,
156        }
157    }
158
159    /// # Panics
160    /// If the number of notes is not equal to `p`
161    pub fn tuplet_with_defaults(
162        p: u32,
163        q: Option<u32>,
164        r: Option<u32>,
165        notes: Vec<MusicSymbol>,
166    ) -> Result<MusicSymbol, &'static str> {
167        assert_eq!(notes.len(), p as usize);
168
169        Self::new_tuplet(
170            p,
171            q.unwrap_or(TUPLET_Q[(p - 2) as usize]),
172            r.unwrap_or(p),
173            notes,
174        )
175    }
176
177    pub fn new_tuplet(
178        p: u32,
179        q: u32,
180        r: u32,
181        notes: Vec<MusicSymbol>,
182    ) -> Result<MusicSymbol, &'static str> {
183        if p < 2 {
184            return Err("Tuplet too small");
185        }
186        if p > 9 {
187            return Err("Tuplet too large");
188        }
189        if r == 0 {
190            return Err("R can't be 0");
191        }
192
193        Ok(MusicSymbol::Tuplet { p, q, r, notes })
194    }
195}
196
197#[derive(Copy, Clone, Debug, Eq, PartialEq)]
198pub enum Note {
199    C,
200    D,
201    E,
202    F,
203    G,
204    A,
205    B,
206}
207
208impl From<Note> for char {
209    fn from(note: Note) -> Self {
210        match note {
211            Note::C => 'C',
212            Note::D => 'D',
213            Note::E => 'E',
214            Note::F => 'F',
215            Note::G => 'G',
216            Note::A => 'A',
217            Note::B => 'B',
218        }
219    }
220}
221
222#[derive(Clone, Debug, Eq, PartialEq)]
223pub enum Decoration {
224    Staccato,
225    Roll,
226    Fermata,
227    Accent,
228    LowerMordent,
229    Coda,
230    UpperMordent,
231    Segno,
232    Trill,
233    UpBow,
234    DownBow,
235    Unresolved(String),
236}
237
238#[derive(Copy, Clone, Debug, Eq, PartialEq)]
239pub enum Accidental {
240    Natural,
241    Sharp,
242    Flat,
243    DoubleSharp,
244    DoubleFlat,
245}
246
247#[derive(Copy, Clone, Debug, Eq, PartialEq)]
248pub enum Rest {
249    Note(u32),
250    Measure(u32),
251    NoteHidden(u32),
252    MeasureHidden(u32),
253}