{-# OPTIONS -fno-implicit-prelude #-}
module Sox.Play where

import qualified BinarySample as BinSmp
import qualified Sox          as Sox

import System.IO(IO)
import qualified System.IO as IO

import qualified System.Process as Proc
import Control.Exception(bracket)

{-
import qualified Shell
-}
import qualified System.Posix.Signals as Signals

import qualified Algebra.RealField      as RealField

import PreludeBase
import NumericPrelude


autoR :: (RealField.C a, BinSmp.C v) => a -> (a -> [v]) -> IO ()
autoR sampleRate renderer =
   auto sampleRate (renderer sampleRate)

monoR :: (RealField.C a) => a -> (a -> [a]) -> IO ()
monoR sampleRate renderer =
   mono sampleRate (renderer sampleRate)

stereoR :: (RealField.C a) => a -> (a -> [(a,a)]) -> IO ()
stereoR sampleRate renderer =
   stereo sampleRate (renderer sampleRate)


auto :: (RealField.C a, BinSmp.C v) => a -> [v] -> IO ()
auto sampleRate signal =
   raw [] sampleRate (BinSmp.numChannels (head signal))
      (BinSmp.signalToBinary signal)

mono :: (RealField.C a) => a -> [a] -> IO ()
mono sampleRate signal =
   raw [] sampleRate 1 (BinSmp.signalToBinaryMono signal)

stereo :: (RealField.C a) => a -> [(a,a)] -> IO ()
stereo sampleRate signal =
   raw [] sampleRate 2 (BinSmp.signalToBinaryStereo signal)

{- |
Disable sigPIPE.
This means that the whole program won't crash when the tool exits.
Unfortunately there doesn't seem to be another way of doing this.

If we don't call this, GHCi quits,
when the playing command is aborted with CTRL-C.
-}
catchCtrlC :: IO Signals.Handler
catchCtrlC =
      Signals.installHandler Signals.sigPIPE 
		  Signals.Ignore Nothing

{-
raw :: Show a => [String] -> a -> [Int] -> IO ()
raw args sampleRate stream =
   do catchCtrlC
      (input,_,_) <- Shell.launch "play"
          (["auto"] ++ Sox.sampleRateOption sampleRate ++
           ["-t","sw","-"] ++ args)
      BinSmp.putInt16Stream input stream
      IO.hClose input
-}

{- |
This routine is probably portable
if there were not the CTRL-C problem.
-}
raw :: (RealField.C a) => [String] -> a -> Int -> [Int] -> IO ()
raw args sampleRate numChannels stream =
   bracket
      (Proc.runInteractiveProcess "play"
          (Sox.channelOption numChannels ++
           Sox.sampleRateOption sampleRate ++
           ["-t","sw","-"] ++ args)
          Nothing Nothing)
      (\(input,output,err,proc) -> do
          mapM IO.hClose [input, output, err]
          -- wait for end of replay
          Proc.waitForProcess proc)
      (\(input,_,_,_) ->
         catchCtrlC >>
         BinSmp.putInt16Stream input stream)

example :: IO ()
example = auto (11025::Double) (map sin [0::Double,0.1..])