
Thanks, everybody! Those were incredibly informative answers. This list is amazing. Heinrich's suggestion of compiling with "-threaded" was by itself sufficient to get the first rhythm to sound right. The second rhythm, however, still blurs into a string of beeps of the same duration even after I throw all of Heinrich's and Carter's suggestions at it by doing this: ghc --make fast -threaded -fno-omit-yields -with-rtsopts -C0 (although I should admit to not really knowing what I'm doing when I run that) where fast.hs is this: import Control.Concurrent import Text.Printf import Control.Monad import System.IO main = do hSetBuffering stdout NoBuffering mapM_ note (cycle [1,1,2]) beat = round (10^6 / 10) -- measured in microseconds note :: Int -> IO () note n = do threadDelay $ beat * n printf "\BEL\n" I therefore suspect I have to teach myself, as Brandon suggested, a realtime scheduler. This seems like a general, powerful thing: http://hackage.haskell.org/package/atom Hayoo also returns a lot of domain-specific results, e.g. from the Sound and Data.Reactive libraries: http://hackage.haskell.org/package/alsa-0.4/docs/Sound-Alsa-Sequencer.html http://hackage.haskell.org/package/midi-0.2.1.3/docs/Sound-MIDI-Message-Syst... http://hackage.haskell.org/package/definitive-reactive-1.0/docs/Data-Reactiv... but I suspect a general tool like Atom would be more useful so I'll start there. Thanks again, Jeff On Sun, Oct 19, 2014 at 12:40 AM, Heinrich Apfelmus < apfelmus@quantentunnel.de> wrote:
Jeffrey Brown wrote:
An earlier version of this question is cross-posted at StackOverflow <http://stackoverflow.com/questions/26437770/timing- inaccuracy-in-haskell-threaddelay> ..
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#v:threadDelay> 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
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe