1use crate::{
2 chord::Chord, defaults::FloatType, duration::Duration, error::Result, interval::Interval,
3 note::Note, pitch::Pitch, rest::Rest,
4};
5
6#[derive(Clone, Debug)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9pub enum StreamElement {
10 Note(Note),
12 Chord(Chord),
14 Rest(Rest),
16}
17
18impl StreamElement {
19 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 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 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 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#[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 pub fn new(offset: FloatType, element: impl Into<StreamElement>) -> Self {
98 Self {
99 offset,
100 element: element.into(),
101 }
102 }
103
104 pub fn offset(&self) -> FloatType {
106 self.offset
107 }
108
109 pub fn element(&self) -> &StreamElement {
111 &self.element
112 }
113}
114
115#[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 pub fn new() -> Self {
125 Self::default()
126 }
127
128 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 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 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 pub fn events(&self) -> &[StreamEvent] {
152 &self.events
153 }
154
155 pub fn iter(&self) -> impl Iterator<Item = &StreamEvent> {
157 self.events.iter()
158 }
159
160 pub fn flatten(&self) -> Self {
162 Self::from_events(self.events.clone())
163 }
164
165 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 pub fn pitches(&self) -> Vec<Pitch> {
175 self.events
176 .iter()
177 .flat_map(|event| event.element.pitches())
178 .collect()
179 }
180
181 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}