Karya, built on 2020-11-26T21:03:17 (patch 23b5be2d53a9e8e7d6136cda5aae2849abe5cded)
Safe HaskellNone

Derive.Warp

Description

Functions for the Warp.

Synopsis

Documentation

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

Instances details
Show Warp # 
Instance details

Defined in Derive.Warp

Methods

showsPrec :: Int -> Warp -> ShowS #

show :: Warp -> String #

showList :: [Warp] -> ShowS #

DeepSeq.NFData Warp #

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

Instance details

Defined in Derive.Warp

Methods

rnf :: Warp -> () #

Pretty Warp # 
Instance details

Defined in Derive.Warp

data Linear Source #

Instances

Instances details
Show Linear # 
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.

utils

compose_hybrid