packages feed

call-0.0.1: src/Call/Internal/PortAudio.hs

{-# LANGUAGE ViewPatterns, FlexibleContexts #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Call.Internal.PortAudio(Error(..), with) where

import Bindings.PortAudio
import Foreign.C.Types
import Foreign hiding (with)
import Control.Monad.IO.Class
import Control.Monad
import Linear
import Control.Exception
import Data.Typeable
data Error = NotInitialized
  | UnanticipatedHostError
  | InvalidChannelCount
  | InvalidSampleRate
  | InvalidDevice
  | InvalidFlag
  | SampleFormatNotSupported
  | BadIODeviceCombination
  | InsufficientMemory
  | BufferTooBig
  | BufferTooSmall
  | NullCallback
  | BadStreamPtr
  | TimedOut
  | InternalError
  | DeviceUnavailable
  | IncompatibleHostApiSpecificStreamInfo
  | StreamIsStopped
  | StreamIsNotStopped
  | InputOverflowed
  | OutputUnderflowed
  | HostApiNotFound
  | InvalidHostApi
  | CanNotReadFromACallbackStream
  | CanNotWriteToACallbackStream
  | CanNotReadFromAnOutputOnlyStream
  | CanNotWriteToAnInputOnlyStream
  | IncompatibleStreamHostApi
  | BadBufferPtr
  deriving (Show, Eq, Ord, Enum, Typeable)

instance Exception Error

fromErrorCode :: CInt -> Error
fromErrorCode n = toEnum (fromIntegral n + 10000)
{-
data Host = Host Int String

getHostApis :: MonadIO m => m [Host]
getHostApis = liftIO $ do
    n <- c'Pa_GetHostApiCount
    forM [0..n - 1] $ \i -> do
      info <- c'Pa_GetHostApiInfo i >>= peek
      name <- peekCAString $ c'PaHostApiInfo'name info
      return (Host (fromIntegral i) name)
-}
callback :: (Int -> IO [V2 Float]) -> Ptr () -> Ptr () -> CULong -> x -> y -> z -> IO CUInt
callback f (castPtr -> _) (castPtr -> pout) (fromIntegral -> n) _ _ _ = do
  f n >>= pokeArray pout
  return c'paContinue

with :: MonadIO m => Double -> Int -> (Int -> IO [V2 Float]) -> m a -> m a
with rate buf f m = do
    w c'Pa_Initialize
    cb <- liftIO $ mk'PaStreamCallback $ callback f
    
    ps <- liftIO malloc
    w $ c'Pa_OpenDefaultStream ps
        0
        2
        1 -- Float
        (realToFrac rate)
        (fromIntegral buf)
        cb
        nullPtr
    s <- liftIO $ peek ps

    w $ c'Pa_StartStream s
    r <- m
    w $ c'Pa_StopStream s
    w $ c'Pa_CloseStream s
    w $ c'Pa_Terminate
    return r
    where
      w n = do
        r <- liftIO n
        unless (r == 0) $ liftIO $ throwIO $ fromErrorCode r