{-# OPTIONS -fno-implicit-prelude -fglasgow-exts #-}
-- glasgow-exts for all quantifier
module Synthesizer.Dimensional.RateAmplitude.File (
   write,
   writeTimeVoltage,
   writeTimeVoltageMonoDouble,
   writeTimeVoltageStereoDouble,
   renderTimeVoltageMonoDouble,
   renderTimeVoltageStereoDouble,
  ) where

import qualified Sox.File
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.Frame.Stereo as Stereo

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 System.Exit(ExitCode)

import NumericPrelude
import PreludeBase



{-# INLINE write #-}
write ::
    (RealField.C t, BinSmp.C yv,
     Dim.C u, Field.C t,
     Dim.C v, Module.C y yv, Field.C y) =>
   DN.T (Dim.Recip u) t ->
   DN.T v y ->
   FilePath ->
   SigP.T u t (SigA.S v y) yv ->
--   SigP.T u t (SigA.T v y (SigS.T Sig.T)) yv ->
   IO ExitCode
write freqUnit amp name sig =
   Sox.File.write name
      (DN.divToScalar (SigP.sampleRate sig) freqUnit)
      (Sig.toList (SigA.vectorSamples (flip DN.divToScalar amp) sig))


{-# INLINE writeTimeVoltage #-}
writeTimeVoltage ::
    (RealField.C t, BinSmp.C yv,
     Field.C t,
     Module.C y yv, Field.C y) =>
   FilePath ->
   SigP.T Dim.Time t (SigA.S Dim.Voltage y) yv ->
--   SigP.T Dim.Time t (SigA.T Dim.Voltage y (SigS.T Sig.T)) yv ->
   IO ExitCode
writeTimeVoltage =
   write (DN.frequency one) (DN.voltage one)



{-# INLINE writeTimeVoltageMonoDouble #-}
writeTimeVoltageMonoDouble ::
   FilePath ->
   SigP.T Dim.Time Double (SigA.S Dim.Voltage Double) Double ->
--   SigP.T Dim.Time t (SigA.T Dim.Voltage y (SigS.T Sig.T)) yv ->
   IO ()
writeTimeVoltageMonoDouble name sig =
   let rate = DN.toNumberWithDimension Dim.frequency (SigP.sampleRate sig)
   in  do SigSt.writeFile (name ++ ".sw")
             (SigP.signal (SigRA.toStorableInt16Mono sig))
          Sox.File.rawToAIFF name [] rate 1
          return ()


{-# INLINE writeTimeVoltageStereoDouble #-}
writeTimeVoltageStereoDouble ::
   FilePath ->
   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 ()
writeTimeVoltageStereoDouble name sig =
   let rate = DN.toNumberWithDimension Dim.frequency (SigP.sampleRate sig)
   in  do SigSt.writeFile (name ++ ".sw")
             (SigP.signal (SigRA.toStorableInt16Stereo sig))
          Sox.File.rawToAIFF name [] rate 2
          return ()

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

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