{-# LANGUAGE ViewPatterns, LambdaCase #-} import Bindings.PortAudio import Control.Applicative import Control.Concurrent.MVar import Control.Monad import Foreign.C.String import Foreign.C.Types import Foreign import qualified Data.Vector as V import System.Environment period :: Int period = 128 table :: V.Vector CFloat table = V.fromList [sin t | i <- [0..period - 1], let t = fromIntegral i / fromIntegral period * 2 * pi] callback phase _ (castPtr -> o) (fromIntegral -> n) info _ _ = do i0 <- takeMVar phase go i0 0 putMVar phase $ i0 + n return c'paContinue where go i0 i | i == n = return () | otherwise = do let v = table V.! ((i0 + i) `mod` period) pokeElemOff o (2 * i) v pokeElemOff o (2 * i + 1) v go i0 (i + 1) dbg s m = do e <- m putStrLn $ s ++ ": " ++ show e unless (e == 0) $ fail "Failed." main = getArgs >>= \case ((read -> rate) : (read -> buf) : _) -> do dbg "Initialization" c'Pa_Initialize n <- c'Pa_GetHostApiCount putStrLn "Available APIs: " forM_ [0..n - 1] $ \i -> do info <- c'Pa_GetHostApiInfo i >>= peek name <- peekCAString $ c'PaHostApiInfo'name info print (i, name) ref <- newMVar 0 cb <- mk'PaStreamCallback $ callback ref ps <- malloc dbg "Opening the default stream" $ c'Pa_OpenDefaultStream ps 0 2 1 rate buf cb nullPtr s <- peek ps dbg "Starting the stream" $ c'Pa_StartStream s c'Pa_Sleep 1000 dbg "Stopping the stream" $ c'Pa_StopStream s dbg "Closing the stream" $ c'Pa_CloseStream s c'Pa_Terminate