-- | The fixities of the operators ("~+", "~*", "~<", etc) are the same as those of
--   their non-'~' equivalents (+, *, < etc)
--
--   (So you can e.g. multiply then add without parens!)

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies, NoMonoLocalBinds #-}

{-# LANGUAGE NoIncoherentInstances #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE NoUndecidableInstances #-}

module Vivid.UGens.Algebraic (
     (~+)
   , (~-)
   , (~*)
   , (~**)
   , (~/)

{- -- removed these to be compatible with tidal, which also uses some of these:
   , (~>)
   , (~>=)
   , (~<)
   , (~<=)
-}
   , binaryOp
   , biOp
   , unaryOp
   , uOp
   , midiCPS
   , cpsMIDI
   , abs'
   , neg
   , tanh'
   , clip2
   , xor
   ) where

import Vivid.SynthDef
-- import Vivid.UGens.Args

import Prelude

infixl 7 ~*
-- | Multiply signals
(~*) :: (ToSig i0 a, ToSig i1 a) => i0 -> i1 -> SDBody' a Signal
~* :: i0 -> i1 -> SDBody' a Signal
(~*) = BinaryOp -> i0 -> i1 -> SDBody' a Signal
forall s0 (a :: [Symbol]) s1.
(ToSig s0 a, ToSig s1 a) =>
BinaryOp -> s0 -> s1 -> SDBody' a Signal
binaryOp BinaryOp
Mul

infixr 8 ~**
-- | Exponentiation of signals
(~**) :: (ToSig i0 a, ToSig i1 a) => i0 -> i1 -> SDBody' a Signal
~** :: i0 -> i1 -> SDBody' a Signal
(~**) = BinaryOp -> i0 -> i1 -> SDBody' a Signal
forall s0 (a :: [Symbol]) s1.
(ToSig s0 a, ToSig s1 a) =>
BinaryOp -> s0 -> s1 -> SDBody' a Signal
binaryOp BinaryOp
Pow

infixl 6 ~+
-- | Add signals
(~+) :: (ToSig i0 a, ToSig i1 a) => i0 -> i1 -> SDBody' a Signal
~+ :: i0 -> i1 -> SDBody' a Signal
(~+) = BinaryOp -> i0 -> i1 -> SDBody' a Signal
forall s0 (a :: [Symbol]) s1.
(ToSig s0 a, ToSig s1 a) =>
BinaryOp -> s0 -> s1 -> SDBody' a Signal
binaryOp BinaryOp
Add

infixl 7 ~/
-- | Divide signals
(~/) :: (ToSig i0 a, ToSig i1 a) => i0 -> i1 -> SDBody' a Signal
~/ :: i0 -> i1 -> SDBody' a Signal
(~/) = BinaryOp -> i0 -> i1 -> SDBody' a Signal
forall s0 (a :: [Symbol]) s1.
(ToSig s0 a, ToSig s1 a) =>
BinaryOp -> s0 -> s1 -> SDBody' a Signal
binaryOp BinaryOp
FDiv

{-
infix 4 ~>
-- | Test signals for left greater than right
(~>) :: (ToSig i0 a, ToSig i1 a) => i0 -> i1 -> SDBody' a Signal
(~>) = binaryOp Gt

infix 4 ~>=
-- | Test signals for left greater than or equal to right
(~>=) :: (ToSig i0 a, ToSig i1 a) => i0 -> i1 -> SDBody' a Signal
(~>=) = binaryOp Ge

infix 4 ~<
-- | Test signals for left less than right
(~<) :: (ToSig i0 a, ToSig i1 a) => i0 -> i1 -> SDBody' a Signal
(~<) = binaryOp Lt

infix 4 ~<=
-- | Test signals for left less than or equal to right
(~<=) :: (ToSig i0 a, ToSig i1 a) => i0 -> i1 -> SDBody' a Signal
(~<=) = binaryOp Le
-}

infixl 6 ~-
-- | Subtract signals
(~-) :: (ToSig i0 a, ToSig i1 a) => i0 -> i1 -> SDBody' a Signal
~- :: i0 -> i1 -> SDBody' a Signal
(~-) = BinaryOp -> i0 -> i1 -> SDBody' a Signal
forall s0 (a :: [Symbol]) s1.
(ToSig s0 a, ToSig s1 a) =>
BinaryOp -> s0 -> s1 -> SDBody' a Signal
binaryOp BinaryOp
Sub

-- | Build your own!
-- 
--   The calculation rate of the result is the larger (more frequent) of the 2 input
--   signals
--   (So you shouldn't need to use "?" very much!)
binaryOp :: (ToSig s0 a, ToSig s1 a) => BinaryOp -> s0 -> s1 -> SDBody' a Signal
binaryOp :: BinaryOp -> s0 -> s1 -> SDBody' a Signal
binaryOp BinaryOp
theBiOp s0
s0 s1
s1 = do
   Signal
s0' <- s0 -> SDBody' a Signal
forall s (args :: [Symbol]).
ToSig s args =>
s -> SDBody' args Signal
toSig s0
s0
   Signal
s1' <-  s1 -> SDBody' a Signal
forall s (args :: [Symbol]).
ToSig s args =>
s -> SDBody' args Signal
toSig s1
s1
   CalculationRate
calcRate <- CalculationRate -> CalculationRate -> CalculationRate
forall a. Ord a => a -> a -> a
max (CalculationRate -> CalculationRate -> CalculationRate)
-> StateT ([Int], SynthDef a, VarSet a) Identity CalculationRate
-> StateT
     ([Int], SynthDef a, VarSet a)
     Identity
     (CalculationRate -> CalculationRate)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Signal
-> StateT ([Int], SynthDef a, VarSet a) Identity CalculationRate
forall (args :: [Symbol]). Signal -> SDBody' args CalculationRate
getCalcRate Signal
s0' StateT
  ([Int], SynthDef a, VarSet a)
  Identity
  (CalculationRate -> CalculationRate)
-> StateT ([Int], SynthDef a, VarSet a) Identity CalculationRate
-> StateT ([Int], SynthDef a, VarSet a) Identity CalculationRate
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Signal
-> StateT ([Int], SynthDef a, VarSet a) Identity CalculationRate
forall (args :: [Symbol]). Signal -> SDBody' args CalculationRate
getCalcRate Signal
s1'
   let sigs :: [Signal]
sigs = [Signal
s0', Signal
s1']
   UGen -> SDBody' a Signal
forall (args :: [Symbol]). UGen -> SDBody' args Signal
addUGen (UGen -> SDBody' a Signal) -> UGen -> SDBody' a Signal
forall a b. (a -> b) -> a -> b
$ UGenName -> CalculationRate -> [Signal] -> Int -> UGen
UGen (BinaryOp -> UGenName
UGName_B BinaryOp
theBiOp) CalculationRate
calcRate [Signal]
sigs Int
1

-- | Alias of 'binaryOp'. Shorter, fer livecodin
biOp :: (ToSig s0 a, ToSig s1 a) => BinaryOp -> s0 -> s1 -> SDBody' a Signal
biOp :: BinaryOp -> s0 -> s1 -> SDBody' a Signal
biOp = BinaryOp -> s0 -> s1 -> SDBody' a Signal
forall s0 (a :: [Symbol]) s1.
(ToSig s0 a, ToSig s1 a) =>
BinaryOp -> s0 -> s1 -> SDBody' a Signal
binaryOp

-- | Build your own, from 'UnaryOp's
unaryOp :: (ToSig sig a) => UnaryOp -> sig -> SDBody' a Signal
unaryOp :: UnaryOp -> sig -> SDBody' a Signal
unaryOp UnaryOp
theUOp sig
sig = do
   Signal
sig' <- sig -> SDBody' a Signal
forall s (args :: [Symbol]).
ToSig s args =>
s -> SDBody' args Signal
toSig sig
sig
   CalculationRate
calcRate <- Signal -> SDBody' a CalculationRate
forall (args :: [Symbol]). Signal -> SDBody' args CalculationRate
getCalcRate Signal
sig'
   UGen -> SDBody' a Signal
forall (args :: [Symbol]). UGen -> SDBody' args Signal
addUGen (UGen -> SDBody' a Signal) -> UGen -> SDBody' a Signal
forall a b. (a -> b) -> a -> b
$ UGenName -> CalculationRate -> [Signal] -> Int -> UGen
UGen (UnaryOp -> UGenName
UGName_U UnaryOp
theUOp) CalculationRate
calcRate [Signal
sig'] Int
1

-- | Alias of 'unaryOp'
uOp :: (ToSig sig a) => UnaryOp -> sig -> SDBody' a Signal
uOp :: UnaryOp -> sig -> SDBody' a Signal
uOp = UnaryOp -> sig -> SDBody' a Signal
forall sig (a :: [Symbol]).
ToSig sig a =>
UnaryOp -> sig -> SDBody' a Signal
unaryOp

-- | Convert from a midi note number (0-127, each representing a musical half step) to a
--   frequency in hz (cycles per second)
midiCPS :: (ToSig i a) => i -> SDBody' a Signal
midiCPS :: i -> SDBody' a Signal
midiCPS = UnaryOp -> i -> SDBody' a Signal
forall sig (a :: [Symbol]).
ToSig sig a =>
UnaryOp -> sig -> SDBody' a Signal
unaryOp UnaryOp
MIDICPS

-- | Inverse of 'midiCPS'
cpsMIDI :: (ToSig i a) => i -> SDBody' a Signal
cpsMIDI :: i -> SDBody' a Signal
cpsMIDI = UnaryOp -> i -> SDBody' a Signal
forall sig (a :: [Symbol]).
ToSig sig a =>
UnaryOp -> sig -> SDBody' a Signal
unaryOp UnaryOp
CPSMIDI



-- | The prime is to not conflict with \"abs\" in the prelude. May just use
--   \"uOp Abs\" in the future
abs' :: (ToSig i a) => i -> SDBody' a Signal
abs' :: i -> SDBody' a Signal
abs' = UnaryOp -> i -> SDBody' a Signal
forall sig (a :: [Symbol]).
ToSig sig a =>
UnaryOp -> sig -> SDBody' a Signal
unaryOp UnaryOp
Abs

neg :: (ToSig i a) => i -> SDBody' a Signal
neg :: i -> SDBody' a Signal
neg = UnaryOp -> i -> SDBody' a Signal
forall sig (a :: [Symbol]).
ToSig sig a =>
UnaryOp -> sig -> SDBody' a Signal
unaryOp UnaryOp
Neg

-- | The prime, like 'abs'', is to not conflict with a prelude definition.
-- 
--   Remember you can always just use:
-- 
--   > uOp TanH
tanh' :: ToSig i a => i -> SDBody' a Signal
tanh' :: i -> SDBody' a Signal
tanh' i
i = UnaryOp -> i -> SDBody' a Signal
forall sig (a :: [Symbol]).
ToSig sig a =>
UnaryOp -> sig -> SDBody' a Signal
uOp UnaryOp
TanH i
i

-- | Like 'Vivid.UGens.Maths.clip' but the lo value is always negative the hi value
clip2 :: (ToSig s0 a, ToSig s1 a) => s0 -> s1 -> SDBody' a Signal
clip2 :: s0 -> s1 -> SDBody' a Signal
clip2 = BinaryOp -> s0 -> s1 -> SDBody' a Signal
forall s0 (a :: [Symbol]) s1.
(ToSig s0 a, ToSig s1 a) =>
BinaryOp -> s0 -> s1 -> SDBody' a Signal
biOp BinaryOp
Clip2

-- | Bitwise xor. Short for @biOp BitXor@
xor :: (ToSig s0 a, ToSig s1 a) => s0 -> s1 -> SDBody' a Signal
xor :: s0 -> s1 -> SDBody' a Signal
xor = BinaryOp -> s0 -> s1 -> SDBody' a Signal
forall s0 (a :: [Symbol]) s1.
(ToSig s0 a, ToSig s1 a) =>
BinaryOp -> s0 -> s1 -> SDBody' a Signal
biOp BinaryOp
BitXor