{-# LANGUAGE CPP #-}
module Derive.Tempo (
with_tempo, with_absolute, with_hybrid
#ifdef TESTING
, tempo_to_warp
#endif
) where
import qualified Ui.ScoreTime as ScoreTime
import qualified Derive.Derive as Derive
import qualified Derive.Deriver.Internal as Internal
import qualified Derive.Warp as Warp
import qualified Perform.RealTime as RealTime
import qualified Perform.Signal as Signal
import Global
import Types
with_tempo :: Monoid a => Bool
-> Maybe (ScoreTime, ScoreTime)
-> Maybe TrackId
-> Signal.Tempo -> Derive.Deriver a -> Derive.Deriver a
with_tempo :: forall a.
Monoid a =>
Bool
-> Maybe (ScoreTime, ScoreTime)
-> Maybe TrackId
-> Tempo
-> Deriver a
-> Deriver a
with_tempo Bool
toplevel Maybe (ScoreTime, ScoreTime)
range Maybe TrackId
maybe_track_id Tempo
signal Deriver a
deriver = do
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (forall {k} (kind :: k). Signal kind -> Bool
Signal.zero_or_below Tempo
signal) forall a b. (a -> b) -> a -> b
$
forall a. HasCallStack => Text -> Deriver a
Derive.throw Text
"tempo signal crosses zero"
let warp :: Warp
warp = Tempo -> Warp
tempo_to_warp Tempo
signal
Deriver a -> Deriver a
stretch_to_1 <- forall a.
Monoid a =>
Maybe (ScoreTime, ScoreTime)
-> ((ScoreTime, ScoreTime) -> Deriver (Deriver a -> Deriver a, X))
-> Deriver (Deriver a -> Deriver a)
get_stretch_to_1 Maybe (ScoreTime, ScoreTime)
range forall a b. (a -> b) -> a -> b
$ \(ScoreTime
start, ScoreTime
end) -> do
let real_start :: X
real_start = Warp -> ScoreTime -> X
Warp.warp Warp
warp ScoreTime
start
real_end :: X
real_end = Warp -> ScoreTime -> X
Warp.warp Warp
warp ScoreTime
end
real_dur :: X
real_dur = X
real_end forall a. Num a => a -> a -> a
- X
real_start
let stretch :: ScoreTime
stretch = ScoreTime
1 forall a. Fractional a => a -> a -> a
/ X -> ScoreTime
RealTime.to_score X
real_dur
forall a. Num a => a -> a -> a
* if Bool
toplevel then ScoreTime
1 else ScoreTime
end forall a. Num a => a -> a -> a
- ScoreTime
start
Deriver a -> Deriver a
place <- forall a. ScoreTime -> X -> (a -> a) -> Deriver (a -> a)
require_nonzero (ScoreTime
end forall a. Num a => a -> a -> a
- ScoreTime
start) X
real_dur forall a b. (a -> b) -> a -> b
$
forall a. ScoreTime -> Deriver a -> Deriver a
Derive.stretch ScoreTime
stretch forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. ScoreTime -> Deriver a -> Deriver a
Derive.at (- X -> ScoreTime
RealTime.to_score X
real_start)
forall (m :: * -> *) a. Monad m => a -> m a
return (Deriver a -> Deriver a
place, X
real_dur)
Deriver a -> Deriver a
stretch_to_1 forall a b. (a -> b) -> a -> b
$ forall a. Warp -> Deriver a -> Deriver a
Internal.warp Warp
warp forall a b. (a -> b) -> a -> b
$ do
Maybe TrackId -> Deriver State Error ()
Internal.add_new_track_warp Maybe TrackId
maybe_track_id
Deriver a
deriver
tempo_to_warp :: Signal.Tempo -> Warp.Warp
tempo_to_warp :: Tempo -> Warp
tempo_to_warp Tempo
sig
| Just Double
y <- forall {k} (kind :: k). X -> Signal kind -> Maybe Double
Signal.constant_val_from X
0 Tempo
sig =
ScoreTime -> Warp -> Warp
Warp.stretch (Double -> ScoreTime
ScoreTime.from_double forall a b. (a -> b) -> a -> b
$ Double
1 forall a. Fractional a => a -> a -> a
/ Double
y) Warp
Warp.identity
| Bool
otherwise = Warp -> Warp
Warp.from_signal Warp
warp_sig
where
warp_sig :: Warp
warp_sig = Tempo -> Warp
Signal.integrate_inverse Tempo
sig
require_nonzero :: ScoreTime -> RealTime -> (a -> a) -> Derive.Deriver (a -> a)
require_nonzero :: forall a. ScoreTime -> X -> (a -> a) -> Deriver (a -> a)
require_nonzero ScoreTime
block_dur X
real_dur a -> a
ok
| ScoreTime
block_dur forall a. Eq a => a -> a -> Bool
== ScoreTime
0 = forall (m :: * -> *) a. Monad m => a -> m a
return forall a. a -> a
id
| X
real_dur forall a. Eq a => a -> a -> Bool
== X
0 = forall a. HasCallStack => Text -> Deriver a
Derive.throw forall a b. (a -> b) -> a -> b
$
Text
"real time of block with dur " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> Text
showt ScoreTime
block_dur forall a. Semigroup a => a -> a -> a
<> Text
" was zero"
| Bool
otherwise = forall (m :: * -> *) a. Monad m => a -> m a
return a -> a
ok
get_stretch_to_1 :: Monoid a => Maybe (ScoreTime, ScoreTime)
-> ((ScoreTime, ScoreTime)
-> Derive.Deriver (Derive.Deriver a -> Derive.Deriver a, RealTime))
-> Derive.Deriver (Derive.Deriver a -> Derive.Deriver a)
get_stretch_to_1 :: forall a.
Monoid a =>
Maybe (ScoreTime, ScoreTime)
-> ((ScoreTime, ScoreTime) -> Deriver (Deriver a -> Deriver a, X))
-> Deriver (Deriver a -> Deriver a)
get_stretch_to_1 Maybe (ScoreTime, ScoreTime)
Nothing (ScoreTime, ScoreTime) -> Deriver (Deriver a -> Deriver a, X)
_ = forall (m :: * -> *) a. Monad m => a -> m a
return forall a. a -> a
id
get_stretch_to_1 (Just (ScoreTime, ScoreTime)
range) (ScoreTime, ScoreTime) -> Deriver (Deriver a -> Deriver a, X)
compute =
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM Deriver Bool
Internal.is_root_block (forall (m :: * -> *) a. Monad m => a -> m a
return forall a. a -> a
id) forall a b. (a -> b) -> a -> b
$ do
(Deriver a -> Deriver a
transform, X
dur) <- (ScoreTime, ScoreTime) -> Deriver (Deriver a -> Deriver a, X)
compute (ScoreTime, ScoreTime)
range
Deriver Mode
Derive.get_mode forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Mode
mode -> case Mode
mode of
Mode
Derive.RealDurationQuery -> do
X -> Deriver State Error ()
set_real_duration X
dur
forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Monoid a => a
mempty
Mode
_ -> forall (m :: * -> *) a. Monad m => a -> m a
return Deriver a -> Deriver a
transform
set_real_duration :: RealTime -> Derive.Deriver ()
set_real_duration :: X -> Deriver State Error ()
set_real_duration X
dur = (Collect -> Collect) -> Deriver State Error ()
Internal.modify_collect forall a b. (a -> b) -> a -> b
$ \Collect
collect ->
Collect
collect { collect_real_duration :: CallDuration X
Derive.collect_real_duration = forall a. a -> CallDuration a
Derive.CallDuration X
dur }
with_absolute :: Monoid a => Bool -> Maybe (ScoreTime, ScoreTime)
-> Maybe TrackId -> Signal.Tempo -> Derive.Deriver a -> Derive.Deriver a
with_absolute :: forall a.
Monoid a =>
Bool
-> Maybe (ScoreTime, ScoreTime)
-> Maybe TrackId
-> Tempo
-> Deriver a
-> Deriver a
with_absolute Bool
toplevel Maybe (ScoreTime, ScoreTime)
range Maybe TrackId
maybe_track_id Tempo
signal Deriver a
deriver = do
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
toplevel forall a b. (a -> b) -> a -> b
$ forall a. HasCallStack => Text -> Deriver a
Derive.throw
Text
"nested absolute tracks not supported yet, use 'with_tempo' as a model"
let warp :: Warp
warp = Tempo -> Warp
tempo_to_warp Tempo
signal
Deriver a -> Deriver a
place <- forall a.
Monoid a =>
Maybe (ScoreTime, ScoreTime)
-> ((ScoreTime, ScoreTime) -> Deriver (Deriver a -> Deriver a, X))
-> Deriver (Deriver a -> Deriver a)
get_stretch_to_1 Maybe (ScoreTime, ScoreTime)
range forall a b. (a -> b) -> a -> b
$ \(ScoreTime
block_start, ScoreTime
block_end) -> do
ScoreTime
start <- X -> ScoreTime
RealTime.to_score forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Time a => a -> Deriver X
Derive.real (ScoreTime
0 :: ScoreTime)
ScoreTime
end <- X -> ScoreTime
RealTime.to_score forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Time a => a -> Deriver X
Derive.real (ScoreTime
1 :: ScoreTime)
let real_end :: X
real_end = Warp -> ScoreTime -> X
Warp.warp Warp
warp ScoreTime
block_end
let real_dur :: X
real_dur = X
real_end forall a. Num a => a -> a -> a
- Warp -> ScoreTime -> X
Warp.warp Warp
warp ScoreTime
block_start
Deriver a -> Deriver a
place <- forall a. ScoreTime -> X -> (a -> a) -> Deriver (a -> a)
require_nonzero (ScoreTime
block_end forall a. Num a => a -> a -> a
- ScoreTime
block_start) X
real_dur forall a b. (a -> b) -> a -> b
$
forall a. ScoreTime -> ScoreTime -> Deriver a -> Deriver a
Internal.place ScoreTime
start ((ScoreTime
end forall a. Num a => a -> a -> a
- ScoreTime
start) forall a. Fractional a => a -> a -> a
/ X -> ScoreTime
RealTime.to_score X
real_dur)
forall (m :: * -> *) a. Monad m => a -> m a
return (Deriver a -> Deriver a
place, X
real_dur)
forall a. Deriver a -> Deriver a
Internal.in_real_time forall a b. (a -> b) -> a -> b
$ Deriver a -> Deriver a
place forall a b. (a -> b) -> a -> b
$ forall a. Warp -> Deriver a -> Deriver a
Internal.warp Warp
warp forall a b. (a -> b) -> a -> b
$ do
Maybe TrackId -> Deriver State Error ()
Internal.add_new_track_warp Maybe TrackId
maybe_track_id
Deriver a
deriver
with_hybrid :: Monoid a => Bool -> Maybe (ScoreTime, ScoreTime)
-> Maybe TrackId -> Signal.Tempo -> Derive.Deriver a -> Derive.Deriver a
with_hybrid :: forall a.
Monoid a =>
Bool
-> Maybe (ScoreTime, ScoreTime)
-> Maybe TrackId
-> Tempo
-> Deriver a
-> Deriver a
with_hybrid Bool
toplevel Maybe (ScoreTime, ScoreTime)
range Maybe TrackId
maybe_track_id Tempo
signal Deriver a
deriver = do
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
toplevel forall a b. (a -> b) -> a -> b
$ forall a. HasCallStack => Text -> Deriver a
Derive.throw
Text
"nested hybrid tracks not supported yet, use 'with_tempo' as a model"
forall a. HasCallStack => Text -> Deriver a
Derive.throw Text
"not implemented"