module Sound.Sox.Play where

import qualified Sound.Sox.Frame as Frame
import Sound.Sox.System (catchCtrlC, )

import qualified Sound.Sox.Option.Format as Option
import qualified Sound.Sox.Private.Option as OptPriv
import qualified Sound.Sox.Private.Arguments as Args
import Data.Monoid (mconcat, )

import qualified System.Process as Proc
import qualified System.IO as IO
import Control.Exception (bracket, )
import System.Exit (ExitCode, )



{- |
> :load Sound.Sox.Play Sound.Sox.Signal.List
>
> simple Sound.Sox.Signal.List.put Option.none 11025 (iterate (1000+) (0::Data.Int.Int16))
-}
simple ::
   (Frame.C y) =>
   (IO.Handle -> sig y -> IO ())
      {- ^ Writer routine -
           e.g. 'Sound.Sox.Signal.List.put'
           or 'Data.StorableVector.hPut' -} ->
   Option.T ->
   Int
      {- ^ sample rate -} ->
   sig y ->
   IO ExitCode
simple write opts =
   extended write Option.none opts

extended ::
   (Frame.C y) =>
   (IO.Handle -> sig y -> IO ())
      {- ^ Writer routine -
           e.g. 'Sound.Sox.Signal.List.put'
           or 'Data.StorableVector.hPut' -} ->
   Option.T
      {- ^ source options, usually none -} ->
   Option.T
      {- ^ target options -} ->
   Int
      {- ^ sample rate -} ->
   sig y ->
   IO ExitCode
extended write srcOpts dstOpts sampleRate stream =
   bracket
      {-
      Formerly we called 'play' here.
      On Windows the SoX package does not install a 'play' command.
      However using the '-d' argument for the destination always works.
      -}
      (Proc.runInteractiveProcess "sox"
          (Args.decons $ mconcat $
           OptPriv.toArguments
             (mconcat $
              srcOpts :
              Option.numberOfChannels
                 (Frame.withSignal Frame.numberOfChannels stream) :
              Option.sampleRate sampleRate :
              Option.format (Frame.withSignal Frame.format stream) :
              []) :
           Args.pipe :
           OptPriv.toArguments dstOpts :
           Args.single "-d" :
           [])
          Nothing Nothing)
      (\(input,output,err,_proc) ->
          mapM_ IO.hClose [input, output, err])
      (\(input,_,_,proc) ->
         catchCtrlC >>
         write input stream >>
         return proc)
   -- wait for end of replay
   >>= Proc.waitForProcess