{-# OPTIONS -fno-implicit-prelude #-}
{- |
Copyright   :  (c) Henning Thielemann 2008
License     :  GPL

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

-}
module Synthesizer.Dimensional.Rate.Oscillator (
   {- * Oscillators with constant waveforms -}
   static,
   staticAntiAlias,
   freqMod,
   freqModAntiAlias,
   phaseMod,
   phaseFreqMod,
   shapeMod,
   shapeFreqMod,
   staticSample,
   freqModSample,
) where

import qualified Synthesizer.Dimensional.Abstraction.Flat as Flat

import qualified Synthesizer.Dimensional.RatePhantom as RP

import qualified Synthesizer.State.Oscillator as Osci
import qualified Synthesizer.State.Signal as Sig

import qualified Synthesizer.Basic.WaveSmoothed as WaveSmooth
import qualified Synthesizer.Basic.Wave         as Wave
import qualified Synthesizer.Basic.Phase        as Phase

import qualified Synthesizer.Dimensional.Straight.Signal as SigS
import qualified Synthesizer.Dimensional.Cyclic.Signal as SigC

import qualified Synthesizer.Dimensional.Amplitude.Signal as SigA
import qualified Synthesizer.Dimensional.Process as Proc
import Synthesizer.Dimensional.Process (toFrequencyScalar, )

import qualified Synthesizer.State.Interpolation as Interpolation

import qualified Number.DimensionTerm        as DN
import qualified Algebra.DimensionTerm       as Dim
-- import Number.DimensionTerm ((&*&))

import qualified Algebra.RealField          as RealField
import qualified Algebra.Field              as Field

-- import NumericPrelude
import PreludeBase as P


{- * Oscillators with constant waveforms -}

{- | oscillator with a functional waveform with constant frequency -}
{-# INLINE static #-}
static :: (RealField.C t, Dim.C u) =>
      Wave.T t y   {- ^ waveform -}
   -> Phase.T t    {- ^ start phase from the range [0,1] -}
   -> DN.T (Dim.Recip u) t
                   {- ^ frequency -}
   -> Proc.T s u t (SigS.R s y)
static wave phase =
   staticAux (SigS.fromSamples . Osci.static wave phase)

{- | oscillator with a functional waveform with constant frequency -}
{-# INLINE staticAntiAlias #-}
staticAntiAlias :: (RealField.C t, Dim.C u) =>
      WaveSmooth.T t y
                   {- ^ waveform -}
   -> Phase.T t    {- ^ start phase from the range [0,1] -}
   -> DN.T (Dim.Recip u) t
                   {- ^ frequency -}
   -> Proc.T s u t (SigS.R s y)
staticAntiAlias wave phase =
   staticAux (SigS.fromSamples . Osci.staticAntiAlias wave phase)

{- | oscillator with a functional waveform with modulated frequency -}
{-# INLINE freqMod #-}
freqMod :: (RealField.C t, Dim.C u) =>
      Wave.T t y   {- ^ waveform -}
   -> Phase.T t    {- ^ start phase from the range [0,1] -}
   -> Proc.T s u t (
        SigA.R s (Dim.Recip u) t t
                   {- v frequency control -}
     -> SigS.R s y)
freqMod wave phase =
   freqModAux (SigS.fromSamples . Osci.freqMod wave phase)

{- | oscillator with a functional waveform with modulated frequency -}
{-# INLINE freqModAntiAlias #-}
freqModAntiAlias :: (RealField.C t, Dim.C u) =>
      WaveSmooth.T t y
                   {- ^ waveform -}
   -> Phase.T t    {- ^ start phase from the range [0,1] -}
   -> Proc.T s u t (
        SigA.R s (Dim.Recip u) t t
                   {- v frequency control -}
     -> SigS.R s y)
freqModAntiAlias wave phase =
   freqModAux (SigS.fromSamples . Osci.freqModAntiAlias wave phase)

{- | oscillator with modulated phase -}
{-# INLINE phaseMod #-}
phaseMod :: (Flat.C flat t, RealField.C t, Dim.C u) =>
      Wave.T t y   {- ^ waveform -}
   -> DN.T (Dim.Recip u) t
                   {- ^ frequency -}
   -> Proc.T s u t (
        RP.T s flat t
                   {- v phase modulation, phases must have no unit and
                        are from range [0,1] -}
     -> SigS.R s y)
phaseMod wave =
   staticAux (\freq -> SigS.fromSamples . Osci.phaseMod wave freq . Flat.toSamples)

{- | oscillator with modulated shape -}
{-# INLINE shapeMod #-}
shapeMod :: (Flat.C flat c, RealField.C t, Dim.C u) =>
      (c -> Wave.T t y)
                   {- ^ waveform -}
   -> Phase.T t    {- ^ phase -}
   -> DN.T (Dim.Recip u) t
                   {- ^ frequency -}
   -> Proc.T s u t (
        RP.T s flat c {- v shape control -}
     -> SigS.R s y)
shapeMod wave phase =
   staticAux (\freq -> SigS.fromSamples . Osci.shapeMod wave phase freq . Flat.toSamples)


{- | oscillator with a functional waveform with modulated phase and frequency -}
{-# INLINE phaseFreqMod #-}
phaseFreqMod :: (Flat.C flat t, RealField.C t, Dim.C u) =>
      Wave.T t y   {- ^ waveform -}
   -> Proc.T s u t (
        RP.T s flat t
                     {- v phase control -}
     -> SigA.R s (Dim.Recip u) t t
                     {- v frequency control -}
     -> SigS.R s y)
phaseFreqMod wave =
   fmap flip $
      freqModAux
         (\ freqs phases ->
              SigS.fromSamples $ Osci.phaseFreqMod wave (Flat.toSamples phases) freqs)

{- | oscillator with both shape and frequency modulation -}
{-# INLINE shapeFreqMod #-}
shapeFreqMod :: (Flat.C flat c, RealField.C t, Dim.C u) =>
      (c -> Wave.T t y)
                   {- ^ waveform -}
   -> Phase.T t    {- ^ phase -}
   -> Proc.T s u t (
        RP.T s flat c
                     {- v shape control -}
     -> SigA.R s (Dim.Recip u) t t
                     {- v frequency control -}
     -> SigS.R s y)
shapeFreqMod wave phase =
   fmap flip $
      freqModAux
         (\ freqs parameters ->
              SigS.fromSamples $ Osci.shapeFreqMod wave phase (Flat.toSamples parameters) freqs)


{- |
oscillator with a sampled waveform with constant frequency
This is essentially an interpolation with cyclic padding.
-}
{-# INLINE staticSample #-}
staticSample :: (RealField.C t, Dim.C u) =>
      Interpolation.T t y
   -> SigC.R r y   {- ^ waveform -}
   -> Phase.T t    {- ^ start phase from the range [0,1] -}
   -> DN.T (Dim.Recip u) t
                   {- ^ frequency -}
   -> Proc.T s u t (SigS.R s y)
staticSample ip wave phase =
   staticAux (SigS.fromSamples . Osci.staticSample ip (SigC.toPeriod wave) phase)

{- |
oscillator with a sampled waveform with modulated frequency
Should behave homogenously for different types of interpolation.
-}
{-# INLINE freqModSample #-}
freqModSample :: (RealField.C t, Dim.C u) =>
      Interpolation.T t y
   -> SigC.R r y   {- ^ waveform -}
   -> Phase.T t    {- ^ start phase from the range [0,1] -}
   -> Proc.T s u t (
        SigA.R s (Dim.Recip u) t t
                   {- v frequency control -}
     -> SigS.R s y)
freqModSample ip wave phase =
   freqModAux (SigS.fromSamples . Osci.freqModSample ip (SigC.toPeriod wave) phase)


{-# INLINE freqModAux #-}
freqModAux :: (Field.C t, Dim.C u) =>
      (Sig.T t -> c)
   -> Proc.T s u t (
        SigA.R s (Dim.Recip u) t t
     -> c)
freqModAux f =
   do toFreq <- Proc.withParam toFrequencyScalar
      return $ f . SigA.scalarSamples toFreq

{-# INLINE staticAux #-}
staticAux :: (Dim.C u, Field.C t) =>
      (t -> c)
   -> DN.T (Dim.Recip u) t
   -> Proc.T s u t c
staticAux f freq =
   fmap f (toFrequencyScalar freq)