module Sound.JACK.Audio (
Sample, Port, withPort,
withProcessMono,
withProcessStereo,
getBufferPtr,
getBufferArray,
mainMono,
mainStereo,
) where
import qualified Sound.JACK.Private as Priv
import qualified Sound.JACK as Jack
import Sound.JACK.Private (Client, )
import Sound.JACK (Direction, Input, Output, )
import qualified Sound.JACK.Exception as JackExc
import qualified Sound.JACK.FFI as JackFFI
import Sound.JACK.FFI (NFrames, nframesIndices, nframesBounds, )
import qualified Control.Monad.Exception.Synchronous as Sync
import qualified Control.Monad.Trans.Class as Trans
import Foreign.ForeignPtr (newForeignPtr_, )
import Foreign.Ptr (Ptr, )
import Foreign.C.Error (Errno, )
import qualified Foreign.C.Types as C
import System.Environment (getProgName)
import Data.Array.Storable
(StorableArray, readArray, writeArray,
unsafeForeignPtrToStorableArray)
type Sample = C.CFloat
type Port = Priv.Port Sample
withPort ::
(Direction dir,
JackExc.ThrowsPortRegister e,
JackExc.ThrowsErrno e) =>
Client
-> String
-> (Port dir -> Sync.ExceptionalT e IO a)
-> Sync.ExceptionalT e IO a
withPort = Jack.withPort
getBufferPtr ::
(Direction dir) =>
Port dir -> NFrames -> IO (Ptr Sample)
getBufferPtr (Priv.Port port) nframes =
JackFFI.port_get_buffer port nframes
getBufferArray ::
(Direction dir) =>
Port dir -> NFrames -> IO (StorableArray NFrames Sample)
getBufferArray port nframes =
flip unsafeForeignPtrToStorableArray (nframesBounds nframes)
=<< newForeignPtr_
=<< getBufferPtr port nframes
mainMono :: (Sample -> IO Sample) -> IO ()
mainMono fun = do
name <- getProgName
Jack.handleExceptions $
Jack.withClientDefault name $ \client ->
Jack.withPort client "input" $ \input ->
Jack.withPort client "output" $ \output ->
withProcessMono client input fun output $
Jack.withActivation client $ Trans.lift $ do
putStrLn $ "started " ++ name ++ "..."
Jack.waitForBreak
withProcessMono ::
(JackExc.ThrowsErrno e) =>
Client ->
Port Input -> (Sample -> IO Sample) ->
Port Output ->
Sync.ExceptionalT e IO a ->
Sync.ExceptionalT e IO a
withProcessMono client input fun output =
Jack.withProcess client $ wrapMonoFun input fun output
wrapMonoFun ::
Port Input -> (Sample -> IO Sample) ->
Port Output ->
NFrames -> Sync.ExceptionalT Errno IO ()
wrapMonoFun input fun output nframes = Trans.lift $ do
inArr <- getBufferArray input nframes
outArr <- getBufferArray output nframes
mapM_ (applyToArraysMono inArr fun outArr) (nframesIndices nframes)
applyToArraysMono ::
StorableArray NFrames Sample -> (Sample -> IO Sample)
-> StorableArray NFrames Sample
-> NFrames -> IO ()
applyToArraysMono inArr fun outArr i =
readArray inArr i >>= fun >>= writeArray outArr i
mainStereo :: ((Sample, Sample) -> IO (Sample, Sample)) -> IO ()
mainStereo fun = do
name <- getProgName
Jack.handleExceptions $
Jack.withClientDefault name $ \client ->
Jack.withPort client "inputLeft" $ \inputLeft ->
Jack.withPort client "inputRight" $ \inputRight ->
Jack.withPort client "outputLeft" $ \outputLeft ->
Jack.withPort client "outputRight" $ \outputRight ->
withProcessStereo client
inputLeft inputRight fun
outputLeft outputRight $
Jack.withActivation client $ Trans.lift $ do
putStrLn $ "started " ++ name ++ "..."
Jack.waitForBreak
withProcessStereo ::
(JackExc.ThrowsErrno e) =>
Client ->
Port Input -> Port Input ->
((Sample, Sample) -> IO (Sample, Sample)) ->
Port Output -> Port Output ->
Sync.ExceptionalT e IO a ->
Sync.ExceptionalT e IO a
withProcessStereo client inputLeft inputRight fun outputLeft outputRight =
Jack.withProcess client $
wrapStereoFun inputLeft inputRight fun outputLeft outputRight
wrapStereoFun ::
Port Input -> Port Input ->
((Sample, Sample) -> IO (Sample, Sample)) ->
Port Output -> Port Output ->
NFrames -> Sync.ExceptionalT Errno IO ()
wrapStereoFun iL iR fun oL oR nframes = Trans.lift $ do
inLArr <- getBufferArray iL nframes
inRArr <- getBufferArray iR nframes
outLArr <- getBufferArray oL nframes
outRArr <- getBufferArray oR nframes
mapM_ (applyToArraysStereo inLArr inRArr fun outLArr outRArr) (nframesIndices nframes)
applyToArraysStereo :: StorableArray NFrames Sample
-> StorableArray NFrames Sample
-> ((Sample, Sample) -> IO (Sample, Sample))
-> StorableArray NFrames Sample
-> StorableArray NFrames Sample
-> NFrames -> IO ()
applyToArraysStereo iL iR fun oL oR i = do
l <- readArray iL i
r <- readArray iR i
(l', r') <- fun (l, r)
writeArray oL i l'
writeArray oR i r'