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}