module Csound.Typed.Plugins.TapeEcho(
    tapeRead
  , tapeWrite
  , tapeEcho
) where

import Control.Monad.Trans.Class
import Csound.Dynamic

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

-- | Function to read from tape.
--
--  > tapeRead aIn, kDelay, kRandomSpread
--
-- The function is used in the same manner as deltapi
--  first init the delay buffer and the use tapeRead.
--
--  aIn - input signal
--  kDelay - delay time
--  kRandomSpread - [0, Inf] - the random spread of reading from the tape
--     the higher the worser the quality of the tape.
-- opcode tapeRead, a, akk
tapeRead :: Sig -> Sig -> Sig -> SE Sig
tapeRead :: Sig -> Sig -> Sig -> SE Sig
tapeRead Sig
ain Sig
kdel Sig
kRandomSpread = (E -> Sig) -> SE E -> SE Sig
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (GE E -> Sig
Sig (GE E -> Sig) -> (E -> GE E) -> E -> Sig
forall b c a. (b -> c) -> (a -> b) -> a -> c
. E -> GE E
forall (m :: * -> *) a. Monad m => a -> m a
return) (SE E -> SE Sig) -> SE E -> SE Sig
forall a b. (a -> b) -> a -> b
$ Dep E -> SE E
forall a. Dep a -> SE a
SE (Dep E -> SE E) -> Dep E -> SE E
forall a b. (a -> b) -> a -> b
$ (E -> Dep E
forall (m :: * -> *). Monad m => E -> DepT m E
depT (E -> Dep E) -> Dep E -> Dep E
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<) (Dep E -> Dep E) -> Dep E -> Dep E
forall a b. (a -> b) -> a -> b
$ GE E -> Dep E
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (GE E -> Dep E) -> GE E -> Dep E
forall a b. (a -> b) -> a -> b
$ do
  UdoPlugin -> GE ()
addUdoPlugin UdoPlugin
E.tapeEchoPlugin
  E -> E -> E -> E
f (E -> E -> E -> E) -> GE E -> GE (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) -> GE E -> GE (E -> E)
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
kdel GE (E -> E) -> GE E -> GE E
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
kRandomSpread
  where f :: E -> E -> E -> E
f E
ain' E
kdel' E
krand' = Name -> Spec1 -> [E] -> E
opcs Name
"tapeRead" [(Rate
Ar, [Rate
Ar, Rate
Kr, Rate
Kr])] [E
ain', E
kdel', E
krand']


-- | Function to write to tape
--
-- > tapeWrite aIn, aOut, kFbGain
--
-- It should be though of as delayw for magnetic tape.
--
-- aIn - input signal
-- aOut - output signal
-- kFbGain - gain of feedback [0, 2]
tapeWrite :: Sig -> Sig -> Sig -> SE ()
tapeWrite :: Sig -> Sig -> Sig -> SE ()
tapeWrite Sig
ain Sig
aout Sig
kFeedback = Dep () -> SE ()
forall a. Dep a -> SE a
SE (Dep () -> SE ()) -> Dep () -> SE ()
forall a b. (a -> b) -> a -> b
$ (E -> Dep ()
forall (m :: * -> *). Monad m => E -> DepT m ()
depT_ (E -> Dep ()) -> Dep E -> Dep ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<<) (Dep E -> Dep ()) -> Dep E -> Dep ()
forall a b. (a -> b) -> a -> b
$ GE E -> Dep E
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (GE E -> Dep E) -> GE E -> Dep E
forall a b. (a -> b) -> a -> b
$ do
  E -> E -> E -> E
f (E -> E -> E -> E) -> GE E -> GE (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) -> GE E -> GE (E -> E)
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
aout GE (E -> E) -> GE E -> GE E
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
kFeedback
  where f :: E -> E -> E -> E
f E
ain' E
aout' E
kfb' = Name -> Spec1 -> [E] -> E
opcs Name
"tapeWrite" [(Rate
Xr, [Rate
Ar, Rate
Ar, Rate
Kr])] [E
ain', E
aout', E
kfb']

-- | Generic multi-tap echo opcode.
--
-- > tapeEcho iSize kDelay kEchoGain kFbGain kTone kRandomSpread aIn
--
-- * iSize - how many units of echo
-- * kDelay - delay time
-- * kEchoGain - gain of the echoes
-- * kFbGain - feedback
-- * kTone - low pass filter frequency
-- * kRandomSpread - quality of the tape [0, Inf], the higher the worser the quality of the tape.
-- * aIn - input signal
tapeEcho :: D -> Sig -> Sig -> Sig -> Sig -> Sig -> Sig -> Sig
tapeEcho :: D -> Sig -> Sig -> Sig -> Sig -> Sig -> Sig -> Sig
tapeEcho D
iSize Sig
kDelay Sig
kEchoGain Sig
kFbGain Sig
kTone Sig
kRandomSpread Sig
aIn = 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.tapeEchoPlugin
  E -> E -> E -> E -> E -> E -> E -> E
f (E -> E -> E -> E -> E -> E -> E -> E)
-> GE E -> GE (E -> E -> 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 -> E -> E)
-> GE E -> GE (E -> E -> E -> E -> E -> E)
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
kDelay GE (E -> E -> E -> E -> E -> E)
-> GE E -> GE (E -> E -> E -> E -> E)
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
kEchoGain GE (E -> E -> E -> E -> E) -> GE E -> GE (E -> E -> E -> E)
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
kFbGain GE (E -> E -> E -> E) -> GE E -> GE (E -> E -> E)
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
kTone GE (E -> E -> E) -> GE E -> GE (E -> E)
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
kRandomSpread GE (E -> E) -> GE E -> GE E
forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> D -> GE E
forall a. Val a => a -> GE E
toGE D
iSize
  where f :: E -> E -> E -> E -> E -> E -> E -> E
f E
aIn' E
kDelay' E
kEchoGain' E
kFbGain' E
kTone' E
kRandomSpread' E
iSize' = Name -> Spec1 -> [E] -> E
opcs Name
"TapeEchoN" [(Rate
Ar, [Rate
Ar, Rate
Kr, Rate
Kr, Rate
Kr, Rate
Kr, Rate
Kr, Rate
Ir])] [E
aIn', E
kDelay', E
kEchoGain', E
kFbGain', E
kTone', E
kRandomSpread', E
iSize']