{-# LANGUAGE NoImplicitPrelude #-}
{- |
An implementation of a Delay using a classical circular buffer
running in the State Thread monad.
module Synthesizer.Plain.Filter.Delay.ST where

import qualified Synthesizer.Plain.Interpolation as Interpolation

import qualified Algebra.RealField as RealField
import qualified Algebra.Additive  as Additive

import Control.Monad.ST.Lazy(runST,strictToLazyST,ST)
import Data.Array.ST

import qualified Prelude as P
import NumericPrelude.Base
import NumericPrelude.Numeric

I had no success in hiding ST in the 'modulatedST' function.
The explicit type signature is crucial.
modulatedAction :: (RealField.C a, Additive.C v) =>
   Interpolation.T a v -> Int -> [a] -> [v] -> ST s [v]
modulatedAction ip size ts xs =
   let ipNum  = Interpolation.number ip
       ipFunc = Interpolation.func   ip
   in  do arr <- strictToLazyST (newArray (0,2*size-1) zero)
                    :: Additive.C v => ST s (STArray s Int v)
          mapM (\(n,t,x) -> strictToLazyST $
                  do writeArray arr n x
                     writeArray arr (n+size) x
                     let (ti,tf) = splitFraction t
                     y <- mapM (readArray arr) (take ipNum [(n+ti) ..])
                     return (if ti<0
                               then error "negative delay"
                                 if size < ti+ipNum
                                   then error "too much delay"
                                   else ipFunc tf y))
               (zip3 (cycle [(size-1),(size-2)..0]) ts xs)

modulated :: (RealField.C a, Additive.C v) =>
   Interpolation.T a v -> Int -> [a] -> [v] -> [v]
modulated ip maxDelay ts xs =
   let offset = Interpolation.offset ip
   in  drop offset
                ip (maxDelay + Interpolation.number ip)
                (replicate offset zero ++ ts) xs))