
Jeffrey Brown wrote:
An earlier version of this question is cross-posted at StackOverflow http://stackoverflow.com/questions/26437770/timing-inaccuracy-in-haskell-thr... ..
What should I use for precise (and eventually, concurrency-compatible) timing in Haskell? I want to make rhythms. I tried the following to produce a repeating rhythm in which one note is twice as long as the other two. (That rhythm is encoded by the list [1,1,2].)
import Control.Concurrent import Text.Printf import Control.Monad
main = mapM_ note (cycle [1,1,2])
beat = round (10^6 / 4) -- measured in microseconds
note :: Int -> IO () note n = do threadDelay $ beat * n printf "\BEL\n"
When I run it the long note is three times as long as the others, not twice. If I speed it up, by changing the number 4 to a 10, the rhythm is destroyed completely: the notes all have the same length.
threadDelay is guaranteed http://hackage.haskell.org/package/base-4.7.0.1/docs/Control-Concurrent.html... to wait at least as long, but potentially longer than, what the caller specifies. Another potential problem could be buffering in printf. (Eventually I intend to replace the printf statement with OSC output to a sound generator.)
Thanks, Jeff
I found that that compiling a program with the -threaded option greatly improves the precision of threadDelay for the purpose of making rhythms. Your program is simple enough that this shouldn't make a difference, though. Note that there may also be issues with stdout buffering. Try System.IO.hSetBuffering stdout NoBuffering before the main loop. Best regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com