rust_music/phrase.rs
1use crate::Chord;
2use crate::Note;
3use crate::Result;
4
5/// Describes the entries contains in a `Phrase`
6#[derive(Debug, Clone, PartialEq)]
7pub enum PhraseEntry {
8 /// Silent Rest that has a rhythm value (see `constants::rhythm`)
9 Rest(f64),
10 /// A regular single `Note`
11 Note(Note),
12 /// A list of Notes played simultaneously
13 Chord(Chord),
14}
15
16impl PhraseEntry {
17 /// Returns the rhythm value of the entry.
18 /// In case of a Chord, this is the rhythm value specified in Chord::new(),
19 /// not the value of the notes of the Chord.
20 pub fn rhythm(&self) -> f64 {
21 match self {
22 PhraseEntry::Chord(c) => c.rhythm(),
23 PhraseEntry::Note(n) => n.rhythm(),
24 PhraseEntry::Rest(r) => *r,
25 }
26 }
27}
28
29/// Describes a single musical phrase. Multiple Phrases can be stored in a Part.
30/// Phrases can be played in parallel too
31#[derive(Debug, Default, Clone, PartialEq)]
32pub struct Phrase {
33 /// list of entries in the phrase
34 entries: Vec<PhraseEntry>,
35 /// duration of the `Phrase`
36 duration: f64,
37 /// title of the phrase
38 name: String,
39}
40
41impl Phrase {
42 /// Returns a new `Phrase`
43 /// A `Phrase` contains entries that can be either a single `Note`, a `Chord` or a `Rest`
44 /// Entries in a Phrase are played sequentially.
45 pub fn new() -> Phrase {
46 Self::default()
47 }
48
49 /// Returns a new `Phrase` made of the sequential notes from the iterator
50 ///
51 /// # Arguments
52 ///
53 /// * `sequence`: iterator over the sequence of notes. Can be produced with `Note::new_sequence` for example
54 ///
55 /// # Errors
56 ///
57 /// This returns any error that can be found in the iterator entries
58 pub fn from_notes_sequence<N: IntoIterator<Item = Result<Note>>>(sequence: N) -> Result<Self> {
59 let mut duration = 0.;
60 let entries = sequence
61 .into_iter()
62 .map(|r| {
63 r.map(|n| {
64 duration += n.rhythm();
65 PhraseEntry::Note(n)
66 })
67 })
68 .collect::<Result<Vec<_>>>()?;
69 Ok(Self {
70 entries,
71 duration,
72 ..Self::default()
73 })
74 }
75
76 /// Sets a name for the `Phrase`. The name does not have to be unique.
77 pub fn set_name<S: ToString>(&mut self, name: S) {
78 self.name = name.to_string();
79 }
80
81 /// Adds a note to the phrase. It starts after the previous
82 /// entry.
83 pub fn add_note(&mut self, note: Note) {
84 self.duration += note.rhythm();
85 self.entries.push(PhraseEntry::Note(note));
86 }
87
88 /// Adds multiple sequential notes to the phrase
89 /// Each note will be played after the previous one.
90 /// This function will clone the notes into the Phrase's entry Vec
91 pub fn add_sequential_notes<N: IntoIterator<Item = Result<Note>>>(
92 &mut self,
93 notes: N,
94 ) -> Result<()> {
95 for n in notes.into_iter() {
96 self.add_note(n?);
97 }
98 Ok(())
99 }
100
101 /// Adds a chord to the phrase.
102 /// All notes of the Chord will start simultaneously
103 /// but can end at different times depending on their respective
104 /// rhythm values.
105 /// The following `Entry` of the `Phrase` will start at the end
106 /// of this `Chord`'s `rhythm` value, regardless of its inner notes'
107 /// duration.
108 /// Therefore, a `Chord` with a single `Note` (or several) allows to play the next
109 /// notes/chords while the current is still playing, by setting a `rhythm` shorter
110 /// than the notes it contains.
111 pub fn add_chord(&mut self, c: Chord) {
112 self.duration += c.rhythm();
113 self.entries.push(PhraseEntry::Chord(c));
114 }
115
116 /// Adds a rest to the phrase. It starts after the previous entry
117 pub fn add_rest(&mut self, rhythm: f64) {
118 self.duration += rhythm;
119 self.entries.push(PhraseEntry::Rest(rhythm));
120 }
121
122 /// Returns the Phrase's Vec of notes
123 pub fn entries(&self) -> &[PhraseEntry] {
124 self.entries.as_slice()
125 }
126
127 /// Returns the Phrase's name
128 pub fn name(&self) -> &str {
129 self.name.as_str()
130 }
131
132 // Returns the total duration (in beats, i.e. the "rhythm" unit) of the `Phrase`
133 pub fn duration(&self) -> f64 {
134 self.duration
135 }
136}