{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
module Synthesizer.Filter.Basic where

import qualified Algebra.Transcendental as Trans
import qualified Algebra.Module         as Module
import qualified Algebra.RealRing      as RealRing
import qualified Number.Complex         as Complex

import NumericPrelude.Numeric
import NumericPrelude.Base

{- ToDo:
    - support of data before time 0
       - the problem is that all past data has to be kept,
         the garbage collector can't flush it :-(
       - this means we will also need functions for plain lists,
         in this case we can't provide initial conditions to recursive filters
       - the question of initial conditions is especially problematic
         since for Graphs we have no explicit feed back
         where initial conditions can be plugged in
       - thus for two-way signal we must request the user
         to insert initial conditions in every loop of a Graph
         using the Past constructor
    - all of the following filter primitives in static and modulated form:
       - mask
       - integer delay
       - fractional delay
          - shall the fractional delay constructor store the interpolation type?
            (this discussion is similar to the one concerning
             initial conditions for recursive filters)
             - yes, because each delay may use a different interpolation type,
                    if no fractional delay is used,
                     no interpolation type needs to be specified
             - no, because the interpolation is only of interest for filter
                   application not for the transfer function
    - Is there a way to avoid the multi-parameter type class?
       - Can we provide a class for lists (OneWay and TwoWay)
         that help implementing filters and filter networks?
       - The 'transferFunction' obviously does not depend on the signal list type.
    - 'transferFunction' should not be restricted to complex numbers.
       - For arguments of type 'Ratio (Polynomial Rational)'
         you could compute the transfer function in terms of a rational function.
-}

screw :: Trans.C a => a -> [Complex.T a]
screw w = iterate (Complex.cis w *) 1


class Filter list filter | filter -> list where
   {-| Apply a filter to a signal. -}
   apply :: (RealRing.C t, Trans.C t,
             Module.C a v, Module.C a (list v)) =>
               filter t a v -> list v -> list v
   {-| Compute the complex amplification factor
       that is applied to the given frequency. -}
   transferFunction :: (Trans.C t, Module.C a t) =>
               filter t a v -> t -> Complex.T t