opusfile-0.1.0.0: examples/openal-playfile/Main.hs
module Main where
import Control.Concurrent (threadDelay)
import Data.StateVar (($=))
import System.Environment (getArgs)
import Text.Printf (printf)
import qualified Data.ByteString as ByteString
import qualified Foreign
import qualified Sound.OpenAL as OpenAL
import qualified Sound.OpusFile as OpusFile
main :: IO ()
main = getArgs >>= \case
[] ->
putStrLn "Usage: openal-playfile <filename.opus>"
files ->
withAL $
mapM_ playFile files
playFile :: FilePath -> IO ()
playFile filename = do
(time, source) <- sourceOpusFile filename
OpenAL.play [source]
putStrLn $ printf "Playing %s (%.1f s)" (show filename) time
threadDelay $ truncate (time * 1000000)
sourceOpusFile :: FilePath -> IO (Double, OpenAL.Source)
sourceOpusFile filePath = do
Right file <- ByteString.readFile filePath >>= OpusFile.openMemoryBS
pcm <- OpusFile.decodeInt16 file
OpusFile.free file
buffer <- OpenAL.genObjectName
Foreign.withForeignPtr (OpusFile.pcmData pcm) \ptr -> do
let
mreg =
OpenAL.MemoryRegion ptr (fromIntegral $ OpusFile.pcmSize pcm)
alFormat =
case OpusFile.pcmChannels pcm of
Right OpusFile.Stereo ->
OpenAL.Stereo16
Right OpusFile.Mono ->
OpenAL.Mono16
Left n ->
error $ "unexpected channels: " <> show n
OpenAL.bufferData buffer $= OpenAL.BufferData mreg alFormat 48000
source <- OpenAL.genObjectName
OpenAL.buffer source $= Just buffer
pure (OpusFile.pcmTime pcm, source)
withAL :: IO () -> IO ()
withAL action = do
OpenAL.openDevice Nothing >>= \case
Nothing ->
error "boo. no device"
Just device -> do
OpenAL.createContext device [] >>= \case
Nothing ->
error "OpenAL.createContext failed"
Just ctx ->
OpenAL.currentContext $= Just ctx
() <- action
OpenAL.closeDevice device >>= print