1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
use crate::Chord;
use crate::Note;
use crate::Result;

/// Describes the entries contains in a `Phrase`
#[derive(Debug, Clone)]
pub enum PhraseEntry {
    /// Silent Rest that has a rhythm value (see `constants::rhythm`)
    Rest(f64),
    /// A regular single `Note`
    Note(Note),
    /// A list of Notes played simultaneously
    Chord(Chord),
}

impl PhraseEntry {
    /// Returns the rhythm value of the entry.
    /// In case of a Chord, this is the rhythm value specified in Chord::new(),
    /// not the value of the notes of the Chord.
    pub fn rhythm(&self) -> f64 {
        match self {
            PhraseEntry::Chord(c) => c.rhythm(),
            PhraseEntry::Note(n) => n.rhythm(),
            PhraseEntry::Rest(r) => *r,
        }
    }
}

/// Describes a single musical phrase. Multiple Phrases can be stored in a Part.
/// Phrases can be played in parallel too
#[derive(Debug, Default, Clone)]
pub struct Phrase {
    /// list of entries in the phrase
    entries: Vec<PhraseEntry>,
    /// duration of the `Phrase`
    duration: f64,
    /// title of the phrase
    name: String,
}

impl Phrase {
    /// Returns a new `Phrase`
    /// A `Phrase` contains entries that can be either a single `Note`, a `Chord` or a `Rest`
    /// Entries in a Phrase are played sequentially.
    pub fn new() -> Phrase {
        Self::default()
    }

    /// Returns a new `Phrase` made of the sequential notes from the iterator
    ///
    /// # Arguments
    ///
    /// * `sequence`: iterator over the sequence of notes. Can be produced with `Note::new_sequence` for example
    ///
    /// # Errors
    ///
    /// This returns any error that can be found in the iterator entries
    pub fn from_notes_sequence<N: IntoIterator<Item = Result<Note>>>(sequence: N) -> Result<Self> {
        let mut duration = 0.;
        let entries = sequence
            .into_iter()
            .map(|r| {
                r.map(|n| {
                    duration += n.rhythm();
                    PhraseEntry::Note(n)
                })
            })
            .collect::<Result<Vec<_>>>()?;
        Ok(Self {
            entries,
            duration,
            ..Self::default()
        })
    }

    /// Sets a name for the `Phrase`. The name does not have to be unique.
    pub fn set_name<S: ToString>(&mut self, name: S) {
        self.name = name.to_string();
    }

    /// Adds a note to the phrase. It starts after the previous
    /// entry.
    pub fn add_note(&mut self, note: Note) {
        self.duration += note.rhythm();
        self.entries.push(PhraseEntry::Note(note));
    }

    /// Adds multiple sequential notes to the phrase
    /// Each note will be played after the previous one.
    /// This function will clone the notes into the Phrase's entry Vec
    pub fn add_sequential_notes<N: IntoIterator<Item = Result<Note>>>(
        &mut self,
        notes: N,
    ) -> Result<()> {
        for n in notes.into_iter() {
            self.add_note(n?);
        }
        Ok(())
    }

    /// Adds a chord to the phrase.
    /// All notes of the Chord will start simultaneously
    /// but can end at different times depending on their respective
    /// rhythm values.
    /// The following `Entry` of the `Phrase` will start at the end
    /// of this `Chord`'s `rhythm` value, regardless of its inner notes'
    /// duration.
    /// Therefore, a `Chord` with a single `Note` (or several) allows to play the next
    /// notes/chords while the current is still playing, by setting a `rhythm` shorter
    /// than the notes it contains.
    pub fn add_chord(&mut self, c: Chord) {
        self.duration += c.rhythm();
        self.entries.push(PhraseEntry::Chord(c));
    }

    /// Adds a rest to the phrase. It starts after the previous entry
    pub fn add_rest(&mut self, rhythm: f64) {
        self.duration += rhythm;
        self.entries.push(PhraseEntry::Rest(rhythm));
    }

    /// Returns the Phrase's Vec of notes
    pub fn entries(&self) -> &[PhraseEntry] {
        self.entries.as_slice()
    }

    /// Returns the Phrase's name
    pub fn name(&self) -> &str {
        self.name.as_str()
    }

    // Returns the total duration (in beats, i.e. the "rhythm" unit) of the `Phrase`
    pub fn duration(&self) -> f64 {
        self.duration
    }
}