-- | The @SC3@ duration model.
module Sound.SC3.Lang.Control.Duration where

import Data.Maybe {- base -}

-- * Durational

-- | Values that have duration.
--
-- @occ@ is the interval from the start through to the end of the
-- current event, ie. the time span the event /occupies/.
--
-- @delta@ is the interval from the start of the current event to the
-- start of the next /sequential/ event.
--
-- @fwd@ is the interval from the start of the current event to the
-- start of the next /parallel/ event.
class Durational d where
    occ :: d -> Double
    delta :: d -> Double
    delta = occ
    fwd :: d -> Double
    fwd = occ

-- * 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 Durational Dur where
    occ d = fromMaybe (delta d * legato d) (sustain' d)
    delta d = fromMaybe (dur d * stretch d * (60 / tempo d)) (delta' 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}