{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE Rank2Types #-}
module Synthesizer.Dimensional.RateAmplitude.Play (
   auto,
   timeVoltage,
   timeVoltageMonoDoubleToInt16,
   timeVoltageStereoDoubleToInt16,
   renderTimeVoltage,
   renderTimeVoltageMonoDoubleToInt16,
   renderTimeVoltageStereoDoubleToInt16,
  ) where

import qualified Sound.Sox.Play as Play
import qualified Sound.Sox.Option.Format as SoxOpt
import qualified Sound.Sox.Frame as Frame
import qualified Synthesizer.Basic.Binary as BinSmp
import qualified Data.StorableVector.Lazy.Builder as Builder
import Foreign.Storable (Storable, )

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 Synthesizer.State.Signal as Sig

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.RealField      as RealField
import qualified Algebra.Field          as Field

import System.Exit(ExitCode)

import NumericPrelude.Numeric
import NumericPrelude.Base


type Signal u t v y yv =
   SigA.T (Rate.Dimensional u t) (Amp.Dimensional v y) (Sig.T yv)


{-# INLINE auto #-}
auto ::
    (Bounded int, ToInteger.C int, Storable int, Frame.C int,
     Dim.C u, RealField.C t,
     Dim.C v, BinSmp.C yv, Module.C y yv, Field.C y) =>
   DN.T (Dim.Recip u) t ->
   DN.T v y ->
   (int -> Builder.Builder int) ->
   Signal u t v y yv ->
   IO ExitCode
auto :: forall int u t v yv y.
(Bounded int, C int, Storable int, C int, C u, C t, C v, C yv,
 C y yv, C y) =>
T (Recip u) t
-> T v y
-> (int -> Builder int)
-> Signal u t v y yv
-> IO ExitCode
auto T (Recip u) t
freqUnit T v y
amp int -> Builder int
put Signal u t v y yv
sig =
   let opts :: T
opts =
          Int -> T
SoxOpt.numberOfChannels forall a b. (a -> b) -> a -> b
$
          forall yv (sig :: * -> *). C yv => sig yv -> Int
BinSmp.numberOfSignalChannels forall a b. (a -> b) -> a -> b
$
          forall rate amplitude body. T rate amplitude body -> body
SigA.body Signal u t v y yv
sig
       sampleRate :: t
sampleRate =
          forall u a. (C u, C a) => T u a -> T u a -> a
DN.divToScalar (forall rate amp sig. T (Actual rate) amp sig -> rate
SigA.actualSampleRate Signal u t v y yv
sig) T (Recip u) t
freqUnit
   in  forall y (sig :: * -> *).
C y =>
(Handle -> sig y -> IO ()) -> T -> T -> Int -> sig y -> IO ExitCode
Play.extended forall a. Storable a => Handle -> Vector a -> IO ()
SigSt.hPut T
opts T
SoxOpt.none
          (forall a b. (C a, C b) => a -> b
round t
sampleRate)
          (forall a. Storable a => ChunkSize -> Builder a -> Vector a
Builder.toLazyStorableVector ChunkSize
SigA.defaultChunkSize forall a b. (a -> b) -> a -> b
$
           forall m a. Monoid m => (a -> m) -> T a -> m
Sig.foldMap (forall a int out.
(C a, Bounded int, C int, Monoid out) =>
(int -> out) -> a -> out
BinSmp.outputFromCanonical int -> Builder int
put) forall a b. (a -> b) -> a -> b
$
           forall y yv (sig :: * -> *) amp rate.
(C y yv, Transform sig yv) =>
(amp -> y) -> T rate (Numeric amp) (sig yv) -> sig yv
SigA.vectorSamples (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall u a. (C u, C a) => T u a -> T u a -> a
DN.divToScalar T v y
amp) Signal u t v y yv
sig)


{-# INLINE timeVoltage #-}
timeVoltage ::
    (Bounded int, ToInteger.C int, Storable int, Frame.C int,
     RealField.C t,
     BinSmp.C yv, Module.C y yv, Field.C y) =>
   (int -> Builder.Builder int) ->
   Signal Dim.Time t Dim.Voltage y yv ->
   IO ExitCode
timeVoltage :: forall int t yv y.
(Bounded int, C int, Storable int, C int, C t, C yv, C y yv,
 C y) =>
(int -> Builder int) -> Signal Time t Voltage y yv -> IO ExitCode
timeVoltage =
   forall int u t v yv y.
(Bounded int, C int, Storable int, C int, C u, C t, C v, C yv,
 C y yv, C y) =>
T (Recip u) t
-> T v y
-> (int -> Builder int)
-> Signal u t v y yv
-> IO ExitCode
auto (forall a. a -> Frequency a
DN.frequency forall a. C a => a
one) (forall a. a -> Voltage a
DN.voltage forall a. C a => a
one)


{-# INLINE timeVoltageMonoDoubleToInt16 #-}
timeVoltageMonoDoubleToInt16 ::
   Signal Dim.Time Double Dim.Voltage Double Double ->
   IO ExitCode
timeVoltageMonoDoubleToInt16 :: Signal Time Double Voltage Double Double -> IO ExitCode
timeVoltageMonoDoubleToInt16 Signal Time Double Voltage Double Double
sig =
   let rate :: Double
rate = forall u a. C u => u -> T u a -> a
DN.toNumberWithDimension Frequency
Dim.frequency (forall rate amp sig. T (Actual rate) amp sig -> rate
SigA.actualSampleRate Signal Time Double Voltage Double Double
sig)
   in  forall y (sig :: * -> *).
C y =>
(Handle -> sig y -> IO ()) -> T -> Int -> sig y -> IO ExitCode
Play.simple forall a. Storable a => Handle -> Vector a -> IO ()
SigSt.hPut T
SoxOpt.none (forall a b. (C a, C b) => a -> b
round Double
rate)
          (forall a rate.
C a =>
T rate (Dimensional Voltage a) (T a) -> T Int16
SigA.toStorableInt16Mono Signal Time Double Voltage Double Double
sig)


{-# INLINE timeVoltageStereoDoubleToInt16 #-}
timeVoltageStereoDoubleToInt16 ::
   Signal Dim.Time Double Dim.Voltage Double (Stereo.T Double) ->
   IO ExitCode
timeVoltageStereoDoubleToInt16 :: Signal Time Double Voltage Double (T Double) -> IO ExitCode
timeVoltageStereoDoubleToInt16 Signal Time Double Voltage Double (T Double)
sig =
   let rate :: Double
rate = forall u a. C u => u -> T u a -> a
DN.toNumberWithDimension Frequency
Dim.frequency (forall rate amp sig. T (Actual rate) amp sig -> rate
SigA.actualSampleRate Signal Time Double Voltage Double (T Double)
sig)
   in  forall y (sig :: * -> *).
C y =>
(Handle -> sig y -> IO ()) -> T -> Int -> sig y -> IO ExitCode
Play.simple forall a. Storable a => Handle -> Vector a -> IO ()
SigSt.hPut T
SoxOpt.none (forall a b. (C a, C b) => a -> b
round Double
rate)
          (forall a rate.
(C a a, C a) =>
T rate (Dimensional Voltage a) (T (T a)) -> T (T Int16)
SigA.toStorableInt16Stereo Signal Time Double Voltage Double (T Double)
sig)


{-# INLINE renderTimeVoltage #-}
renderTimeVoltage ::
    (Bounded int, ToInteger.C int, Storable int, Frame.C int,
     RealField.C t,
     BinSmp.C yv, Module.C y yv, Field.C y) =>
   (int -> Builder.Builder int) ->
   DN.T Dim.Frequency t ->
   (forall s. Proc.T s Dim.Time t (SigA.R s Dim.Voltage y yv)) ->
   IO ExitCode
renderTimeVoltage :: forall int t yv y.
(Bounded int, C int, Storable int, C int, C t, C yv, C y yv,
 C y) =>
(int -> Builder int)
-> T Frequency t
-> (forall s. T s Time t (R s Voltage y yv))
-> IO ExitCode
renderTimeVoltage int -> Builder int
put T Frequency t
rate forall s. T s Time t (R s Voltage y yv)
sig =
   forall int t yv y.
(Bounded int, C int, Storable int, C int, C t, C yv, C y yv,
 C y) =>
(int -> Builder int) -> Signal Time t Voltage y yv -> IO ExitCode
timeVoltage int -> Builder int
put (forall u t amp sig.
C u =>
T (Recip u) t
-> (forall s. T s u t (T (Phantom s) amp sig))
-> T (Dimensional u t) amp sig
SigA.render T Frequency t
rate forall s. T s Time t (R s Voltage y yv)
sig)

{-# INLINE renderTimeVoltageMonoDoubleToInt16 #-}
renderTimeVoltageMonoDoubleToInt16 ::
   DN.T Dim.Frequency Double ->
   (forall s. Proc.T s Dim.Time Double (SigA.R s Dim.Voltage Double Double)) ->
   IO ExitCode
renderTimeVoltageMonoDoubleToInt16 :: T Frequency Double
-> (forall s. T s Time Double (R s Voltage Double Double))
-> IO ExitCode
renderTimeVoltageMonoDoubleToInt16 T Frequency Double
rate forall s. T s Time Double (R s Voltage Double Double)
sig =
   Signal Time Double Voltage Double Double -> IO ExitCode
timeVoltageMonoDoubleToInt16 (forall u t amp sig.
C u =>
T (Recip u) t
-> (forall s. T s u t (T (Phantom s) amp sig))
-> T (Dimensional u t) amp sig
SigA.render T Frequency Double
rate forall s. T s Time Double (R s Voltage Double Double)
sig)

{-# INLINE renderTimeVoltageStereoDoubleToInt16 #-}
renderTimeVoltageStereoDoubleToInt16 ::
   DN.T Dim.Frequency Double ->
   (forall s. Proc.T s Dim.Time Double (SigA.R s Dim.Voltage Double (Stereo.T Double))) ->
   IO ExitCode
renderTimeVoltageStereoDoubleToInt16 :: T Frequency Double
-> (forall s. T s Time Double (R s Voltage Double (T Double)))
-> IO ExitCode
renderTimeVoltageStereoDoubleToInt16 T Frequency Double
rate forall s. T s Time Double (R s Voltage Double (T Double))
sig =
   Signal Time Double Voltage Double (T Double) -> IO ExitCode
timeVoltageStereoDoubleToInt16 (forall u t amp sig.
C u =>
T (Recip u) t
-> (forall s. T s u t (T (Phantom s) amp sig))
-> T (Dimensional u t) amp sig
SigA.render T Frequency Double
rate forall s. T s Time Double (R s Voltage Double (T Double))
sig)