Christopher Done
Christopher Done

Reputation: 5974

Play a wav file with Haskell

Is there a simple, direct way to play a WAV file from Haskell using some library and possibly such that I play many sounds at once?

I'm aware of OpenAL but I'm not writing some advanced audio synthesis program, I just want to play some sounds for a little play thing. Ideally the API might be something like:

readWavFile :: FilePath -> IO Wave
playWave :: Wave -> IO ()
playWaveNonBlocking :: Wave -> IO ()

I'm this close to merely launching mplayer or something. Or trying to cat the wav directly to /dev/snd/ or somesuch.

Upvotes: 25

Views: 4719

Answers (4)

yokoP
yokoP

Reputation: 1

module Main (main) where

import qualified SDL
import SDL.Mixer 

main :: IO ()
main = do
  SDL.initialize [SDL.InitAudio]
  withAudio defaultAudio 4096 $ do
    load "test.wav" >>= play
    SDL.delay 1000 
  SDL.quit

I was trying to play sound with Haskell and I found this board when I searched how to do this. Actually, I want to know some kind of solution in Japanese sites because I am Japanese, but I couldn't find such sites.
I tried the OpenAl one above and with a little revision I succeeded, but I want to have a result with a simpler way.
I use 'sdl2' and 'sdl2-mixer' library. To do this, I had to install sdl2 and sdl2-mixer library into my OS.

I am using DebianOS and I installed 'libsdl2-dev' and 'libsdl2-mixer-dev' with apt command.

sudo apt instll libsdl2-dev libsdl2-mixer-dev

(Because I installed these files many months ago, so my memory is ambiguous.) I use 'stack' to launch a Haskell project.

stack new myproject

(myproject is the project name)

In the myproject folder I edited the package.yaml file:

dependencies:
- base >= 4.7 && < 5
- sdl2
- sdl2-mixer

and I also edited then Main.hs file in the app folder. That is the above code.
I put the test.wav file in the myproject folder and with the command:

stack run

I could play the test sound.

Upvotes: 0

Cybr Anvl
Cybr Anvl

Reputation: 83

using OpenAL through ALUT:

import Control.Monad
import Sound.ALUT

playSound :: IO ()
playSound =
  withProgNameAndArgs runALUTUsingCurrentContext $ \_ _ ->
  do
    (Just device) <- openDevice Nothing
    (Just context) <- createContext device []
    currentContext $= Just context
    buffer1 <- createBuffer $ Sine 440 0 1
    buffer2 <- createBuffer HelloWorld
    [source] <- genObjectNames 1
    queueBuffers source [buffer1,buffer2]
    play [source]
    sleep 4
    closeDevice device
    return ()

main = playSound

to load a wav file:

buffer3 <- createBuffer $ File "/path/to/file.wav"

credit goes to Chris Double: http://bluishcoder.co.nz/articles/haskell/openal.html

Upvotes: 4

Christopher Done
Christopher Done

Reputation: 5974

This is how to play multiple sounds on multiple channels at once with SDL. I think this answers the question criteria. WAV files, simple, Haskell, multiple channels.

import Control.Monad
import Control.Monad.Fix
import Graphics.UI.SDL as SDL
import Graphics.UI.SDL.Mixer as Mix

main = do
  SDL.init [SDL.InitAudio]
  result <- openAudio audioRate audioFormat audioChannels audioBuffers
  classicJungle <- Mix.loadWAV "/home/chris/Samples/ClassicJungle/A4.wav"
  realTech      <- Mix.loadWAV "/home/chris/Samples/RealTech/A4.wav"
  ch1 <- Mix.playChannel anyChannel classicJungle 0
  SDL.delay 1000
  ch2 <- Mix.playChannel anyChannel realTech 0
  fix $ \loop -> do
    SDL.delay 50
    stillPlaying <- numChannelsPlaying
    when (stillPlaying /= 0) loop
  Mix.closeAudio
  SDL.quit

  where audioRate     = 22050
        audioFormat   = Mix.AudioS16LSB
        audioChannels = 2
        audioBuffers  = 4096
        anyChannel    = (-1)

Upvotes: 35

C. A. McCann
C. A. McCann

Reputation: 77384

I realize this is not actually a convenient way to do it, but I had the test code lying around, so...

{-# LANGUAGE NoImplicitPrelude #-}
module Wav (main) where

import Fay.W3C.Events
import Fay.W3C.Html5

import Language.Fay.FFI
import Language.Fay.Prelude

main :: Fay ()
main = addWindowEventListener "load" run

run :: Event -> Fay Bool
run _ = do
    aud <- mkAudio
    setSrc aud "test.wav"
    play aud
    return False


mkAudio :: Fay HTMLAudioElement
mkAudio = ffi "new Audio()"

addWindowEventListener :: String -> (Event -> Fay Bool) -> Fay ()
addWindowEventListener = ffi "window['addEventListener'](%1,%2,false)"

There you go--playing a WAV file in Haskell thanks to the power of HTML5! All you have to do is launch a web browser instead of mplayer. :D

Upvotes: 9

Related Questions