synthesizer-dimensional-0.2: src/Synthesizer/Dimensional/RateAmplitude/File.hs
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE Rank2Types #-}
module Synthesizer.Dimensional.RateAmplitude.File (
write,
writeTimeVoltage,
writeTimeVoltageMonoDoubleToInt16,
writeTimeVoltageStereoDoubleToInt16,
renderTimeVoltageMonoDoubleToInt16,
renderTimeVoltageStereoDoubleToInt16,
) where
import qualified Sound.Sox.Write as Write
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.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.ToInteger as ToInteger
-- 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
{- |
The output format is determined by SoX by the file name extension.
The sample precision is determined by the provided 'Builder.Builder' function.
Example:
> import qualified Data.StorableVector.Lazy.Builder as Builder
>
> write (DN.frequency one) (DN.voltage one) (\i -> Builder.put (i::Int16)) "test.aiff" sound
-}
{-# INLINE write #-}
write ::
(Bounded int, ToInteger.C int, Storable int, Frame.C int, BinSmp.C yv,
Dim.C u, RealField.C t,
Dim.C v, Module.C y yv, Field.C y) =>
DN.T (Dim.Recip u) t ->
DN.T v y ->
(int -> Builder.Builder int) ->
FilePath ->
SigP.T u t (SigA.S v y) yv ->
-- SigP.T u t (SigA.D v y SigS.S) yv ->
IO ExitCode
write freqUnit amp put name sig =
let opts =
SoxOpt.numberOfChannels (BinSmp.numberOfSignalChannels sig)
sampleRate =
DN.divToScalar (SigP.sampleRate sig) freqUnit
in Write.extended SigSt.hPut opts SoxOpt.none name
(round sampleRate)
(Builder.toLazyStorableVector SigSt.defaultChunkSize $
Sig.monoidConcatMap (BinSmp.outputFromCanonical put) $
SigA.vectorSamples (flip DN.divToScalar amp) sig)
{-# INLINE writeTimeVoltage #-}
writeTimeVoltage ::
(Bounded int, ToInteger.C int, Storable int, Frame.C int, BinSmp.C yv,
RealField.C t,
Module.C y yv, Field.C y) =>
(int -> Builder.Builder int) ->
FilePath ->
SigP.T Dim.Time t (SigA.S Dim.Voltage y) yv ->
-- SigP.T Dim.Time t (SigA.D Dim.Voltage y SigS.S) yv ->
IO ExitCode
writeTimeVoltage =
write (DN.frequency one) (DN.voltage one)
{-# INLINE writeTimeVoltageMonoDoubleToInt16 #-}
writeTimeVoltageMonoDoubleToInt16 ::
FilePath ->
SigP.T Dim.Time Double (SigA.S Dim.Voltage Double) Double ->
-- SigP.T Dim.Time t (SigA.D Dim.Voltage y SigS.S) yv ->
IO ExitCode
writeTimeVoltageMonoDoubleToInt16 name sig =
let rate = DN.toNumberWithDimension Dim.frequency (SigP.sampleRate sig)
in Write.simple SigSt.hPut SoxOpt.none name (round rate)
(SigP.signal (SigRA.toStorableInt16Mono sig))
{-# INLINE writeTimeVoltageStereoDoubleToInt16 #-}
writeTimeVoltageStereoDoubleToInt16 ::
FilePath ->
SigP.T Dim.Time Double (SigA.S Dim.Voltage Double) (Stereo.T Double) ->
-- SigP.T Dim.Time t (SigA.D Dim.Voltage y SigS.S) yv ->
IO ExitCode
writeTimeVoltageStereoDoubleToInt16 name sig =
let rate = DN.toNumberWithDimension Dim.frequency (SigP.sampleRate sig)
in Write.simple SigSt.hPut SoxOpt.none name (round rate)
(SigP.signal (SigRA.toStorableInt16Stereo sig))
{-# INLINE renderTimeVoltageMonoDoubleToInt16 #-}
renderTimeVoltageMonoDoubleToInt16 ::
DN.T Dim.Frequency Double ->
FilePath ->
(forall s. Proc.T s Dim.Time Double (SigA.R s Dim.Voltage Double Double)) ->
IO ExitCode
renderTimeVoltageMonoDoubleToInt16 rate name sig =
writeTimeVoltageMonoDoubleToInt16 name (SigP.runProcess rate sig)
{-# INLINE renderTimeVoltageStereoDoubleToInt16 #-}
renderTimeVoltageStereoDoubleToInt16 ::
DN.T Dim.Frequency Double ->
FilePath ->
(forall s. Proc.T s Dim.Time Double (SigA.R s Dim.Voltage Double (Stereo.T Double))) ->
IO ExitCode
renderTimeVoltageStereoDoubleToInt16 rate name sig =
writeTimeVoltageStereoDoubleToInt16 name (SigP.runProcess rate sig)