{-# LANGUAGE NoImplicitPrelude #-}
module Synthesizer.Plain.Play where

import qualified Synthesizer.Plain.Builder as Builder
import qualified Synthesizer.Basic.Binary as BinSmp

import qualified Sound.Sox.Frame as Frame
import qualified Sound.Sox.Frame.Stereo as Stereo
import qualified Sound.Sox.Option.Format as SoxOpt
import qualified Sound.Sox.Play as Play
import qualified Sound.Sox.Signal.List as SoxList

import Foreign.Storable (Storable, )
import Data.Int (Int16, )
import Data.Monoid (mconcat, )

import System.Exit (ExitCode, )

import qualified Algebra.ToInteger as ToInteger
import qualified Algebra.RealRing as RealRing

import NumericPrelude.Numeric
import NumericPrelude.Base


{- |
See 'Synthesizer.Plain.File.write'.
-}
render ::
   (Storable int, Frame.C int, ToInteger.C int, Bounded int,
    RealRing.C a, BinSmp.C v) =>
   Builder.Put int -> a -> (a -> [v]) -> IO ExitCode
render :: forall int a v.
(Storable int, C int, C int, Bounded int, C a, C v) =>
Put int -> a -> (a -> [v]) -> IO ExitCode
render Put int
put a
sampleRate a -> [v]
renderer =
   Put int -> a -> [v] -> IO ExitCode
forall int a v.
(Storable int, C int, C int, Bounded int, C a, C v) =>
Put int -> a -> [v] -> IO ExitCode
auto Put int
put a
sampleRate (a -> [v]
renderer a
sampleRate)

renderToInt16 :: (RealRing.C a, BinSmp.C v) => a -> (a -> [v]) -> IO ExitCode
renderToInt16 :: forall a v. (C a, C v) => a -> (a -> [v]) -> IO ExitCode
renderToInt16 a
sampleRate a -> [v]
renderer =
   a -> [v] -> IO ExitCode
forall a v. (C a, C v) => a -> [v] -> IO ExitCode
toInt16 a
sampleRate (a -> [v]
renderer a
sampleRate)

renderMonoToInt16 :: (RealRing.C a) => a -> (a -> [a]) -> IO ExitCode
renderMonoToInt16 :: forall a. C a => a -> (a -> [a]) -> IO ExitCode
renderMonoToInt16 a
sampleRate a -> [a]
renderer =
   a -> [a] -> IO ExitCode
forall a. C a => a -> [a] -> IO ExitCode
monoToInt16 a
sampleRate (a -> [a]
renderer a
sampleRate)

renderStereoToInt16 :: (RealRing.C a) => a -> (a -> [(a,a)]) -> IO ExitCode
renderStereoToInt16 :: forall a. C a => a -> (a -> [(a, a)]) -> IO ExitCode
renderStereoToInt16 a
sampleRate a -> [(a, a)]
renderer =
   a -> [(a, a)] -> IO ExitCode
forall a. C a => a -> [(a, a)] -> IO ExitCode
stereoToInt16 a
sampleRate (a -> [(a, a)]
renderer a
sampleRate)


{- |
See 'Synthesizer.Plain.File.write'.
-}
auto ::
   (Storable int, Frame.C int, ToInteger.C int, Bounded int,
    RealRing.C a, BinSmp.C v) =>
   Builder.Put int -> a -> [v] -> IO ExitCode
auto :: forall int a v.
(Storable int, C int, C int, Bounded int, C a, C v) =>
Put int -> a -> [v] -> IO ExitCode
auto Put int
put a
sampleRate [v]
signal =
   T -> a -> [int] -> IO ExitCode
forall a v. (C a, C v, Storable v) => T -> a -> [v] -> IO ExitCode
raw
      (Int -> T
SoxOpt.numberOfChannels ([v] -> Int
forall yv (sig :: * -> *). C yv => sig yv -> Int
BinSmp.numberOfSignalChannels [v]
signal))
      a
sampleRate
      (T int -> [int]
forall a. T a -> [a]
Builder.run (T int -> [int]) -> ([v] -> T int) -> [v] -> [int]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [T int] -> T int
forall a. Monoid a => [a] -> a
mconcat ([T int] -> T int) -> ([v] -> [T int]) -> [v] -> T int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (v -> T int) -> [v] -> [T int]
forall a b. (a -> b) -> [a] -> [b]
map (Put int -> v -> T int
forall a int out.
(C a, Bounded int, C int, Monoid out) =>
(int -> out) -> a -> out
forall int out.
(Bounded int, C int, Monoid out) =>
(int -> out) -> v -> out
BinSmp.outputFromCanonical Put int
put) ([v] -> [int]) -> [v] -> [int]
forall a b. (a -> b) -> a -> b
$
       [v]
signal)

toInt16 :: (RealRing.C a, BinSmp.C v) => a -> [v] -> IO ExitCode
toInt16 :: forall a v. (C a, C v) => a -> [v] -> IO ExitCode
toInt16 =
   Put Int16 -> a -> [v] -> IO ExitCode
forall int a v.
(Storable int, C int, C int, Bounded int, C a, C v) =>
Put int -> a -> [v] -> IO ExitCode
auto (Put Int16
forall a. Put a
Builder.put :: Builder.Put Int16)

monoToInt16 :: (RealRing.C a) => a -> [a] -> IO ExitCode
monoToInt16 :: forall a. C a => a -> [a] -> IO ExitCode
monoToInt16 a
sampleRate [a]
signal =
   T -> a -> [Int16] -> IO ExitCode
forall a v. (C a, C v, Storable v) => T -> a -> [v] -> IO ExitCode
raw T
SoxOpt.none a
sampleRate
      ((a -> Int16) -> [a] -> [Int16]
forall a b. (a -> b) -> [a] -> [b]
map a -> Int16
forall a. C a => a -> Int16
BinSmp.int16FromCanonical [a]
signal)

stereoToInt16 :: (RealRing.C a) => a -> [(a,a)] -> IO ExitCode
stereoToInt16 :: forall a. C a => a -> [(a, a)] -> IO ExitCode
stereoToInt16 a
sampleRate [(a, a)]
signal =
   T -> a -> [T Int16] -> IO ExitCode
forall a v. (C a, C v, Storable v) => T -> a -> [v] -> IO ExitCode
raw T
SoxOpt.none a
sampleRate
      (((a, a) -> T Int16) -> [(a, a)] -> [T Int16]
forall a b. (a -> b) -> [a] -> [b]
map ((a -> Int16) -> T a -> T Int16
forall a b. (a -> b) -> T a -> T b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> Int16
forall a. C a => a -> Int16
BinSmp.int16FromCanonical (T a -> T Int16) -> ((a, a) -> T a) -> (a, a) -> T Int16
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> a -> T a) -> (a, a) -> T a
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry a -> a -> T a
forall a. a -> a -> T a
Stereo.cons) [(a, a)]
signal)


raw :: (RealRing.C a, Frame.C v, Storable v) =>
   SoxOpt.T -> a -> [v] -> IO ExitCode
raw :: forall a v. (C a, C v, Storable v) => T -> a -> [v] -> IO ExitCode
raw T
opts a
sampleRate [v]
signal =
   (Handle -> [v] -> IO ()) -> T -> T -> Int -> [v] -> IO ExitCode
forall y (sig :: * -> *).
C y =>
(Handle -> sig y -> IO ()) -> T -> T -> Int -> sig y -> IO ExitCode
Play.extended Handle -> [v] -> IO ()
forall a. Storable a => Handle -> [a] -> IO ()
SoxList.put T
opts T
SoxOpt.none (a -> Int
forall b. C b => a -> b
forall a b. (C a, C b) => a -> b
round a
sampleRate) [v]
signal


exampleMono :: IO ExitCode
exampleMono :: IO ExitCode
exampleMono =
   Double -> [Double] -> IO ExitCode
forall a. C a => a -> [a] -> IO ExitCode
monoToInt16 (Double
11025::Double) ((Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map Double -> Double
forall a. C a => a -> a
sin [Double
0::Double,Double
0.2..])

exampleStereo :: IO ExitCode
exampleStereo :: IO ExitCode
exampleStereo =
   Double -> [(Double, Double)] -> IO ExitCode
forall a. C a => a -> [(a, a)] -> IO ExitCode
stereoToInt16 (Double
11025::Double) ([(Double, Double)] -> IO ExitCode)
-> [(Double, Double)] -> IO ExitCode
forall a b. (a -> b) -> a -> b
$
      [Double] -> [Double] -> [(Double, Double)]
forall a b. [a] -> [b] -> [(a, b)]
zip
         ((Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map Double -> Double
forall a. C a => a -> a
sin [Double
0::Double,Double
0.199..])
         ((Double -> Double) -> [Double] -> [Double]
forall a b. (a -> b) -> [a] -> [b]
map Double -> Double
forall a. C a => a -> a
sin [Double
0::Double,Double
0.201..])