```{-# OPTIONS -fno-implicit-prelude #-}
module Synthesizer.Generic.Filter.Delay where

import qualified Synthesizer.Generic.Interpolation as Interpolation
import qualified Synthesizer.Generic.SampledValue  as Sample
import qualified Synthesizer.Generic.Signal        as SigG

import qualified Algebra.RealField as RealField

-- import qualified Prelude as P
-- import PreludeBase
import NumericPrelude

{- * Shift -}

{-# INLINE static #-}
static :: (Additive.C y, Sample.C y, SigG.C sig) => Int -> sig y -> sig y

staticPad :: (Sample.C y, SigG.C sig) => y -> Int -> sig y -> sig y

{-# INLINE staticPos #-}
staticPos :: (Additive.C y, Sample.C y, SigG.C sig) => Int -> sig y -> sig y
staticPos n = SigG.append (SigG.replicate n zero)

{-# INLINE staticNeg #-}
staticNeg :: (Sample.C y, SigG.C sig) => Int -> sig y -> sig y
staticNeg = SigG.drop

{-# INLINE modulatedCore #-}
modulatedCore ::
(RealField.C a, Additive.C v, Sample.C a, Sample.C v, SigG.C sig) =>
Interpolation.T sig a v -> Int -> sig a -> sig v -> sig v
modulatedCore ip size =
SigG.zipWithTails
(\t -> Interpolation.single ip (fromIntegral size + t))

{- |
This is essentially different for constant interpolation,
because this function "looks forward"
whereas the other two variants "look backward".
For the symmetric interpolation functions
of linear and cubic interpolation, this does not really matter.
-}
{-# INLINE modulated #-}
modulated ::
(RealField.C a, Additive.C v, Sample.C a, Sample.C v, SigG.C sig) =>
Interpolation.T sig a v -> Int -> sig a -> sig v -> sig v
modulated ip minDev ts xs =
let size = Interpolation.number ip - minDev
in  modulatedCore ip
(size - Interpolation.offset ip)
ts
(staticPos size xs)
```