use std::fmt;
use crate::core::{Chord, Duration, Fraction, Note, Rest};
#[derive(Debug, Clone, PartialEq)]
pub enum MusicElement {
Note(Note),
Chord(Chord),
Rest(Rest),
}
impl MusicElement {
pub fn duration(&self) -> &Duration {
match self {
MusicElement::Note(n) => n.duration(),
MusicElement::Chord(c) => c.duration(),
MusicElement::Rest(r) => r.duration(),
}
}
pub fn quarter_length(&self) -> Fraction {
match self {
MusicElement::Note(n) => n.quarter_length(),
MusicElement::Chord(c) => c.quarter_length(),
MusicElement::Rest(r) => r.quarter_length(),
}
}
pub fn is_note(&self) -> bool {
matches!(self, MusicElement::Note(_))
}
pub fn is_chord(&self) -> bool {
matches!(self, MusicElement::Chord(_))
}
pub fn is_rest(&self) -> bool {
matches!(self, MusicElement::Rest(_))
}
pub fn as_note(&self) -> Option<&Note> {
match self {
MusicElement::Note(n) => Some(n),
_ => None,
}
}
pub fn as_chord(&self) -> Option<&Chord> {
match self {
MusicElement::Chord(c) => Some(c),
_ => None,
}
}
pub fn as_rest(&self) -> Option<&Rest> {
match self {
MusicElement::Rest(r) => Some(r),
_ => None,
}
}
pub fn as_note_mut(&mut self) -> Option<&mut Note> {
match self {
MusicElement::Note(n) => Some(n),
_ => None,
}
}
pub fn as_chord_mut(&mut self) -> Option<&mut Chord> {
match self {
MusicElement::Chord(c) => Some(c),
_ => None,
}
}
pub fn as_rest_mut(&mut self) -> Option<&mut Rest> {
match self {
MusicElement::Rest(r) => Some(r),
_ => None,
}
}
}
impl From<Note> for MusicElement {
fn from(note: Note) -> Self {
MusicElement::Note(note)
}
}
impl From<Chord> for MusicElement {
fn from(chord: Chord) -> Self {
MusicElement::Chord(chord)
}
}
impl From<Rest> for MusicElement {
fn from(rest: Rest) -> Self {
MusicElement::Rest(rest)
}
}
impl fmt::Display for MusicElement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
MusicElement::Note(n) => write!(f, "{}", n),
MusicElement::Chord(c) => write!(f, "{}", c),
MusicElement::Rest(r) => write!(f, "{}", r),
}
}
}
pub trait StreamElement: Clone {
fn offset(&self) -> Fraction;
fn set_offset(&mut self, offset: Fraction);
fn duration(&self) -> Fraction;
fn priority(&self) -> i32 {
0
}
}
#[derive(Debug, Clone, Default)]
pub struct Stream {
elements: Vec<(Fraction, MusicElement)>,
end_elements: Vec<MusicElement>,
auto_sort: bool,
is_sorted: bool,
}
impl Stream {
pub fn new() -> Self {
Self {
elements: Vec::new(),
end_elements: Vec::new(),
auto_sort: true,
is_sorted: true,
}
}
pub fn len(&self) -> usize {
self.elements.len()
}
pub fn is_empty(&self) -> bool {
self.elements.is_empty()
}
pub fn elements(&self) -> &[(Fraction, MusicElement)] {
&self.elements
}
pub fn elements_mut(&mut self) -> &mut Vec<(Fraction, MusicElement)> {
self.is_sorted = false;
&mut self.elements
}
pub fn append(&mut self, element: MusicElement) {
let offset = self.highest_time();
self.elements.push((offset, element));
}
pub fn insert(&mut self, offset: Fraction, element: MusicElement) {
self.elements.push((offset, element));
self.is_sorted = false;
if self.auto_sort {
self.sort();
}
}
pub fn remove(&mut self, index: usize) -> Option<(Fraction, MusicElement)> {
if index < self.elements.len() {
Some(self.elements.remove(index))
} else {
None
}
}
pub fn clear(&mut self) {
self.elements.clear();
self.end_elements.clear();
self.is_sorted = true;
}
pub fn sort(&mut self) {
if !self.is_sorted {
self.elements.sort_by(|(a, _), (b, _)| a.cmp(b));
self.is_sorted = true;
}
}
pub fn is_sorted(&self) -> bool {
self.is_sorted
}
pub fn set_auto_sort(&mut self, auto_sort: bool) {
self.auto_sort = auto_sort;
}
pub fn highest_offset(&self) -> Fraction {
self.elements
.iter()
.map(|(offset, _)| *offset)
.max()
.unwrap_or(Fraction::new(0, 1))
}
pub fn highest_time(&self) -> Fraction {
self.elements
.iter()
.map(|(offset, elem)| *offset + elem.quarter_length())
.max()
.unwrap_or(Fraction::new(0, 1))
}
pub fn lowest_offset(&self) -> Fraction {
self.elements
.iter()
.map(|(offset, _)| *offset)
.min()
.unwrap_or(Fraction::new(0, 1))
}
pub fn duration(&self) -> Fraction {
self.highest_time() - self.lowest_offset()
}
pub fn iter(&self) -> impl Iterator<Item = &(Fraction, MusicElement)> {
self.elements.iter()
}
pub fn iter_elements(&self) -> impl Iterator<Item = &MusicElement> {
self.elements.iter().map(|(_, elem)| elem)
}
pub fn notes(&self) -> impl Iterator<Item = &Note> {
self.elements.iter().filter_map(|(_, elem)| elem.as_note())
}
pub fn chords(&self) -> impl Iterator<Item = &Chord> {
self.elements.iter().filter_map(|(_, elem)| elem.as_chord())
}
pub fn rests(&self) -> impl Iterator<Item = &Rest> {
self.elements.iter().filter_map(|(_, elem)| elem.as_rest())
}
pub fn elements_at_offset(&self, offset: Fraction) -> impl Iterator<Item = &MusicElement> {
self.elements
.iter()
.filter(move |(o, _)| *o == offset)
.map(|(_, elem)| elem)
}
pub fn shift_elements(&mut self, shift: Fraction) {
for (offset, _) in &mut self.elements {
*offset = *offset + shift;
}
}
pub fn scale_offsets(&mut self, scale: Fraction) {
for (offset, _) in &mut self.elements {
*offset = *offset * scale;
}
}
pub fn store_at_end(&mut self, element: MusicElement) {
self.end_elements.push(element);
}
pub fn end_elements(&self) -> &[MusicElement] {
&self.end_elements
}
pub fn first(&self) -> Option<&MusicElement> {
self.elements.first().map(|(_, elem)| elem)
}
pub fn last(&self) -> Option<&MusicElement> {
self.elements.last().map(|(_, elem)| elem)
}
pub fn get(&self, index: usize) -> Option<&(Fraction, MusicElement)> {
self.elements.get(index)
}
pub fn get_mut(&mut self, index: usize) -> Option<&mut (Fraction, MusicElement)> {
self.elements.get_mut(index)
}
}
impl fmt::Display for Stream {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Stream({} elements)", self.elements.len())
}
}
impl IntoIterator for Stream {
type Item = (Fraction, MusicElement);
type IntoIter = std::vec::IntoIter<(Fraction, MusicElement)>;
fn into_iter(self) -> Self::IntoIter {
self.elements.into_iter()
}
}
impl<'a> IntoIterator for &'a Stream {
type Item = &'a (Fraction, MusicElement);
type IntoIter = std::slice::Iter<'a, (Fraction, MusicElement)>;
fn into_iter(self) -> Self::IntoIter {
self.elements.iter()
}
}
impl FromIterator<(Fraction, MusicElement)> for Stream {
fn from_iter<T: IntoIterator<Item = (Fraction, MusicElement)>>(iter: T) -> Self {
let mut stream = Stream::new();
for (offset, element) in iter {
stream.insert(offset, element);
}
stream.sort();
stream
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::{Pitch, Step};
fn make_note() -> Note {
Note::quarter(Pitch::from_parts(Step::C, Some(4), None))
}
#[test]
fn test_stream_creation() {
let stream = Stream::new();
assert!(stream.is_empty());
assert_eq!(stream.len(), 0);
}
#[test]
fn test_stream_append() {
let mut stream = Stream::new();
stream.append(MusicElement::Note(make_note()));
stream.append(MusicElement::Note(make_note()));
assert_eq!(stream.len(), 2);
assert_eq!(stream.elements()[0].0, Fraction::new(0, 1));
assert_eq!(stream.elements()[1].0, Fraction::new(1, 1)); }
#[test]
fn test_stream_insert() {
let mut stream = Stream::new();
stream.insert(Fraction::new(2, 1), MusicElement::Note(make_note()));
stream.insert(Fraction::new(0, 1), MusicElement::Note(make_note()));
stream.insert(Fraction::new(1, 1), MusicElement::Note(make_note()));
assert!(stream.is_sorted());
assert_eq!(stream.elements()[0].0, Fraction::new(0, 1));
assert_eq!(stream.elements()[1].0, Fraction::new(1, 1));
assert_eq!(stream.elements()[2].0, Fraction::new(2, 1));
}
#[test]
fn test_stream_duration() {
let mut stream = Stream::new();
stream.append(MusicElement::Note(make_note()));
stream.append(MusicElement::Note(make_note()));
assert_eq!(stream.duration(), Fraction::new(2, 1));
}
#[test]
fn test_stream_shift() {
let mut stream = Stream::new();
stream.insert(Fraction::new(0, 1), MusicElement::Note(make_note()));
stream.insert(Fraction::new(1, 1), MusicElement::Note(make_note()));
stream.shift_elements(Fraction::new(2, 1));
assert_eq!(stream.elements()[0].0, Fraction::new(2, 1));
assert_eq!(stream.elements()[1].0, Fraction::new(3, 1));
}
}