{-# LANGUAGE NoImplicitPrelude #-}
{- |
Copyright   :  (c) Henning Thielemann 2006
License     :  GPL

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

Tone generators
-}
module Synthesizer.Storable.Oscillator where

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

import qualified Synthesizer.Storable.Signal as Signal
import Synthesizer.Storable.Signal (ChunkSize)
import Foreign.Storable (Storable)

import qualified Algebra.Transcendental        as Trans
import qualified Algebra.RealRing              as RealRing

import NumericPrelude.Numeric
import NumericPrelude.Base



{- * Oscillators with arbitrary but constant waveforms -}

{-# INLINE freqToPhase #-}
{- | Convert a list of phase steps into a list of momentum phases
     phase is a number in the interval [0,1)
     freq contains the phase steps -}
freqToPhase :: (RealRing.C a, Storable a) =>
   Phase.T a -> Signal.T a -> Signal.T (Phase.T a)
freqToPhase :: forall a. (C a, Storable a) => T a -> T a -> T (T a)
freqToPhase T a
phase T a
freq = (T a -> a -> T a) -> T a -> T a -> T (T a)
forall a b.
(Storable a, Storable b) =>
(a -> b -> a) -> a -> T b -> T a
Signal.scanL ((a -> T a -> T a) -> T a -> a -> T a
forall a b c. (a -> b -> c) -> b -> a -> c
flip a -> T a -> T a
forall a. C a => a -> T a -> T a
Phase.increment) T a
phase T a
freq


{-# INLINE static #-}
{- disabled SPECIALISE static :: Storable b => ChunkSize -> (Double -> b) -> (Double -> Double -> Signal.T b) -}
{- | oscillator with constant frequency -}
static :: (RealRing.C a, Storable a, Storable b) =>
    ChunkSize -> Wave.T a b -> (Phase.T a -> a -> Signal.T b)
static :: forall a b.
(C a, Storable a, Storable b) =>
ChunkSize -> T a b -> T a -> a -> T b
static ChunkSize
size T a b
wave T a
phase a
freq =
    (T a -> b) -> Vector (T a) -> Vector b
forall x y.
(Storable x, Storable y) =>
(x -> y) -> Vector x -> Vector y
Signal.map (T a b -> T a -> b
forall t y. T t y -> T t -> y
Wave.apply T a b
wave) (ChunkSize -> (T a -> T a) -> T a -> Vector (T a)
forall a. Storable a => ChunkSize -> (a -> a) -> a -> Vector a
Signal.iterate ChunkSize
size (a -> T a -> T a
forall a. C a => a -> T a -> T a
Phase.increment a
freq) T a
phase)

{- | oscillator with modulated phase -}
phaseMod :: (RealRing.C a, Storable a, Storable b) =>
    ChunkSize -> Wave.T a b -> a -> Signal.T a -> Signal.T b
phaseMod :: forall a b.
(C a, Storable a, Storable b) =>
ChunkSize -> T a b -> a -> T a -> T b
phaseMod ChunkSize
size T a b
wave = ChunkSize -> (a -> T a b) -> T a -> a -> T a -> T b
forall a b c.
(C a, Storable a, Storable b, Storable c) =>
ChunkSize -> (c -> T a b) -> T a -> a -> T c -> T b
shapeMod ChunkSize
size (T a b -> a -> T a b
forall a b. C a => T a b -> a -> T a b
Wave.phaseOffset T a b
wave) T a
forall a. C a => a
zero

{- disabled INLINE shapeMod -}
{- | oscillator with modulated shape -}
shapeMod :: (RealRing.C a, Storable a, Storable b, Storable c) =>
    ChunkSize -> (c -> Wave.T a b) -> Phase.T a -> a -> Signal.T c -> Signal.T b
shapeMod :: forall a b c.
(C a, Storable a, Storable b, Storable c) =>
ChunkSize -> (c -> T a b) -> T a -> a -> T c -> T b
shapeMod ChunkSize
size c -> T a b
wave T a
phase a
freq T c
parameters =
    (c -> T a -> b) -> T c -> Vector (T a) -> Vector b
forall a b c.
(Storable a, Storable b, Storable c) =>
(a -> b -> c) -> Vector a -> Vector b -> Vector c
Signal.zipWith (T a b -> T a -> b
forall t y. T t y -> T t -> y
Wave.apply (T a b -> T a -> b) -> (c -> T a b) -> c -> T a -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. c -> T a b
wave) T c
parameters
       (ChunkSize -> (T a -> T a) -> T a -> Vector (T a)
forall a. Storable a => ChunkSize -> (a -> a) -> a -> Vector a
Signal.iterate ChunkSize
size (a -> T a -> T a
forall a. C a => a -> T a -> T a
Phase.increment a
freq) T a
phase)

{- | oscillator with modulated frequency -}
freqMod :: (RealRing.C a, Storable a, Storable b) =>
    ChunkSize -> Wave.T a b -> Phase.T a -> Signal.T a -> Signal.T b
freqMod :: forall a b.
(C a, Storable a, Storable b) =>
ChunkSize -> T a b -> T a -> T a -> T b
freqMod ChunkSize
_size T a b
wave T a
phase T a
freqs =
    (T a -> b) -> Vector (T a) -> Vector b
forall x y.
(Storable x, Storable y) =>
(x -> y) -> Vector x -> Vector y
Signal.map (T a b -> T a -> b
forall t y. T t y -> T t -> y
Wave.apply T a b
wave) (T a -> T a -> Vector (T a)
forall a. (C a, Storable a) => T a -> T a -> T (T a)
freqToPhase T a
phase T a
freqs)

{- | oscillator with both phase and frequency modulation -}
phaseFreqMod :: (RealRing.C a, Storable a, Storable b) =>
    ChunkSize -> Wave.T a b -> Signal.T a -> Signal.T a -> Signal.T b
phaseFreqMod :: forall a b.
(C a, Storable a, Storable b) =>
ChunkSize -> T a b -> T a -> T a -> T b
phaseFreqMod ChunkSize
size T a b
wave =
    ChunkSize -> (a -> T a b) -> T a -> T a -> T a -> T b
forall a b c.
(C a, Storable a, Storable b, Storable c) =>
ChunkSize -> (c -> T a b) -> T a -> T c -> T a -> T b
shapeFreqMod ChunkSize
size (T a b -> a -> T a b
forall a b. C a => T a b -> a -> T a b
Wave.phaseOffset T a b
wave) T a
forall a. C a => a
zero

{- | oscillator with both shape and frequency modulation -}
shapeFreqMod :: (RealRing.C a, Storable a, Storable b, Storable c) =>
    ChunkSize -> (c -> Wave.T a b) ->
    Phase.T a -> Signal.T c -> Signal.T a -> Signal.T b
shapeFreqMod :: forall a b c.
(C a, Storable a, Storable b, Storable c) =>
ChunkSize -> (c -> T a b) -> T a -> T c -> T a -> T b
shapeFreqMod ChunkSize
_size c -> T a b
wave T a
phase T c
parameters T a
freqs =
    (c -> T a -> b) -> T c -> Vector (T a) -> Vector b
forall a b c.
(Storable a, Storable b, Storable c) =>
(a -> b -> c) -> Vector a -> Vector b -> Vector c
Signal.zipWith (T a b -> T a -> b
forall t y. T t y -> T t -> y
Wave.apply (T a b -> T a -> b) -> (c -> T a b) -> c -> T a -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. c -> T a b
wave) T c
parameters (T a -> T a -> Vector (T a)
forall a. (C a, Storable a) => T a -> T a -> T (T a)
freqToPhase T a
phase T a
freqs)


{-
{- | oscillator with a sampled waveform with constant frequency
     This essentially an interpolation with cyclic padding. -}
staticSample :: RealRing.C a => Interpolation.T a b -> Signal.T b -> a -> a -> Signal.T b
staticSample ip wave phase freq =
    freqModSample ip wave phase (repeat freq)

{- | oscillator with a sampled waveform with modulated frequency
     Should behave homogenously for different types of interpolation. -}
freqModSample :: RealRing.C a => Interpolation.T a b -> Signal.T b -> a -> Signal.T a -> Signal.T b
freqModSample ip wave phase freqs =
    let len = fromIntegral (length wave)
    in  Interpolation.multiRelativeCyclicPad
           ip (phase*len) (Signal.map (*len) freqs) wave
-}



{- * Oscillators with specific waveforms -}

{-# INLINE staticSine #-}
{- disabled SPECIALISE staticSine :: ChunkSize -> Double -> Double -> Signal.T Double -}
{- | sine oscillator with static frequency -}
staticSine :: (Trans.C a, RealRing.C a, Storable a) =>
   ChunkSize -> Phase.T a -> a -> Signal.T a
staticSine :: forall a. (C a, C a, Storable a) => ChunkSize -> T a -> a -> T a
staticSine ChunkSize
size = ChunkSize -> T a a -> T a -> a -> T a
forall a b.
(C a, Storable a, Storable b) =>
ChunkSize -> T a b -> T a -> a -> T b
static ChunkSize
size T a a
forall a. C a => T a a
Wave.sine

{-# INLINE freqModSine #-}
{- disabled SPECIALISE freqModSine :: ChunkSize -> Double -> Signal.T Double -> Signal.T Double -}
{- | sine oscillator with modulated frequency -}
freqModSine :: (Trans.C a, RealRing.C a, Storable a) =>
   ChunkSize -> Phase.T a -> Signal.T a -> Signal.T a
freqModSine :: forall a. (C a, C a, Storable a) => ChunkSize -> T a -> T a -> T a
freqModSine ChunkSize
size = ChunkSize -> T a a -> T a -> T a -> T a
forall a b.
(C a, Storable a, Storable b) =>
ChunkSize -> T a b -> T a -> T a -> T b
freqMod ChunkSize
size T a a
forall a. C a => T a a
Wave.sine

{-# INLINE phaseModSine #-}
{- disabled SPECIALISE phaseModSine :: ChunkSize -> Double -> Signal.T Double -> Signal.T Double -}
{- | sine oscillator with modulated phase, useful for FM synthesis -}
phaseModSine :: (Trans.C a, RealRing.C a, Storable a) =>
   ChunkSize -> a -> Signal.T a -> Signal.T a
phaseModSine :: forall a. (C a, C a, Storable a) => ChunkSize -> a -> T a -> T a
phaseModSine ChunkSize
size = ChunkSize -> T a a -> a -> T a -> T a
forall a b.
(C a, Storable a, Storable b) =>
ChunkSize -> T a b -> a -> T a -> T b
phaseMod ChunkSize
size T a a
forall a. C a => T a a
Wave.sine

{-# INLINE staticSaw #-}
{- disabled SPECIALISE staticSaw :: ChunkSize -> Double -> Double -> Signal.T Double -}
{- | saw tooth oscillator with modulated frequency -}
staticSaw :: (RealRing.C a, Storable a) =>
   ChunkSize -> Phase.T a -> a -> Signal.T a
staticSaw :: forall a. (C a, Storable a) => ChunkSize -> T a -> a -> T a
staticSaw ChunkSize
size = ChunkSize -> T a a -> T a -> a -> T a
forall a b.
(C a, Storable a, Storable b) =>
ChunkSize -> T a b -> T a -> a -> T b
static ChunkSize
size T a a
forall a. C a => T a a
Wave.saw

{-# INLINE freqModSaw #-}
{- disabled SPECIALISE freqModSaw :: ChunkSize -> Double -> Signal.T Double -> Signal.T Double -}
{- | saw tooth oscillator with modulated frequency -}
freqModSaw :: (RealRing.C a, Storable a) =>
   ChunkSize -> Phase.T a -> Signal.T a -> Signal.T a
freqModSaw :: forall a. (C a, Storable a) => ChunkSize -> T a -> T a -> T a
freqModSaw ChunkSize
size = ChunkSize -> T a a -> T a -> T a -> T a
forall a b.
(C a, Storable a, Storable b) =>
ChunkSize -> T a b -> T a -> T a -> T b
freqMod ChunkSize
size T a a
forall a. C a => T a a
Wave.saw


{- Test whether Fusion takes place.
For the following code the simplifier can't resist!

testLength :: (Storable a, Enum a) => a -> Int
testLength x =
   Signal.length (Signal.map succ (Signal.fromList (Signal.ChunkSize 100) [x,x,x]))
-}