Karya, built on 2022-03-21T01:30:44 (patch 89d1651424c35e564138d93424a157ff87457245)
Safe HaskellSafe-Inferred



This module manages the performance of music, specifically the creation of performance threads.

Performance is relative to a toplevel block, so each block has its own set of caches. Since performance is lazy, a separate thread will force it asynchronously.



update_performance :: SendStatus -> Ui.State -> Cmd.State -> ScoreDamage -> IO.IO Cmd.State Source #

Update the performances by rederiving if necessary. This means figuring out ScoreDamage, and if there has been damage, killing any in-progress derivation and starting derivation. This updates performances for the root block and all visible blocks.

The majority of the calls here will bring neither score damage nor a changed view id, and thus this will do nothing.

This is tricky, and I've gotten it wrong in the past, so here's a detailed description:

Merge ui damage with each perf's damage. Then for each perf, if it's Cmd.state_current_performance has damage, kill its thread, and remove its entry in Cmd.state_performance_threads. The lack of a thread entry, whether because was removed or never existed, means that a block should be rederived. Derivation creates a new Msg.Performance and an evaluate thread, and puts them into Cmd.state_current_performance and Cmd.state_performance_threads respectively, but due to laziness, no actual derivation happens unless someone (like play) happens to look at the performance. This all happens synchronously, so the next time update_performance is called, it sees a nice clean new Performance with no damage.

Meanwhile, the evaluate thread asynchronously waits for a bit, then forces the contents of the Performance, and then sends it back to the responder so it can stash it in Cmd.state_performance. If a new change comes in while it's waiting it'll get killed off, and the out-of-date derivation will never happen. Yay for laziness!

derive_blocks :: Ui.State -> Set BlockId Source #

Which blocks should get derived?

evaluate_im :: Config.Config -> (ScoreT.Instrument -> Maybe.Maybe Cmd.ResolvedInstrument) -> IO.FilePath -> RealTime.RealTime -> RealTime.RealTime -> BlockId -> Vector.Vector Score.Event -> IO.IO ([Process], Vector.Vector Score.Event) Source #

If there are im events, serialize them and return a Processes to render them, and the non-im events.

wait_for_subprocesses :: IO.IO () -> Set ScoreT.Instrument -> Set Process -> IO.IO Bool Source #

Like watch_subprocesses, but notify the callback as soon as they have all rendered enough audio.