-- | Operating rate definitions and utilities.
module Sound.Sc3.Common.Rate where

import Data.Char {- base -}
import Data.Maybe {- base -}

-- | Enumeration of operating rates of unit generators.
data Rate = InitialisationRate | ControlRate | AudioRate | DemandRate
  deriving (Rate -> Rate -> Bool
(Rate -> Rate -> Bool) -> (Rate -> Rate -> Bool) -> Eq Rate
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Rate -> Rate -> Bool
== :: Rate -> Rate -> Bool
$c/= :: Rate -> Rate -> Bool
/= :: Rate -> Rate -> Bool
Eq, Eq Rate
Eq Rate =>
(Rate -> Rate -> Ordering)
-> (Rate -> Rate -> Bool)
-> (Rate -> Rate -> Bool)
-> (Rate -> Rate -> Bool)
-> (Rate -> Rate -> Bool)
-> (Rate -> Rate -> Rate)
-> (Rate -> Rate -> Rate)
-> Ord Rate
Rate -> Rate -> Bool
Rate -> Rate -> Ordering
Rate -> Rate -> Rate
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Rate -> Rate -> Ordering
compare :: Rate -> Rate -> Ordering
$c< :: Rate -> Rate -> Bool
< :: Rate -> Rate -> Bool
$c<= :: Rate -> Rate -> Bool
<= :: Rate -> Rate -> Bool
$c> :: Rate -> Rate -> Bool
> :: Rate -> Rate -> Bool
$c>= :: Rate -> Rate -> Bool
>= :: Rate -> Rate -> Bool
$cmax :: Rate -> Rate -> Rate
max :: Rate -> Rate -> Rate
$cmin :: Rate -> Rate -> Rate
min :: Rate -> Rate -> Rate
Ord, Int -> Rate
Rate -> Int
Rate -> [Rate]
Rate -> Rate
Rate -> Rate -> [Rate]
Rate -> Rate -> Rate -> [Rate]
(Rate -> Rate)
-> (Rate -> Rate)
-> (Int -> Rate)
-> (Rate -> Int)
-> (Rate -> [Rate])
-> (Rate -> Rate -> [Rate])
-> (Rate -> Rate -> [Rate])
-> (Rate -> Rate -> Rate -> [Rate])
-> Enum Rate
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: Rate -> Rate
succ :: Rate -> Rate
$cpred :: Rate -> Rate
pred :: Rate -> Rate
$ctoEnum :: Int -> Rate
toEnum :: Int -> Rate
$cfromEnum :: Rate -> Int
fromEnum :: Rate -> Int
$cenumFrom :: Rate -> [Rate]
enumFrom :: Rate -> [Rate]
$cenumFromThen :: Rate -> Rate -> [Rate]
enumFromThen :: Rate -> Rate -> [Rate]
$cenumFromTo :: Rate -> Rate -> [Rate]
enumFromTo :: Rate -> Rate -> [Rate]
$cenumFromThenTo :: Rate -> Rate -> Rate -> [Rate]
enumFromThenTo :: Rate -> Rate -> Rate -> [Rate]
Enum, Rate
Rate -> Rate -> Bounded Rate
forall a. a -> a -> Bounded a
$cminBound :: Rate
minBound :: Rate
$cmaxBound :: Rate
maxBound :: Rate
Bounded, Int -> Rate -> ShowS
[Rate] -> ShowS
Rate -> String
(Int -> Rate -> ShowS)
-> (Rate -> String) -> ([Rate] -> ShowS) -> Show Rate
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Rate -> ShowS
showsPrec :: Int -> Rate -> ShowS
$cshow :: Rate -> String
show :: Rate -> String
$cshowList :: [Rate] -> ShowS
showList :: [Rate] -> ShowS
Show, ReadPrec [Rate]
ReadPrec Rate
Int -> ReadS Rate
ReadS [Rate]
(Int -> ReadS Rate)
-> ReadS [Rate] -> ReadPrec Rate -> ReadPrec [Rate] -> Read Rate
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS Rate
readsPrec :: Int -> ReadS Rate
$creadList :: ReadS [Rate]
readList :: ReadS [Rate]
$creadPrec :: ReadPrec Rate
readPrec :: ReadPrec Rate
$creadListPrec :: ReadPrec [Rate]
readListPrec :: ReadPrec [Rate]
Read)

{- | Standard abbreviations of Rate values.
ir = initialisation, kr = control, ar = audio, dr = demand.
dr sorts to the right of the fixed clock rates.

> Data.List.sort [dr,ar,kr,ir] == [ir,kr,ar,dr]
-}
ir, kr, ar, dr :: Rate
ir :: Rate
ir = Rate
InitialisationRate
kr :: Rate
kr = Rate
ControlRate
ar :: Rate
ar = Rate
AudioRate
dr :: Rate
dr = Rate
DemandRate

{- | Standard SuperCollider rate abbreviations.

> map rateAbbrev [minBound .. maxBound] == ["ir","kr","ar","dr"]
-}
rateAbbrev :: Rate -> String
rateAbbrev :: Rate -> String
rateAbbrev Rate
rt =
  String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe
    (ShowS
forall a. HasCallStack => String -> a
error String
"rateAbbrev?")
    (Int -> [(Int, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup (Rate -> Int
forall a. Enum a => a -> Int
fromEnum Rate
rt) ([Int] -> [String] -> [(Int, String)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0 ..] (String -> [String]
words String
"ir kr ar dr")))

{- | Standard SuperCollider rate abbreviations.

> map rateName [minBound .. maxBound] == ["scalar","control","audio","demand"]
-}
rateName :: Rate -> String
rateName :: Rate -> String
rateName Rate
rt =
  String -> Maybe String -> String
forall a. a -> Maybe a -> a
fromMaybe
    (ShowS
forall a. HasCallStack => String -> a
error String
"rateName?")
    (Int -> [(Int, String)] -> Maybe String
forall a b. Eq a => a -> [(a, b)] -> Maybe b
lookup (Rate -> Int
forall a. Enum a => a -> Int
fromEnum Rate
rt) ([Int] -> [String] -> [(Int, String)]
forall a b. [a] -> [b] -> [(a, b)]
zip [Int
0 ..] (String -> [String]
words String
"scalar control audio demand")))

-- | Integer rate identifier, as required for scsynth bytecode.
rateId :: Rate -> Int
rateId :: Rate -> Int
rateId = Rate -> Int
forall a. Enum a => a -> Int
fromEnum

-- | Color identifiers for each 'Rate'.
rate_color :: Rate -> String
rate_color :: Rate -> String
rate_color Rate
r =
  case Rate
r of
    Rate
AudioRate -> String
"black"
    Rate
ControlRate -> String
"blue"
    Rate
InitialisationRate -> String
"yellow"
    Rate
DemandRate -> String
"red"

-- | Set of all 'Rate' values.
all_rates :: [Rate]
all_rates :: [Rate]
all_rates = [Rate
forall a. Bounded a => a
minBound .. Rate
forall a. Bounded a => a
maxBound]

{- | Case insensitive parser for rate.

> Data.Maybe.mapMaybe rate_parse (words "ar kR IR Dr") == [AudioRate,ControlRate,InitialisationRate,DemandRate]
-}
rate_parse :: String -> Maybe Rate
rate_parse :: String -> Maybe Rate
rate_parse String
r =
  case (Char -> Char) -> ShowS
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper String
r of
    String
"AR" -> Rate -> Maybe Rate
forall a. a -> Maybe a
Just Rate
AudioRate
    String
"KR" -> Rate -> Maybe Rate
forall a. a -> Maybe a
Just Rate
ControlRate
    String
"IR" -> Rate -> Maybe Rate
forall a. a -> Maybe a
Just Rate
InitialisationRate
    String
"DR" -> Rate -> Maybe Rate
forall a. a -> Maybe a
Just Rate
DemandRate
    String
_ -> Maybe Rate
forall a. Maybe a
Nothing

-- * Control rates

{- | Enumeration of the four operating rates for controls.
I = initialisation, K = control, T = trigger, A = audio.
-}
data K_Type = K_InitialisationRate | K_ControlRate | K_TriggerRate | K_AudioRate
  deriving (K_Type -> K_Type -> Bool
(K_Type -> K_Type -> Bool)
-> (K_Type -> K_Type -> Bool) -> Eq K_Type
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: K_Type -> K_Type -> Bool
== :: K_Type -> K_Type -> Bool
$c/= :: K_Type -> K_Type -> Bool
/= :: K_Type -> K_Type -> Bool
Eq, Int -> K_Type -> ShowS
[K_Type] -> ShowS
K_Type -> String
(Int -> K_Type -> ShowS)
-> (K_Type -> String) -> ([K_Type] -> ShowS) -> Show K_Type
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> K_Type -> ShowS
showsPrec :: Int -> K_Type -> ShowS
$cshow :: K_Type -> String
show :: K_Type -> String
$cshowList :: [K_Type] -> ShowS
showList :: [K_Type] -> ShowS
Show, Eq K_Type
Eq K_Type =>
(K_Type -> K_Type -> Ordering)
-> (K_Type -> K_Type -> Bool)
-> (K_Type -> K_Type -> Bool)
-> (K_Type -> K_Type -> Bool)
-> (K_Type -> K_Type -> Bool)
-> (K_Type -> K_Type -> K_Type)
-> (K_Type -> K_Type -> K_Type)
-> Ord K_Type
K_Type -> K_Type -> Bool
K_Type -> K_Type -> Ordering
K_Type -> K_Type -> K_Type
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: K_Type -> K_Type -> Ordering
compare :: K_Type -> K_Type -> Ordering
$c< :: K_Type -> K_Type -> Bool
< :: K_Type -> K_Type -> Bool
$c<= :: K_Type -> K_Type -> Bool
<= :: K_Type -> K_Type -> Bool
$c> :: K_Type -> K_Type -> Bool
> :: K_Type -> K_Type -> Bool
$c>= :: K_Type -> K_Type -> Bool
>= :: K_Type -> K_Type -> Bool
$cmax :: K_Type -> K_Type -> K_Type
max :: K_Type -> K_Type -> K_Type
$cmin :: K_Type -> K_Type -> K_Type
min :: K_Type -> K_Type -> K_Type
Ord)

-- | Determine class of control given 'Rate' and /trigger/ status.
ktype :: Rate -> Bool -> K_Type
ktype :: Rate -> Bool -> K_Type
ktype Rate
r Bool
tr =
  if Bool
tr
    then case Rate
r of
      Rate
ControlRate -> K_Type
K_TriggerRate
      Rate
_ -> String -> K_Type
forall a. HasCallStack => String -> a
error String
"ktype: non ControlRate trigger control"
    else case Rate
r of
      Rate
InitialisationRate -> K_Type
K_InitialisationRate
      Rate
ControlRate -> K_Type
K_ControlRate
      Rate
AudioRate -> K_Type
K_AudioRate
      Rate
DemandRate -> String -> K_Type
forall a. HasCallStack => String -> a
error String
"ktype: DemandRate control"