haskell - Using Gloss to run a simulation while using SDL to play a sound -
i have simulation that's tied data gleaned sound file. run simulation , play sound file @ same time see how data matches up.
the problem seem unable play sound via sdl.mixer , run gloss simulation @ same time. both of these functions work fine on own.
the window simulation gets created, nothing drawn , wav file plays. data make model simulation (onsets
) extremely computationally expensive? doesn't seem evaluated @ all.
{-# language scopedtypevariables #-} module main import ghc.float import debug.trace import control.concurrent import control.monad.fix import control.monad import graphics.gloss import graphics.gloss.interface.pure.simulate import graphics.gloss.data.color import qualified sound.file.sndfile snd import qualified sound.file.sndfile.buffer.vector b import qualified graphics.ui.sdl sdl import qualified graphics.ui.sdl.mixer mix --my own libraries import sound.analysis.spectrum import sound.analysis.spectralflux import sound.analysis.onset import sound.data.buffers --(timeelapsed, todraw, tobedrawn) type time = float type drawableonsets = (time, onset, onsetstream) main = --bs holds our buffers (info, (bs :: b.buffer double)) <- snd.readfile "./downtheroad.wav" --convert unboxed array let b = sterilize bs --grab of sound file let ct = (truncate $ (fromintegral $ snd.frames info)/2048) let = streaminfo 1024 44100 2 let b' = samplerawpcm 0 ct (i, b) let s = pcmstream b' --very expensive computations let freqs = freqstream s --get frequency bins let fluxes = fluxstream freqs --get spectral flux let onsets = onset fluxes --get onsets based on spectral flux let onsetmodel = makemodel onsets let dispwin = inwindow "onset test" (1440, 300) (0,0) forkio playsound simulate dispwin white 45 onsetmodel drawonsets stepworld print "done" playsound = sdl.init [sdl.initaudio] result <- mix.openaudio 44100 mix.audios16lsb 2 4096 toplay <- mix.loadwav "./downtheroad.wav" ch1 <- mix.playchannel (-1) toplay 0 fix $ \loop -> sdl.delay 50 stillplaying <- mix.numchannelsplaying when (stillplaying /= 0) loop makemodel :: onsetstream -> drawableonsets makemodel (i, os) = (0.0, onset 0 0.0, (i, os)) drawonsets :: drawableonsets -> picture drawonsets (t, o, os) = translate x 50 $ color red $ circlesolid rad rad = (double2float $ power o)*0.01 x = (fromintegral $ frame o) stepworld :: viewport -> float -> drawableonsets -> drawableonsets stepworld vp t' (t, o, (i, os)) = (elapsed, o', (i, os')) o' | elapsed > nexttime = head os | otherwise = o os' | (elapsed > nexttime) = tail os | otherwise = os elapsed = t+t'*1000 interval = (fromintegral $ samplerate i)/(fromintegral $ fftwindow i) nexttime = (fromintegral $ frame o) * 86
i've tried few things such using evaluate
in control.exception
package such.
makemodel :: drawableonsets -> io drawableonsets makemodel (i, os) = evaluate (0.0, onset 0 0.0, os)
to try , force evaluation of expensive computations, seems have no effect. same goes adding bang pattern makemodel
, in let
declarations in main
.
... let !freqs = freqstream s let !fluxes = fluxstream freqs ... makemodel (i, !os) = (0.0, onset 0 0.0, os)
futhermore, if try forkio both playsound
, simulate
program terminates without playing sound or simulation.
any appreciated!
your code not self-contained, stripped down forkio playsound
followed gloss.display
of static picture, , experienced same problem: sound playing nothing displayed until stops.
i found out sdl-mixer uses unsafe
foreign functions not preemptible. replaced sdl.delay 50
(which blocks current os thread entire duration) threaddelay 50000
give scheduler chance work, , changed forkio
forkos
make sure ffi calls sdl issued same os thread (generally idea when dealing stateful libraries). picture appears immediately, sound ends abruptly after fraction of second.
then found this answer suggesting audio chunk freed haskell gc while still playing. after inserting touchforeignptr toplay
before threaddelay
works expected.
playsound = sdl.init [sdl.initaudio] result <- mix.openaudio 44100 mix.audios16lsb 2 4096 toplay <- mix.loadwav "./sound.wav" ch1 <- mix.playchannel (-1) toplay 0 fix $ \loop -> touchforeignptr toplay threaddelay 50000 stillplaying <- mix.numchannelsplaying when (stillplaying /= 0) loop
of course, make sure compile threaded rts (-threaded
ghc option). computationally intensive simulation may introduce additional problems, eager know how works out you.
Comments
Post a Comment