{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE Rank2Types #-}
module Synthesizer.Dimensional.ALSA.Play where

import qualified Synthesizer.Storable.ALSA.Play as Play

import qualified Synthesizer.Dimensional.Rate as Rate
import qualified Synthesizer.Dimensional.Amplitude as Amp

import qualified Synthesizer.Dimensional.Process as Proc
import qualified Synthesizer.Dimensional.Signal.Private as SigA

import qualified Synthesizer.Frame.Stereo as Stereo

import qualified Synthesizer.Storable.Signal as SigSt

import qualified Sound.ALSA.PCM as ALSA

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

-- import qualified Algebra.ToInteger      as ToInteger
import qualified Algebra.Module         as Module
import qualified Algebra.RealRing      as RealRing
-- import qualified Algebra.Field          as Field
-- import qualified Algebra.Ring           as Ring

import Foreign.Storable (Storable, )

-- import NumericPrelude.Numeric
import NumericPrelude.Base


type RenderedStorableSignal u t v y yv =
   SigA.T (Rate.Dimensional u t) (Amp.Dimensional v y) (SigSt.T yv)

type StorableSignal s v y yv =
   SigA.T (Rate.Phantom s) (Amp.Dimensional v y) (SigSt.T yv)


{-# INLINE timeVoltageStorable #-}
timeVoltageStorable ::
   (Module.C y yv, ALSA.SampleFmt yv, RealRing.C t) =>
   DN.Time t->
   RenderedStorableSignal Dim.Time t Dim.Voltage y yv ->
   IO ()
timeVoltageStorable period sig =
   let rate = DN.toNumberWithDimension Dim.frequency (SigA.actualSampleRate sig)
       per  = DN.toNumberWithDimension Dim.time period
   in  Play.auto per (RealRing.round rate)
          (SigA.vectorSamples (DN.toNumberWithDimension Dim.voltage) sig)

{-# INLINE timeVoltageMonoStorableToInt16 #-}
timeVoltageMonoStorableToInt16 ::
   (Storable y, RealRing.C y, RealRing.C t) =>
   DN.Time t->
   RenderedStorableSignal Dim.Time t Dim.Voltage y y ->
   IO ()
timeVoltageMonoStorableToInt16 period sig =
   let rate = DN.toNumberWithDimension Dim.frequency (SigA.actualSampleRate sig)
       per  = DN.toNumberWithDimension Dim.time period
   in  Play.monoToInt16 per (RealRing.round rate)
          (SigA.scalarSamples (DN.toNumberWithDimension Dim.voltage) sig)

{-# INLINE timeVoltageStereoStorableToInt16 #-}
timeVoltageStereoStorableToInt16 ::
   (Storable y, Module.C y y, RealRing.C y, RealRing.C t) =>
   DN.Time t->
   RenderedStorableSignal Dim.Time t Dim.Voltage y (Stereo.T y) ->
   IO ()
timeVoltageStereoStorableToInt16 period sig =
   let rate = DN.toNumberWithDimension Dim.frequency (SigA.actualSampleRate sig)
       per  = DN.toNumberWithDimension Dim.time period
   in  Play.stereoToInt16 per (RealRing.round rate)
          (SigA.vectorSamples (DN.toNumberWithDimension Dim.voltage) sig)


{-# INLINE renderTimeVoltageStorable #-}
renderTimeVoltageStorable ::
   (Module.C y yv, ALSA.SampleFmt yv, RealRing.C t) =>
   DN.Time t->
   DN.T Dim.Frequency t ->
   (forall s. Proc.T s Dim.Time t
      (StorableSignal s Dim.Voltage y yv)) ->
   IO ()
renderTimeVoltageStorable period rate sig =
   timeVoltageStorable period (SigA.render rate sig)

{-# INLINE renderTimeVoltageMonoStorableToInt16 #-}
renderTimeVoltageMonoStorableToInt16 ::
   (Storable y, RealRing.C y, RealRing.C t) =>
   DN.Time t->
   DN.T Dim.Frequency t ->
   (forall s. Proc.T s Dim.Time t
      (StorableSignal s Dim.Voltage y y)) ->
   IO ()
renderTimeVoltageMonoStorableToInt16 period rate sig =
   timeVoltageMonoStorableToInt16 period (SigA.render rate sig)

{-# INLINE renderTimeVoltageStereoStorableToInt16 #-}
renderTimeVoltageStereoStorableToInt16 ::
   (Storable y, Module.C y y, RealRing.C y, RealRing.C t) =>
   DN.Time t->
   DN.T Dim.Frequency t ->
   (forall s. Proc.T s Dim.Time t
      (StorableSignal s Dim.Voltage y (Stereo.T y))) ->
   IO ()
renderTimeVoltageStereoStorableToInt16 period rate sig =
   timeVoltageStereoStorableToInt16 period (SigA.render rate sig)