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



Functions for the Warp.



data Warp Source #

The Warp keeps track of the ScoreTime -> RealTime function, as well as its inverse.

This treats linear warps specially, since they're common and allow some optimizations.

The main transformation is compose, but shift and stretch are shortcuts for composing with f(x) = y + shift or f(x) = y * stretch, respectively.

The confusing thing is that shift and stretch compose with the *input* of the function, so shift n is (compose shift n identity). This means that shift 1 . stretch 2 is actually (*2) . (+1), which makes compositions look backwards. It turns out this is more convenient since Deriver level shift and stretch go in left-to-right order since monadic effects go left to right:

Reader.runReader (Reader.local (+1) . Reader.local (*2) $ Reader.ask) 0

is 2, not 1.

There is probably some kind of theory to do with positive position or negative position or some such thing, but my tiny brain can't quite get a handle on it, so all I can say is that this is the way that makes things work out right.


Instances details
Show Warp Source # 
Instance details

Defined in Derive.Warp


showsPrec :: Int -> Warp -> ShowS #

show :: Warp -> String #

showList :: [Warp] -> ShowS #

DeepSeq.NFData Warp Source #

I can't really rnf functions, but maybe there will be data in here someday.

Instance details

Defined in Derive.Warp


rnf :: Warp -> () #

Pretty Warp Source # 
Instance details

Defined in Derive.Warp

data Linear Source #


Instances details
Show Linear Source # 
Instance details

Defined in Derive.Warp

unwarp :: Warp -> RealTime.RealTime -> ScoreTime.ScoreTime Source #

The inverse of warp. I originally would fail when the RealTime doesn't occur in the Warp, but now I extend it in the same way as warp. Failing caused awkwardness with events at the end of the score.

identity :: Warp Source #

1:1 identity warp. Previously I could detect this to optimize it away, but since compose is cheap now, I might not need that anymore.

from_signal :: Signal.Warp -> Warp Source #

Create a Warp from a signal and its inverse. This assumes the signal is monotonically increasing.

Times <0 always pass through unchanged. This is because warps start at 0, since tracks start at 0, but events may be moved before it. Since there's no tempo data there, I need to make something up, and I might as well make up id. TODO error on empty signal? or id?

stretch :: ScoreTime.ScoreTime -> Warp -> Warp Source #

See Warp.

Previously, this would disallow <=0 stretch, but it turns out to be useful to stretch events to 0, and to negative durations.