mod parse;
use super::{
resolve_state::ResolveState, Chord, Inversion, Note, Overlapped, Rest, Scale, Sequence,
};
use crate::{
metronome::{Beat, Metronome},
nodes::instrument::Tone,
parse::IResult,
pitch::PitchStandard,
};
use nom::{combinator::all_consuming, error::convert_error, Finish as _};
use std::{
fmt,
str::FromStr,
sync::{Arc, Mutex},
};
#[derive(Clone)]
pub enum Item {
Note(Arc<Mutex<Note>>),
Chord(Arc<Mutex<Chord>>),
Rest(Arc<Mutex<Rest>>),
Overlapped(Arc<Mutex<Overlapped>>),
Sequence(Arc<Mutex<Sequence>>),
Scale(Arc<Mutex<Scale>>),
Inversion(Arc<Mutex<Inversion>>),
}
impl fmt::Debug for Item {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Item::Note(note) => fmt::Debug::fmt(¬e.lock().expect("poisoned"), f),
Item::Chord(chord) => fmt::Debug::fmt(&chord.lock().expect("poisoned"), f),
Item::Rest(rest) => fmt::Debug::fmt(&rest.lock().expect("poisoned"), f),
Item::Overlapped(overlapped) => {
fmt::Debug::fmt(&overlapped.lock().expect("poisoned"), f)
}
Item::Sequence(sequence) => fmt::Debug::fmt(&sequence.lock().expect("poisoned"), f),
Item::Scale(scale) => fmt::Debug::fmt(&scale.lock().expect("poisoned"), f),
Item::Inversion(inversion) => fmt::Debug::fmt(&inversion.lock().expect("poisoned"), f),
}
}
}
impl Item {
pub(super) fn inner_tones<S>(
&self,
offset: Beat,
metronome: &Metronome,
pitch_standard: &S,
state: &ResolveState,
) -> Box<dyn Iterator<Item = Tone> + 'static>
where
S: PitchStandard + ?Sized,
{
match self {
Item::Note(note) => Box::new(std::iter::once(
note.lock()
.expect("poisoned")
.inner_tone(offset, metronome, pitch_standard, state),
)),
Item::Chord(chord) => Box::new(chord.lock().expect("poisoned").inner_tones(
offset,
metronome,
pitch_standard,
state.clone(),
)),
Item::Overlapped(overlapped) => {
Box::new(overlapped.lock().expect("poisoned").inner_tones(
offset,
metronome,
pitch_standard,
state,
))
}
Item::Sequence(sequence) => Box::new(sequence.lock().expect("poisoned").inner_tones(
offset,
metronome,
pitch_standard,
state.clone(),
)),
Item::Scale(_) | Item::Inversion(_) | Item::Rest(_) => Box::new(std::iter::empty()),
}
}
pub fn tones<S>(
&self,
offset: Beat,
metronome: &Metronome,
pitch_standard: &S,
) -> Box<dyn Iterator<Item = Tone> + 'static>
where
S: PitchStandard + ?Sized,
{
self.inner_tones(offset, metronome, pitch_standard, &Default::default())
}
pub(super) fn inner_length(&self, state: &ResolveState) -> Beat {
match self {
Item::Note(note) => note.lock().expect("poisoned").inner_length(state),
Item::Chord(chord) => chord.lock().expect("poisoned").inner_length(state),
Item::Rest(rest) => rest.lock().expect("poisoned").inner_length(state),
Item::Overlapped(overlapped) => {
overlapped.lock().expect("poisoned").inner_length(state)
}
Item::Sequence(sequence) => sequence
.lock()
.expect("poisoned")
.inner_length(state.clone()),
Item::Scale(_) | Item::Inversion(_) => Beat::ZERO,
}
}
pub(super) fn update_state(&self, state: &mut ResolveState) {
match self {
Item::Note(note) => note.lock().expect("poisoned").update_state(state),
Item::Chord(chord) => chord.lock().expect("poisoned").update_state(state),
Item::Rest(rest) => rest.lock().expect("poisoned").update_state(state),
Item::Scale(scale) => scale.lock().expect("poisoned").update_state(state),
Item::Inversion(inversion) => inversion.lock().expect("poisoned").update_state(state),
Item::Overlapped(_) | Item::Sequence(_) => (),
}
}
pub(super) fn inner_duration(&self, state: &ResolveState) -> Beat {
match self {
Item::Note(note) => note.lock().expect("poisoned").inner_duration(state),
Item::Chord(chord) => chord.lock().expect("poisoned").inner_duration(state),
Item::Rest(rest) => rest.lock().expect("poisoned").duration(),
Item::Overlapped(overlapped) => {
overlapped.lock().expect("poisoned").inner_duration(state)
}
Item::Sequence(sequence) => sequence
.lock()
.expect("poisoned")
.inner_duration(state.clone()),
Item::Scale(_) | Item::Inversion(_) => Beat::ZERO,
}
}
pub fn length(&self) -> Beat {
self.inner_length(&Default::default())
}
pub fn duration(&self) -> Beat {
self.inner_duration(&Default::default())
}
pub fn parse(input: &str) -> IResult<&str, Self> {
parse::item(input)
}
}
impl FromStr for Item {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let note = all_consuming(parse::item)(s)
.finish()
.map_err(move |e| convert_error(s, e))?
.1;
Ok(note)
}
}