hsc3-lang-0.15: Sound/SC3/Lang/Control/Duration.hs
-- | The @SC3@ duration model.
module Sound.SC3.Lang.Control.Duration where
import Data.Maybe {- base -}
import Data.Ratio {- base -}
-- * Duration
-- | There are three parts to a duration:
--
-- 'delta' is the /logical/ or /notated/ duration.
--
-- 'occ' is the /sounding/ duration, the interval that a value
-- actually occupies in time. If 'occ' '<' 'delta' there will be a
-- /hole/, if 'occ' '>' 'delta' there will be an /overlap/.
--
-- 'fwd' is the /forward/ duration, the interval to the start time of
-- the next value in the sequence, which may be /parallel/ to the
-- current value. Ordinarily 'fwd' is either 'delta' or @0@.
class Duration d where
delta :: d -> Double
occ :: d -> Double
occ = delta
fwd :: d -> Double
fwd = delta
instance Duration Int where delta = fromIntegral
instance Duration Integer where delta = fromIntegral
instance Duration Float where delta = realToFrac
instance Duration Double where delta = id
instance Integral i => Duration (Ratio i) where delta = realToFrac
{- FlexibleInstances
instance Real i => Duration (i,i,i) where
delta (i,_,_) = realToFrac i
occ (_,i,_) = realToFrac i
fwd (_,_,i) = realToFrac i
-}
-- | Composite of 'delta', 'occ', and 'fwd'.
duration :: Duration d => d -> (Double,Double,Double)
duration d = (delta d,occ d,fwd d)
-- * Dur
-- | Variant of the @SC3@ 'Duration' model.
--
-- > delta (defaultDur {dur = 2,stretch = 2}) == 4
-- > occ defaultDur == 0.8
-- > let d = defaultDur {fwd' = Just 0} in (delta d,fwd d) == (1,0)
data Dur =
Dur {tempo :: Double -- ^ Tempo (in pulses per minute)
,dur :: Double -- ^ Duration (in pulses)
,stretch :: Double -- ^ Stretch multiplier
,legato :: Double -- ^ Legato multipler
,sustain' :: Maybe Double -- ^ Sustain time
,delta' :: Maybe Double -- ^ Delta time
,lag :: Double -- ^ Lag value
,fwd' :: Maybe Double -- ^ Possible non-sequential delta time field
}
deriving (Eq,Show)
instance Duration Dur where
delta d = fromMaybe (dur d * stretch d * (60 / tempo d)) (delta' d)
occ d = fromMaybe (delta d * legato d) (sustain' d)
fwd d = maybe (delta d) (* stretch d) (fwd' d)
-- | Default 'Dur' value, equal to one second.
--
-- > delta defaultDur == 1
defaultDur :: Dur
defaultDur =
Dur {tempo = 60
,dur = 1
,stretch = 1
,legato = 0.8
,sustain' = Nothing
,delta' = Nothing
,lag = 0.1
,fwd' = Nothing}
-- * OptDur
-- | Eight tuple.
type T8 n = (n,n,n,n,n,n,n,n)
-- | 'Dur' represented as an eight-tuple of optional values.
type OptDur = T8 (Maybe Double)
-- | Translate 'OptDur' to 'Dur'.
optDur :: OptDur -> Dur
optDur (t,d,s,l,s',d',l',f) =
Dur {tempo = fromMaybe 60 t
,dur = fromMaybe 1 d
,stretch = fromMaybe 1 s
,legato = fromMaybe 0.8 l
,sustain' = s'
,delta' = d'
,lag = fromMaybe 0.1 l'
,fwd' = f}