How to Play an Audio File from Haskell Code, Cross-Platform

How to play an audio file from Haskell code, cross-platform

This is the code I came up with, using SDL-1.2:

module PlaySound (withSound, playSound) where

import Control.Monad
import System.IO
import System.Directory
import Data.Foldable
import Control.Exception
import qualified Data.ByteString.Lazy as B
import Foreign.ForeignPtr

import Graphics.UI.SDL as SDL
import Graphics.UI.SDL.Mixer as Mix

withSound :: IO a -> IO a
withSound = bracket_ init cleanup
where
init = do
SDL.init [SDL.InitAudio]
getError >>= traverse_ putStrLn
ok <- Mix.tryOpenAudio Mix.defaultFrequency Mix.AudioS16LSB 2 4096
unless ok $
putStrLn "Failed to open SDL audio device"

cleanup = do
Mix.closeAudio
SDL.quit

playSound :: B.ByteString -> IO ()
playSound content = do
dir <- getTemporaryDirectory
(tmp, h) <- openTempFile dir "sdl-input"
B.hPutStr h content
hClose h

mus <- Mix.loadMUS tmp
Mix.playMusic mus 1
wait

-- This would double-free the Music, as it is also freed via a
-- finalizer
--Mix.freeMusic mus
finalizeForeignPtr mus
removeFile tmp

wait :: IO ()
wait = do
SDL.delay 50
stillPlaying <- Mix.playingMusic
when stillPlaying wait

The program in the end works fine, but

  • compiling the SDL bindings under Windows is tricky. I followed this nice explanation on how to do it
  • the SDL bindings for SDL-1.2 seem to be unmaintained and do not even compile with GHC-7.8 or newer. I didn’t notice at first, because my distribution (Debian) patches around such issues, but it means that my users cannot easily cabal install the dependencies any more.
  • there are bindings for SDL-2, but none for the SDL_mixer, which I need here (I believe).

So I’ll happily read better answers.

cross-platform API to play audio files in console-based application

Almost all programming languages have bindings to SDL and SDL_mixer, the latter has a relatively simple API to play audio files in common format.

Play a wav file with Haskell

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)

Capturing audio input from microphone, with Haskell?

easily capture microphone input and, perhaps, play various audio files as well..

It will strongly depend on your OS platform: there are standard C libraries for this functionality on each OS, and you'll be looking for Haskell bindings to them (e.g. PulseAudio, etc). Look in the Sound category on Hackage:

  • http://hackage.haskell.org/packages/archive/pkg-list.html#cat:sound

E.g. HSndFile for audio file writing, http://hackage.haskell.org/package/HSoundFile

Sound lib haskell

Being on Windows is a major limitation in Haskell audio. Most packages are bindings to C code, and they tend to be either Linux-centric (JACK, Alsa) or at best nominally cross-platform but in practice difficult to build and use on Windows. You'll need to build or install the C library first before installing the Haskell binding.

Have you tried OpenAL? It's probably the most well-suited for what you want to do. If you install the C OpenAL libraries, the Haskell binding should be a fairly simple next step. There are a few add-on packages that are meant to simplify some common tasks, like ALUT and Alure.

Otherwise, most other solutions would actually involve several packages that may not work well together. hsndfile and hsndfile-vector are good for reading audio files (you'll need to have libsndfile installed), but they don't play sound. portaudio will play audio (again, you'll need the C portaudio library), but it hasn't been updated in a while (and some updates are badly needed). You'll also need to be moderately familiar with a C compiler chain (e.g. MinGW or Cygwin) to install the necessary C libraries first.

Another way might be to bind to a dedicated audio language such as Supercollider or Csound. This would be a rather heavyweight solution, but the bindings tend to be better-maintained and at least Csound should be easily installable on Windows (disclosure: I wrote the hCsound package). Sox (C library/executable) might also work for you (I've never tried it on Windows, but it claims to work).

asp.net playing sound file from code behind

I'd try pulling it using Server.MapPath

System.Web.HttpContext.Current.Server.MapPath(path);

Which fopen() mode should i use when working with a .wav file?

This article indicates that using rb works well.
Note that nothing in this answer is Windows specific. Just standard C IO.



Related Topics



Leave a reply



Submit