Skip to content

Commit

Permalink
make truly lazy Music::perform
Browse files Browse the repository at this point in the history
  • Loading branch information
tsionyx committed Aug 14, 2024
1 parent 9ad3b59 commit 41c49e1
Show file tree
Hide file tree
Showing 7 changed files with 304 additions and 51 deletions.
15 changes: 11 additions & 4 deletions examples/hsom-exercises/ch6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -614,9 +614,16 @@ mod intervals {
pub mod shepard_scale {
use std::iter;

use musik::{midi::Instrument, AbsPitch, Dur, Interval, Music, Octave, Pitch, Volume};
use musik::{
midi::Instrument, utils::CloneableIterator, AbsPitch, Dur, Interval, Music, Octave, Pitch,
Volume,
};

fn interval_line(start: Pitch, dur: Dur, delta: Interval) -> impl Iterator<Item = Music> {
fn interval_line(
start: Pitch,
dur: Dur,
delta: Interval,
) -> impl CloneableIterator<Item = Music> + Clone {
iter::successors(Some(start), move |prev| Some(prev.trans(delta)))
.map(move |p| Music::note(dur, p))
}
Expand Down Expand Up @@ -679,7 +686,7 @@ pub mod shepard_scale {
}
}

fn scale(&self) -> Music<(Pitch, Volume)> {
fn scale(self) -> Music<(Pitch, Volume)> {
let max_volume = u8::from(Volume::loudest().get_inner());
let min_volume = u8::from(Volume::softest().get_inner());

Expand All @@ -690,7 +697,7 @@ pub mod shepard_scale {
interval_line(self.start, self.dur, self.delta)
.take(self.size as usize)
.zip(0..)
.map(|(step, i)| {
.map(move |(step, i)| {
if i < self.size - fade_out_parts {
volume = (volume + self.fade_in_volume_step).min(max_volume);
} else {
Expand Down
13 changes: 5 additions & 8 deletions examples/hsom-exercises/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::path::PathBuf;
use clap::{Args, Parser, Subcommand};
use ux2::u7;

use musik::{p, AbsPitch, Dur, Interval, Music, Performable as _, Pitch, Temporal as _, Volume};
use musik::{p, AbsPitch, Dur, Interval, Music, Performable as _, Performance, Pitch, Volume};

mod ch1;
mod ch2;
Expand Down Expand Up @@ -95,15 +95,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
};

// TODO: make the whole flow lazy:
// - fix `Music::perform` to produce truly lazy stream of events;
// Then replace `Music::take` with `Performance::with_events(perf.iter().take(500_000))`
// (for the shepard scale it is roughly identical to `let m = m.take(Dur::from(10_000));`).
// It should almost immediately start to play (select output MIDI device, etc).
// - introduce lazy `midly::Smf` , then check that it starts real sound almost instantly.
// - introduce lazy `midly::Smf`, then check that it starts real sound almost instantly without any `take`.
// (Now it takes ~30s to generate performance and then `Smf`).
let perf = m.take(Dur::from(10_000)).perform();
let perf = m.perform();
if cli.mode.play {
perf.clone().play()?;
let perf = Performance::with_events(perf.iter().take(500_000));
perf.play()?;
}

if let Some(path) = cli.mode.save_into {
Expand Down
28 changes: 19 additions & 9 deletions src/music/perf/interpretations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{
scale::KeySig,
volume::Volume,
},
utils::CloneableIterator,
utils::{CloneableIterator, Measure},
};

use super::{player::Player, Context, Duration, Event, Performance, TimePoint};
Expand Down Expand Up @@ -70,8 +70,9 @@ impl Player<(Pitch, Volume)> for DefaultPlayer {
}

fn default_event_from_note<P>(note: (Dur, Pitch), ctx: Context<P>) -> Event {
let start_time = ctx.start_time();
let Context {
start_time,
start_time: _ignore,
player: _ignore_player,
instrument,
whole_note,
Expand Down Expand Up @@ -194,7 +195,7 @@ where
music: &Music<(Pitch, Vec<A>)>,
attrs: &[PhraseAttribute],
mut ctx: Context<(Pitch, Vec<A>)>,
) -> (Performance, Duration) {
) -> (Performance, Measure<Duration>) {
let key = ctx.key;

let last_volume_phrase = attrs.iter().fold(None, |found, pa| match pa {
Expand Down Expand Up @@ -224,9 +225,14 @@ where
};

let inflate = move |event: Event, coef: Ratio<u32>, sign: bool| {
let r = coef / dur;
let dt = event.start_time - t0;
let coef_event = dt * r;
let coef_event = match dur {
Measure::Finite(dur) => {
let r = coef / dur;
let dt = event.start_time - t0;
dt * r
}
Measure::Infinite => Ratio::from_integer(0),
};
let shift = if sign {
Ratio::one() + coef_event
} else {
Expand All @@ -243,7 +249,11 @@ where
};

let stretch = move |event: Event, coef: Ratio<u32>, sign: bool| {
let r = coef / dur;
let r = match dur {
Measure::Finite(dur) => coef / dur,
Measure::Infinite => Ratio::from_integer(0),
};

let dt = event.start_time - t0;
let time_coef_event = dt * r;
let dur_coef_event = (Ratio::from(2) * dt + event.duration) * r;
Expand Down Expand Up @@ -288,12 +298,12 @@ where
}
PhraseAttribute::Tmp(Tempo::Ritardando(x)) => {
let perf = perf.map(move |e| stretch(e, x, true));
let dur = (Ratio::one() + x) * dur;
let dur = dur * (Ratio::one() + x);
(perf, dur)
}
PhraseAttribute::Tmp(Tempo::Accelerando(x)) => {
let perf = perf.map(move |e| stretch(e, x, false));
let dur = Ratio::one().checked_sub(&x).unwrap_or_default() * dur;
let dur = dur * Ratio::one().checked_sub(&x).unwrap_or_default();
(perf, dur)
}
PhraseAttribute::Orn(Ornament::Trill(opts)) => {
Expand Down
Loading

0 comments on commit 41c49e1

Please sign in to comment.