{-# OPTIONS -fno-implicit-prelude -fglasgow-exts #-}
-- glasgow-exts for all quantifier
module Synthesizer.Dimensional.RateAmplitude.Play (
   timeVoltageMonoDouble,
   timeVoltageStereoDouble,
   timeVoltageMonoDoubleR,
   timeVoltageStereoDoubleR,
  ) where

import qualified Sox
-- import qualified Sox.File
import qualified Sox.Play
-- import qualified BinarySample as BinSmp

import qualified Synthesizer.Dimensional.Process as Proc

import qualified Synthesizer.Dimensional.Amplitude.Signal as SigA
import qualified Synthesizer.Dimensional.RateAmplitude.Signal as SigRA
import qualified Synthesizer.Dimensional.RateWrapper as SigP

import qualified Synthesizer.Storable.Signal as SigSt

-- import qualified Synthesizer.Dimensional.Straight.Signal as SigS
-- import qualified Synthesizer.State.Signal as Sig

-- import qualified Algebra.Transcendental as Trans
-- import qualified Algebra.Module         as Module
import qualified Algebra.RealField      as RealField
-- import qualified Algebra.Field          as Field
-- import qualified Algebra.Ring           as Ring

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

import qualified Synthesizer.Frame.Stereo as Stereo

-- import System.Exit(ExitCode)
import Control.Exception(bracket)
import Foreign.Storable (Storable)

import qualified System.IO as IO
import qualified System.Process as Proc

import NumericPrelude
import PreludeBase


raw :: (RealField.C a, Storable y) =>
   [String] -> a -> Int -> SigSt.T y -> IO ()
raw args sampleRate numChannels stream =
   bracket
      (Proc.runInteractiveProcess "play"
          (args ++
           Sox.sampleRateOption sampleRate ++
           Sox.channelOption numChannels ++
           ["-t","sw","-"])
          Nothing Nothing)
      (\(input,output,err,proc) -> do
          mapM IO.hClose [input, output, err]
          -- wait for end of replay
          Proc.waitForProcess proc)
      (\(input,_,_,_) ->
         Sox.Play.catchCtrlC >>
         SigSt.hPut input stream)


{-# INLINE timeVoltageMonoDouble #-}
timeVoltageMonoDouble ::
   SigP.T Dim.Time Double (SigA.S Dim.Voltage Double) Double ->
   IO ()
timeVoltageMonoDouble sig =
   let rate = DN.toNumberWithDimension Dim.frequency (SigP.sampleRate sig)
   in  raw [] rate 1
          (SigP.signal (SigRA.toStorableInt16Mono sig))


{-# INLINE timeVoltageStereoDouble #-}
timeVoltageStereoDouble ::
   SigP.T Dim.Time Double (SigA.S Dim.Voltage Double) (Stereo.T Double) ->
--   SigP.T Dim.Time t (SigA.T Dim.Voltage y (SigS.T Sig.T)) yv ->
   IO ()
timeVoltageStereoDouble sig =
   let rate = DN.toNumberWithDimension Dim.frequency (SigP.sampleRate sig)
   in  raw [] rate 2
          (SigP.signal (SigRA.toStorableInt16Stereo sig))

{-# INLINE timeVoltageMonoDoubleR #-}
timeVoltageMonoDoubleR ::
   DN.T Dim.Frequency Double ->
   (forall s. Proc.T s Dim.Time Double (SigA.R s Dim.Voltage Double Double)) ->
   IO ()
timeVoltageMonoDoubleR rate sig =
   timeVoltageMonoDouble (SigP.runProcess rate sig)

{-# INLINE timeVoltageStereoDoubleR #-}
timeVoltageStereoDoubleR ::
   DN.T Dim.Frequency Double ->
   (forall s. Proc.T s Dim.Time Double (SigA.R s Dim.Voltage Double (Stereo.T Double))) ->
   IO ()
timeVoltageStereoDoubleR rate sig =
   timeVoltageStereoDouble (SigP.runProcess rate sig)