Skip to main content

music21_rs/
stream.rs

1use crate::{
2    chord::Chord, defaults::FloatType, duration::Duration, error::Result, interval::Interval,
3    note::Note, pitch::Pitch, rest::Rest,
4};
5
6/// A musical object that can live on a timeline.
7#[derive(Clone, Debug)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub enum StreamElement {
10    /// A single pitched note.
11    Note(Note),
12    /// A chord containing one or more notes.
13    Chord(Chord),
14    /// A silent rest.
15    Rest(Rest),
16}
17
18impl StreamElement {
19    /// Returns the assigned duration, if present.
20    pub fn duration(&self) -> Option<&Duration> {
21        match self {
22            Self::Note(note) => note.duration(),
23            Self::Chord(chord) => chord.duration(),
24            Self::Rest(rest) => Some(rest.duration()),
25        }
26    }
27
28    /// Returns the duration in quarter lengths, defaulting to `1.0`.
29    pub fn quarter_length(&self) -> FloatType {
30        self.duration()
31            .map(Duration::quarter_length)
32            .unwrap_or_else(|| Duration::default().quarter_length())
33    }
34
35    /// Returns all pitches contained by this element.
36    pub fn pitches(&self) -> Vec<Pitch> {
37        match self {
38            Self::Note(note) => vec![note.pitch().clone()],
39            Self::Chord(chord) => chord.pitches(),
40            Self::Rest(_) => Vec::new(),
41        }
42    }
43
44    /// Returns a transposed copy.
45    pub fn transpose(&self, interval: &Interval) -> Result<Self> {
46        match self {
47            Self::Note(note) => {
48                let mut out = note.clone();
49                out._pitch = interval.transpose_pitch(note.pitch())?;
50                Ok(Self::Note(out))
51            }
52            Self::Chord(chord) => {
53                let pitches = chord
54                    .pitches()
55                    .iter()
56                    .map(|pitch| interval.transpose_pitch(pitch))
57                    .collect::<Result<Vec<_>>>()?;
58                let mut out = Chord::new(pitches.as_slice())?;
59                if let Some(duration) = chord.duration() {
60                    out.set_duration(duration.clone());
61                }
62                Ok(Self::Chord(out))
63            }
64            Self::Rest(rest) => Ok(Self::Rest(rest.clone())),
65        }
66    }
67}
68
69impl From<Note> for StreamElement {
70    fn from(value: Note) -> Self {
71        Self::Note(value)
72    }
73}
74
75impl From<Chord> for StreamElement {
76    fn from(value: Chord) -> Self {
77        Self::Chord(value)
78    }
79}
80
81impl From<Rest> for StreamElement {
82    fn from(value: Rest) -> Self {
83        Self::Rest(value)
84    }
85}
86
87/// A timestamped stream item.
88#[derive(Clone, Debug)]
89#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
90pub struct StreamEvent {
91    offset: FloatType,
92    element: StreamElement,
93}
94
95impl StreamEvent {
96    /// Creates an event at an offset measured in quarter lengths.
97    pub fn new(offset: FloatType, element: impl Into<StreamElement>) -> Self {
98        Self {
99            offset,
100            element: element.into(),
101        }
102    }
103
104    /// Returns the offset in quarter lengths.
105    pub fn offset(&self) -> FloatType {
106        self.offset
107    }
108
109    /// Returns the stream element.
110    pub fn element(&self) -> &StreamElement {
111        &self.element
112    }
113}
114
115/// A small ordered stream of notes, chords, and rests.
116#[derive(Clone, Debug, Default)]
117#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
118pub struct Stream {
119    events: Vec<StreamEvent>,
120}
121
122impl Stream {
123    /// Creates an empty stream.
124    pub fn new() -> Self {
125        Self::default()
126    }
127
128    /// Creates a stream from events, sorted by offset.
129    pub fn from_events(events: impl IntoIterator<Item = StreamEvent>) -> Self {
130        let mut stream = Self {
131            events: events.into_iter().collect(),
132        };
133        stream.sort_events();
134        stream
135    }
136
137    /// Inserts an element at a quarter-length offset.
138    pub fn insert(&mut self, offset: FloatType, element: impl Into<StreamElement>) {
139        self.events.push(StreamEvent::new(offset, element));
140        self.sort_events();
141    }
142
143    /// Appends an element after the current end of the stream.
144    pub fn push(&mut self, element: impl Into<StreamElement>) {
145        let element = element.into();
146        let offset = self.end_offset();
147        self.events.push(StreamEvent::new(offset, element));
148    }
149
150    /// Returns immutable events in offset order.
151    pub fn events(&self) -> &[StreamEvent] {
152        &self.events
153    }
154
155    /// Iterates over events in offset order.
156    pub fn iter(&self) -> impl Iterator<Item = &StreamEvent> {
157        self.events.iter()
158    }
159
160    /// Returns a sorted clone of the stream.
161    pub fn flatten(&self) -> Self {
162        Self::from_events(self.events.clone())
163    }
164
165    /// Returns the maximum event end offset.
166    pub fn end_offset(&self) -> FloatType {
167        self.events
168            .iter()
169            .map(|event| event.offset + event.element.quarter_length())
170            .fold(0.0, FloatType::max)
171    }
172
173    /// Returns all pitches in timeline order.
174    pub fn pitches(&self) -> Vec<Pitch> {
175        self.events
176            .iter()
177            .flat_map(|event| event.element.pitches())
178            .collect()
179    }
180
181    /// Returns a transposed copy.
182    pub fn transpose(&self, interval: &Interval) -> Result<Self> {
183        let events = self
184            .events
185            .iter()
186            .map(|event| {
187                Ok(StreamEvent::new(
188                    event.offset,
189                    event.element.transpose(interval)?,
190                ))
191            })
192            .collect::<Result<Vec<_>>>()?;
193        Ok(Self::from_events(events))
194    }
195
196    fn sort_events(&mut self) {
197        self.events.sort_by(|left, right| {
198            left.offset
199                .partial_cmp(&right.offset)
200                .unwrap_or(std::cmp::Ordering::Equal)
201        });
202    }
203}
204
205#[cfg(test)]
206mod tests {
207    use super::*;
208
209    #[test]
210    fn stream_push_uses_durations() {
211        let mut stream = Stream::new();
212        stream.push(
213            Note::from_name("C4")
214                .unwrap()
215                .with_duration(Duration::half()),
216        );
217        stream.push(Rest::from_quarter_length(0.5).unwrap());
218        assert_eq!(stream.events()[0].offset(), 0.0);
219        assert_eq!(stream.events()[1].offset(), 2.0);
220        assert_eq!(stream.end_offset(), 2.5);
221    }
222
223    #[test]
224    fn stream_transposes_notes_and_chords() {
225        let mut stream = Stream::new();
226        stream.push(Note::from_name("C4").unwrap());
227        stream.push(Chord::new("E4 G4").unwrap());
228        let out = stream
229            .transpose(&Interval::from_name("M2").unwrap())
230            .unwrap();
231        let names = out
232            .pitches()
233            .iter()
234            .map(Pitch::name_with_octave)
235            .collect::<Vec<_>>();
236        assert_eq!(names, vec!["D4", "F#4", "A4"]);
237    }
238}