-- | Event and Ctl systems for external control interfaces.
module Sound.SC3.UGen.Event where

import Sound.SC3.Common.Rate {- hsc3 -}
import Sound.SC3.UGen.Bindings.DB {- hsc3 -}
import Sound.SC3.UGen.Bindings.Composite {- hsc3 -}
import Sound.SC3.UGen.Type {- hsc3 -}
import Sound.SC3.UGen.UGen {- hsc3 -}

-- * Event

-- | (w/gate,x,y,z/force,orientation,radius-x,radius-y,pitch,pitch-x,pitch-y)
type REvent t = (t,t,t,t,t,t,t,t,t,t)

-- | Translate list to REvent.
rEvent_from_list :: Num t => [t] -> REvent t
rEvent_from_list :: [t] -> REvent t
rEvent_from_list [t]
l =
  case [t]
l of
    [t
w,t
x,t
y,t
z,t
o,t
rx,t
ry,t
p,t
px,t
py] -> (t
w,t
x,t
y,t
z,t
o,t
rx,t
ry,t
p,t
px,t
py)
    [t]
_ -> [Char] -> REvent t
forall a. HasCallStack => [Char] -> a
error [Char]
"rEvent_from_list?"

{- | k0 = index of control bus zero for event system,
    stp = voice index incremennt,
      c = event channel or voice (zero indexed)
-}
rEventAddr :: UGen -> UGen -> UGen -> REvent UGen
rEventAddr :: UGen -> UGen -> UGen -> REvent UGen
rEventAddr UGen
k0 UGen
stp UGen
c =
  let u :: UGen
u = Int -> Rate -> UGen -> UGen
in' Int
10 Rate
KR (UGen
k0 UGen -> UGen -> UGen
forall a. Num a => a -> a -> a
+ (UGen
c UGen -> UGen -> UGen
forall a. Num a => a -> a -> a
* UGen
stp))
  in [UGen] -> REvent UGen
forall t. Num t => [t] -> REvent t
rEvent_from_list (UGen -> [UGen]
mceChannels UGen
u)

-- | c0 = index of voice (channel) zero for event set, n = number of voices (channels)
rEventVoicerAddr :: UGen -> UGen -> UGen -> Int -> (Int -> REvent UGen -> UGen) -> UGen
rEventVoicerAddr :: UGen -> UGen -> UGen -> Int -> (Int -> REvent UGen -> UGen) -> UGen
rEventVoicerAddr UGen
k0 UGen
stp UGen
c0 Int
n Int -> REvent UGen -> UGen
f = [UGen] -> UGen
mce ((Int -> UGen) -> [Int] -> [UGen]
forall a b. (a -> b) -> [a] -> [b]
map (\Int
c -> Int -> REvent UGen -> UGen
f Int
c (UGen -> UGen -> UGen -> REvent UGen
rEventAddr UGen
k0 UGen
stp (UGen
c0 UGen -> UGen -> UGen
forall a. Num a => a -> a -> a
+ Int -> UGen
forall n. Real n => n -> UGen
constant Int
c))) [Int
0 .. Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1])

-- | 'rEventAddr' with 'control' inputs for /eventAddr/, /eventIncr/ and /eventZero/.
rEvent :: REvent UGen
rEvent :: REvent UGen
rEvent = UGen -> UGen -> UGen -> REvent UGen
rEventAddr (Rate -> [Char] -> Double -> UGen
control Rate
KR [Char]
"eventAddr" Double
13000) (Rate -> [Char] -> Double -> UGen
control Rate
KR [Char]
"eventIncr" Double
10) (Rate -> [Char] -> Double -> UGen
control Rate
KR [Char]
"eventZero" Double
0)

-- | 'rEventVoicerAddr' with 'control' inputs for /eventAddr/, /eventIncr/ and /eventZero/.
rEventVoicer :: Int -> (Int -> REvent UGen -> UGen) -> UGen
rEventVoicer :: Int -> (Int -> REvent UGen -> UGen) -> UGen
rEventVoicer = UGen -> UGen -> UGen -> Int -> (Int -> REvent UGen -> UGen) -> UGen
rEventVoicerAddr (Rate -> [Char] -> Double -> UGen
control Rate
KR [Char]
"eventAddr" Double
13000) (Rate -> [Char] -> Double -> UGen
control Rate
KR [Char]
"eventIncr" Double
10) (Rate -> [Char] -> Double -> UGen
control Rate
KR [Char]
"eventZero" Double
0)

{- | Given /g/ and /p/ fields of an 'REvent' derive a 'gateReset' from g
and a trigger derived from monitoring /g/ and /p/ for changed values.
-}
rEventGateReset :: UGen -> UGen -> (UGen, UGen)
rEventGateReset :: UGen -> UGen -> (UGen, UGen)
rEventGateReset UGen
g UGen
p = let tr :: UGen
tr = UGen -> UGen -> UGen
changed UGen
p UGen
0.01 UGen -> UGen -> UGen
forall a. Num a => a -> a -> a
+ UGen -> UGen -> UGen
changed UGen
g UGen
0.01 in (UGen -> UGen -> UGen
forall a. Num a => a -> a -> a
gateReset UGen
g UGen
tr,UGen
tr)

-- * Ctl

-- | Sequence of 16 continous controller inputs in range (0-1).
type RCtl = (UGen,UGen,UGen,UGen,UGen,UGen,UGen,UGen,UGen,UGen,UGen,UGen,UGen,UGen,UGen,UGen)

-- | k0 = index of control bus zero for ctl system, c = ctl channel or voice (zero indexed)
rCtlAddr :: UGen -> UGen -> RCtl
rCtlAddr :: UGen -> UGen -> RCtl
rCtlAddr UGen
k0 UGen
c =
  let u :: UGen
u = Int -> Rate -> UGen -> UGen
in' Int
16 Rate
KR (UGen
k0 UGen -> UGen -> UGen
forall a. Num a => a -> a -> a
+ (UGen
c UGen -> UGen -> UGen
forall a. Num a => a -> a -> a
* UGen
16))
  in case UGen -> [UGen]
mceChannels UGen
u of
       [UGen
cc0,UGen
cc1,UGen
cc2,UGen
cc3,UGen
cc4,UGen
cc5,UGen
cc6,UGen
cc7,UGen
cc8,UGen
cc9,UGen
cc10,UGen
cc11,UGen
cc12,UGen
cc13,UGen
cc14,UGen
cc15] ->
         (UGen
cc0,UGen
cc1,UGen
cc2,UGen
cc3,UGen
cc4,UGen
cc5,UGen
cc6,UGen
cc7,UGen
cc8,UGen
cc9,UGen
cc10,UGen
cc11,UGen
cc12,UGen
cc13,UGen
cc14,UGen
cc15)
       [UGen]
_ -> [Char] -> RCtl
forall a. HasCallStack => [Char] -> a
error [Char]
"rCtlAddr?"

-- | c0 = index of voice (channel) zero for ctl set, n = number of voices (channels)
rCtlVoicerAddr :: UGen -> UGen -> Int -> (Int -> RCtl -> UGen) -> UGen
rCtlVoicerAddr :: UGen -> UGen -> Int -> (Int -> RCtl -> UGen) -> UGen
rCtlVoicerAddr UGen
k0 UGen
c0 Int
n Int -> RCtl -> UGen
f = [UGen] -> UGen
mce ((Int -> UGen) -> [Int] -> [UGen]
forall a b. (a -> b) -> [a] -> [b]
map (\Int
c -> Int -> RCtl -> UGen
f Int
c (UGen -> UGen -> RCtl
rCtlAddr UGen
k0 (UGen
c0 UGen -> UGen -> UGen
forall a. Num a => a -> a -> a
+ Int -> UGen
forall n. Real n => n -> UGen
constant Int
c))) [Int
0 .. Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1])

-- | 'rCtlAddr' with 'control' inputs for /CtlAddr/ and /CtlZero/.
rCtl :: RCtl
rCtl :: RCtl
rCtl = UGen -> UGen -> RCtl
rCtlAddr (Rate -> [Char] -> Double -> UGen
control Rate
KR [Char]
"CtlAddr" Double
11000) (Rate -> [Char] -> Double -> UGen
control Rate
KR [Char]
"CtlZero" Double
0)

-- | 'rCtlVoicerAddr' with 'control' inputs for /CtlAddr/ and /CtlZero/.
rCtlVoicer :: Int -> (Int -> RCtl -> UGen) -> UGen
rCtlVoicer :: Int -> (Int -> RCtl -> UGen) -> UGen
rCtlVoicer = UGen -> UGen -> Int -> (Int -> RCtl -> UGen) -> UGen
rCtlVoicerAddr (Rate -> [Char] -> Double -> UGen
control Rate
KR [Char]
"CtlAddr" Double
11000) (Rate -> [Char] -> Double -> UGen
control Rate
KR [Char]
"CtlZero" Double
0)

-- | First eight elements of RCtl.
type RCtl8 = (UGen,UGen,UGen,UGen,UGen,UGen,UGen,UGen)

-- | Select first eight elements of RCtl.
rCtl_to_rCtl8 :: RCtl -> RCtl8
rCtl_to_rCtl8 :: RCtl -> RCtl8
rCtl_to_rCtl8 (UGen
cc0,UGen
cc1,UGen
cc2,UGen
cc3,UGen
cc4,UGen
cc5,UGen
cc6,UGen
cc7,UGen
_,UGen
_,UGen
_,UGen
_,UGen
_,UGen
_,UGen
_,UGen
_) = (UGen
cc0,UGen
cc1,UGen
cc2,UGen
cc3,UGen
cc4,UGen
cc5,UGen
cc6,UGen
cc7)

-- | 'rCtlVoicer' of 'rCtl_to_rCtl8'
rCtl8Voicer :: Int -> (Int -> RCtl8 -> UGen) -> UGen
rCtl8Voicer :: Int -> (Int -> RCtl8 -> UGen) -> UGen
rCtl8Voicer Int
k0 Int -> RCtl8 -> UGen
f = Int -> (Int -> RCtl -> UGen) -> UGen
rCtlVoicer Int
k0 (\Int
n RCtl
c -> Int -> RCtl8 -> UGen
f Int
n (RCtl -> RCtl8
rCtl_to_rCtl8 RCtl
c))

-- * Names

{- | See SCClassLibrary/Common/Control/Spec:ControlSpec.initClass

"ControlSpec defines the range and curve of a control"
-}
sc3_control_spec :: Fractional t => [(String,(t,t,String))]
sc3_control_spec :: [([Char], (t, t, [Char]))]
sc3_control_spec =
  [([Char]
"amp",(t
0,t
1,[Char]
"amp"))
  ,([Char]
"beats",(t
0,t
20,[Char]
"lin"))
  ,([Char]
"bipolar",(-t
1,t
1,[Char]
"lin"))
  ,([Char]
"boostcut",(-t
20,t
20,[Char]
"lin"))
  ,([Char]
"db",(-t
180,t
0,[Char]
"db"))
  ,([Char]
"delay",(t
0.0001,t
1,[Char]
"exp"))
  ,([Char]
"detune",(-t
20,t
20,[Char]
"lin"))
  ,([Char]
"freq",(t
20,t
20000,[Char]
"exp"))
  ,([Char]
"lofreq",(t
0.1,t
100,[Char]
"exp"))
  ,([Char]
"midfreq",(t
25,t
4200,[Char]
"exp"))
  ,([Char]
"midi",(t
0,t
127,[Char]
"lin"))
  ,([Char]
"midinote",(t
0,t
127,[Char]
"lin"))
  ,([Char]
"midivelocity",(t
1,t
127,[Char]
"lin"))
  ,([Char]
"pan",(-t
1,t
1,[Char]
"lin"))
  ,([Char]
"phase",(t
0,t
6.28318,[Char]
"lin"))
  ,([Char]
"rate",(t
0.125,t
8,[Char]
"exp"))
  ,([Char]
"rq",(t
0.001,t
2,[Char]
"exp"))
  ,([Char]
"unipolar",(t
0,t
1,[Char]
"lin"))
  ,([Char]
"widefreq",(t
0.1,t
20000,[Char]
"exp"))]

{- | See Kyma X Revealed, p.403

"The following EventValue names are associated with initial ranges
other than (0,1). EventValue names are not case-sensitive."

This list adds curve specifiers as strings.

> let x = Data.List.intersect (map fst sc3_control_spec) (map fst kyma_event_value_ranges)
> x == ["beats","boostcut","freq","rate"]
> let c z = let (p,q) = unzip z in let f i = filter (flip elem i . fst) in zip (f p sc3_control_spec) (f q kyma_event_value_ranges)
> c (zip x x)

> c [("lofreq","freqlow"),("midfreq","freqmid")]
> lookup "freqhigh" kyma_event_value_ranges
-}
kyma_event_value_ranges :: Fractional t => [(String,(t,t,String))]
kyma_event_value_ranges :: [([Char], (t, t, [Char]))]
kyma_event_value_ranges =
  [([Char]
"angle",(-t
0.5,t
1.5,[Char]
"lin"))
  ,([Char]
"beats",(t
1,t
16,[Char]
"lin"))
  ,([Char]
"boostcut",(-t
12,t
12,[Char]
"lin"))
  ,([Char]
"bpm",(t
0,t
2000,[Char]
"lin"))
  ,([Char]
"centervalue",(-t
1,t
1,[Char]
"lin"))
  ,([Char]
"coef",(-t
1,t
1,[Char]
"lin"))
  ,([Char]
"cutoff",(t
0,t
10000,[Char]
"exp"))
  ,([Char]
"cycles",(t
0,t
100,[Char]
"lin"))
  ,([Char]
"dcoffset",(-t
1,t
1,[Char]
"lin"))
  ,([Char]
"direction",(-t
1,t
1,[Char]
"lin"))
  ,([Char]
"distance",(-t
2,t
2,[Char]
"lin"))
  ,([Char]
"fmntshift",(t
0.75,t
1.25,[Char]
"lin"))
  ,([Char]
"freq",(t
0,t
10000,[Char]
"exp"))
  ,([Char]
"freqhigh",(t
8000,t
24000,[Char]
"exp")) -- sampleRate / 2
  ,([Char]
"freqjitter",(t
0,t
1,[Char]
"lin"))
  ,([Char]
"freqlow",(t
0,t
1000,[Char]
"exp"))
  ,([Char]
"freqmid",(t
1000,t
8000,[Char]
"exp"))
  ,([Char]
"gain",(t
0,t
10,[Char]
"amp"))
  ,([Char]
"gaindb",(-t
128,t
128,[Char]
"lin"))
  ,([Char]
"interval",(-t
24,t
24,[Char]
"lin"))
  ,([Char]
"keynumber",(t
0,t
127,[Char]
"lin"))
  ,([Char]
"logfreq",(t
0,t
127,[Char]
"lin"))
  ,([Char]
"looplength",(-t
1,t
1,[Char]
"lin"))
  ,([Char]
"offset",(-t
1,t
1,[Char]
"lin"))
  ,([Char]
"onduration",(t
0,t
30,[Char]
"lin"))
  ,([Char]
"panner",(-t
0.5,t
1.5,[Char]
"lin"))
  ,([Char]
"pitch",(t
0,t
127,[Char]
"lin"))
  ,([Char]
"q",(t
0,t
10,[Char]
"lin"))
  ,([Char]
"radius",(-t
2,t
2,[Char]
"lin"))
  ,([Char]
"rate",(t
0,t
2,[Char]
"lin"))
  ,([Char]
"ratio",(t
0,t
100,[Char]
"lin"))
  ,([Char]
"scale",(-t
2,t
2,[Char]
"lin"))
  ,([Char]
"smallInterval",(t
0,t
12,[Char]
"lin"))
  ,([Char]
"steps",(t
1,t
128,[Char]
"lin"))
  ,([Char]
"swing",(t
0,t
0.5,[Char]
"lin"))
  ,([Char]
"threshdb",(-t
60,t
0,[Char]
"lin"))
  ,([Char]
"timeconstant",(t
0.0001,t
5,[Char]
"lin"))
  ,([Char]
"timeindex",(-t
1,t
1,[Char]
"lin"))
  ,([Char]
"tune",(-t
1,t
1,[Char]
"lin"))
  ,([Char]
"upinterval",(t
0,t
24,[Char]
"lin"))]