mod parse;
use super::{resolve_state::ResolveState, NotePitch};
use crate::{
metronome::{Beat, Metronome},
nodes::instrument::Tone,
parse::IResult,
pitch::PitchStandard,
};
use nom::{combinator::all_consuming, error::convert_error, Finish as _};
use std::str::FromStr;
#[derive(Debug, Clone)]
pub struct Chord {
pub pitches: Vec<NotePitch>,
pub length: Option<Beat>,
pub duration: Option<Beat>,
}
impl Chord {
pub(super) fn inner_tones<S>(
&self,
offset: Beat,
metronome: &Metronome,
pitch_standard: &S,
mut state: ResolveState,
) -> impl Iterator<Item = Tone> + 'static
where
S: PitchStandard + ?Sized,
{
let start = metronome.beat_to_time(offset);
let duration = self.inner_duration(&state);
let end_beat = offset + duration;
let end = metronome.beat_to_time(end_beat);
let length = end - start;
let pitches: Vec<_> = self
.pitches
.iter()
.map(move |pitch| {
let frequency = pitch_standard.resolve(&pitch.absolute(&state));
pitch.update_state(&mut state);
Tone {
start,
length,
frequency,
}
})
.collect();
pitches.into_iter()
}
pub fn tones<S>(
&self,
offset: Beat,
metronome: &Metronome,
pitch_standard: &S,
) -> impl 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 {
self.length.unwrap_or(state.length)
}
pub(super) fn inner_duration(&self, state: &ResolveState) -> Beat {
self.duration.or(self.length).unwrap_or(state.length)
}
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::chord(input)
}
pub(super) fn update_state(&self, state: &mut ResolveState) {
state.length = self.inner_length(state);
}
}
impl FromStr for Chord {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let chord = all_consuming(parse::chord)(s)
.finish()
.map_err(move |e| convert_error(s, e))?
.1;
Ok(chord)
}
}