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

import Data.Boolean
import Control.Monad.Trans.Class
import Control.Applicative

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 cfq res ain = diodeLadder ain cfq (normReson res) 0 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 ksaturation cfq res ain = diodeLadder ain cfq (normReson res) 1 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 ksaturation cfq res ain = diodeLadder ain cfq (normReson res) 2 ksaturation

normReson :: Sig -> Sig
normReson res = res * 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 ain xcf xk knlp ksaturation = fromGE $ do
    addUdoPlugin E.diodePlugin
    f <$> toGE ain <*> toGE xcf <*> toGE xk <*> toGE knlp <*> toGE ksaturation
    where f ain xcf xk knlp ksaturation = opcs "diode_ladder" [(Ar, [Ar, Xr, Xr, Kr, Kr])] [ain, xcf, xk, knlp, ksaturation]