{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{- |
Copyright   :  (c) Henning Thielemann 2008
License     :  GPL

Maintainer  :  synthesizer@henning-thielemann.de
Stability   :  provisional
Portability :  requires multi-parameter type classes

Class that allows unified handling of
@SigS.T@ and @Sig.D Dim.Scalar@
which is often used for control curves.
module Synthesizer.Dimensional.Abstraction.Flat where

import qualified Synthesizer.Dimensional.Amplitude as Amp
import qualified Synthesizer.Dimensional.RatePhantom as RP
import qualified Synthesizer.Dimensional.Straight.Signal as SigS
import qualified Synthesizer.Dimensional.Amplitude.Signal as SigA

import qualified Synthesizer.State.Signal as Sig

import qualified Number.DimensionTerm        as DN
import qualified Algebra.DimensionTerm       as Dim

import qualified Algebra.Module         as Module
import qualified Algebra.Field          as Field
import qualified Algebra.Ring           as Ring

-- import Number.DimensionTerm ((&/&))

-- import NumericPrelude
import PreludeBase
-- import Prelude ()

toSamples :: C sig y => RP.T s sig y -> Sig.T y
toSamples = unwrappedToSamples . RP.toSignal

class C sig y where
   unwrappedToSamples :: sig y -> Sig.T y

instance C Sig.T y where
   unwrappedToSamples = id

instance C sig y => C (SigS.T sig) y where
   unwrappedToSamples = unwrappedToSamples . SigS.samples

instance (Dim.IsScalar scalar, Module.C y yv) => C (SigA.D scalar y) yv where
   toSamples =
      SigA.vectorSamples (DN.toNumber . DN.rewriteDimension Dim.toScalar)

instance (C flat y, OccScalar.C y amp, Amp.C amp, Ring.C y) =>
             C (SigA.T amp flat) y where
   unwrappedToSamples =
      SigA.scalarSamples OccScalar.toScalar .
      (\x ->
            (SigA.privateAmplitude x)
            (unwrappedToSamples (SigA.signal x)))

we could use OccasionallyScalar class,
but this would flood user code with OccScalar.C y y constraints
class Amp.C amp => Amplitude y amp where
   toScalar :: amp -> y

instance Ring.C y => Amplitude y Amp.Flat where
   toScalar = const Ring.one

instance (Dim.IsScalar v) => Amplitude y (DN.T v y) where
   toScalar = DN.toNumber . DN.rewriteDimension Dim.toScalar

instance (C flat y, Amplitude y amp, Ring.C y) =>
             C (SigA.T amp flat) y where
   unwrappedToSamples =
      SigA.scalarSamples toScalar .
      (\x ->
            (SigA.privateAmplitude x)
            (unwrappedToSamples (SigA.signal x)))