module Csound.Typed.Plugins.Diode(
    diode, linDiode, noNormDiode
) where

import Csound.Dynamic

import Csound.Typed.Types
import Csound.Typed.GlobalState
import qualified Csound.Typed.GlobalState.Elements as E(diodePlugin)

-- | Linear diode ladder filter.
--
-- > linDiode centerFrequency resonance asig
--
-- resonance ranges in the interval [0, 1] and higher.
-- self-resonance occurs at 1.
linDiode :: Sig -> Sig -> Sig -> Sig
linDiode :: Sig -> Sig -> Sig -> Sig
linDiode Sig
cfq Sig
res Sig
ain = Sig -> Sig -> Sig -> Sig -> Sig -> Sig
diodeLadder Sig
ain Sig
cfq (Sig -> Sig
normReson Sig
res) Sig
0 Sig
1

-- | Non-Linear normalized diode ladder filter.
--
-- > diode saturation centerFrequency resonance asig
--
-- resonance ranges in the interval [0, 1] and higher.
-- self-resonance occurs at 1.
--
-- saturation ranges from 1 and higher (typical value: 4)
diode :: Sig -> Sig -> Sig -> Sig -> Sig
diode :: Sig -> Sig -> Sig -> Sig -> Sig
diode Sig
ksaturation Sig
cfq Sig
res Sig
ain = Sig -> Sig -> Sig -> Sig -> Sig -> Sig
diodeLadder Sig
ain Sig
cfq (Sig -> Sig
normReson Sig
res) Sig
1 Sig
ksaturation

-- | Non-Linear not normalized diode ladder filter.
--
-- > noNormDiode saturation centerFrequency resonance asig
--
-- resonance ranges in the interval [0, 1] and higher.
-- self-resonance occurs at 1.
--
-- saturation ranges from 1 and higher (typical value: 4)
noNormDiode :: Sig -> Sig -> Sig -> Sig -> Sig
noNormDiode :: Sig -> Sig -> Sig -> Sig -> Sig
noNormDiode Sig
ksaturation Sig
cfq Sig
res Sig
ain = Sig -> Sig -> Sig -> Sig -> Sig -> Sig
diodeLadder Sig
ain Sig
cfq (Sig -> Sig
normReson Sig
res) Sig
2 Sig
ksaturation

normReson :: Sig -> Sig
normReson :: Sig -> Sig
normReson Sig
res = Sig
res Sig -> Sig -> Sig
forall a. Num a => a -> a -> a
* Sig
17

-------------------------------------------------------------------------------

-- | Diode Ladder Filter
--
-- Based on code by Will Pirkle, presented in:
--
-- http://www.willpirkle.com/Downloads/AN-6DiodeLadderFilter.pdf
--
-- and in his book "Designing software synthesizer plug-ins in C++ : for
-- RackAFX, VST3, and Audio Units"
--
-- UDO version by Steven Yi (2016.xx.xx)
--
-- ARGS
-- ain - signal to filter
-- acf/kcf - cutoff frequency
-- ak/kk  - k-value that controls resonance, self-resonance occurs at k=17;
-- knlp - use non-linear processing:
--        0 - none
--        1 - normalized (outputs to range +-1.0)
--        2 - non-normalized (less expensive than normalized, range +-0.8)
-- ksaturation - saturation amount for non-linear processing
--        (default: 1.0, greater values lead to higher saturation)
diodeLadder :: Sig -> Sig -> Sig -> Sig -> Sig -> Sig
diodeLadder :: Sig -> Sig -> Sig -> Sig -> Sig -> Sig
diodeLadder Sig
ain Sig
xcf Sig
xk Sig
knlp Sig
ksaturation = GE E -> Sig
forall a. Val a => GE E -> a
fromGE (GE E -> Sig) -> GE E -> Sig
forall a b. (a -> b) -> a -> b
$ do
    UdoPlugin -> GE ()
addUdoPlugin UdoPlugin
E.diodePlugin
    E -> E -> E -> E -> E -> E
f (E -> E -> E -> E -> E -> E) -> GE E -> GE (E -> E -> E -> E -> E)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Sig -> GE E
forall a. Val a => a -> GE E
toGE Sig
ain GE (E -> E -> E -> E -> E) -> GE E -> GE (E -> E -> E -> E)
forall a b. GE (a -> b) -> GE a -> GE b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Sig -> GE E
forall a. Val a => a -> GE E
toGE Sig
xcf GE (E -> E -> E -> E) -> GE E -> GE (E -> E -> E)
forall a b. GE (a -> b) -> GE a -> GE b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Sig -> GE E
forall a. Val a => a -> GE E
toGE Sig
xk GE (E -> E -> E) -> GE E -> GE (E -> E)
forall a b. GE (a -> b) -> GE a -> GE b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Sig -> GE E
forall a. Val a => a -> GE E
toGE Sig
knlp GE (E -> E) -> GE E -> GE E
forall a b. GE (a -> b) -> GE a -> GE b
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> Sig -> GE E
forall a. Val a => a -> GE E
toGE Sig
ksaturation
    where f :: E -> E -> E -> E -> E -> E
f E
ain' E
xcf' E
xk' E
knlp' E
ksaturation' = Name -> Spec1 -> [E] -> E
opcs Name
"diode_ladder" [(Rate
Ar, [Rate
Ar, Rate
Xr, Rate
Xr, Rate
Kr, Rate
Kr])] [E
ain', E
xcf', E
xk', E
knlp', E
ksaturation']