In this short lesson you will learn how to play sound in your HOpenGL applications. Please keep two things in mind here:
Ok, let's start. First of all, let me explain how the sound stuff works: there is a Windows system routine called
PlaySound, that is used to play simple sound files (such as .wav). I'll make available to you a module, written in Haskell, that treats this routine as a foreing function, and makes it possible to call it in a Haskell program, although it was written in another language. I won't explain how this module works, because this is not a HOpenGL topic, but you can get more information about the Haskell FFI (Foreign Function Interface) here.
Ok, since you download this Sound module you'll be ready to start. We'll use only one single funciton from it,
playSound, which is a binding to the original
PlaySound Windows function. Its signature is:
playSound :: String -> Win32.HMODULE -> [SoundFlag] -> IO Bool
Notice that it returns a boolean, indicating if the sound file was played successfully or not. The
String corresponds to the path to the .wav file. Don't worry about the second argument: it'll always be
nullAddr, because we won't use any advanced sound features, as mentioned before. By the way, you can check out the
PlaySound documentation for more details if you wish.
The third argument of
playSound is the most interesting: it tells how the sound will be played. Its possible values are:
Some of these values are too advanced for we to cover here, but others are very interesting. Let's check some of them:
Sync- Synchronous playback of a sound event:
playSoundreturns after the sound event completes. In other words, your HOpenGL application will stop completely (freeze) during the execution of the sound.
Async- The sound is played asynchronously and
playSoundreturns immediately after beginning the sound (your HOpenGL application won't freeze and its computations will occur in parallel with the sound execution).
Loop- The sound plays repeatedly until
playSoundis called again. You must also specify the
Asyncflag to indicate an asynchronous sound event.
NoStop- The specified sound event will yield to another sound event that is already playing (the sound won't interrupt another sound that is being executed).
NoWait- If the driver is busy, return immediately without playing the sound.
Ok, let's create some code now, since you understood some sound theory. Our application will be very simple: if the user presses the
4 keyboard key, the sound
4.wav will be played respectively. Sound 1 will be synchronous, sound 2 will be asynchronous, sound 3 will be played repeatedly (loop) and sound 4 won't interrupt any other sound that is being currently played.
The first thing to do is to import the
Sound module (besides the
GLUT modules, of course). Then create an empty window and register the function
keyboard as our keyboard callback function:
main :: IO ()
main = do
createWindow "Sound Example" (return ()) [ Single, GLUT.Rgb ]
(Just (WindowPosition 100 100))
(Just (WindowSize 300 250))
keyboardFunc (Just keyboard)
Now there is only one thing left: define what
keyboard should do. As you may have guessed, it's a very easy job: it's just necessary to set the correct flags to the sound events:
keyboard :: KeyboardAction
keyboard '1' _ = playSound "1.wav" nullAddr [Async] >>= \soundStatus -> print soundStatus
keyboard '2' _ = playSound "2.wav" nullAddr [Sync] >>= \soundStatus -> print soundStatus
keyboard '3' _ = playSound "3.wav" nullAddr [Loop,Async] >>= \soundStatus -> print soundStatus
keyboard '4' _ = playSound "4.wav" nullAddr [NoStop] >>= \soundStatus -> print soundStatus
keyboard _ _ = return ()
Notice that the prompt shows if the sound was played successfully or not (
soundStatus). Notice also that we can call
playSound with more that one sound flag. For example, if you wish that sound 4 to also be played asynchronously, you would use:
keyboard '4' _ = playSound "4.wav" nullAddr [Async,NoStop] >>= \soundStatus -> print soundStatus
That's it, now we are done. I'd like to thank Monique Monteiro for helping with sound issues.