
I wrote a program in Haskell that does real-time MIDI playback. This involves computing what are called MIDI "events" (things like notes and volume controls) and then using the PortMidi library to play back the events. PortMidi also provides a time reading function that is accurate to 1 millisecond which is useful for timing the playback accurately. I used 'evaluate' in the IO Monad to make sure that all events were fully computed before playback started. However I was still getting delays (timing errors). I added some code to the program that wrote the data to disk before playing it back, and the timing errors went away. Apparently 'evaluate' was not forcing a complete evaluation, while writing a disk file was. Or at least I think that's what happened. But writing to disk is a hack. What can I do to get 'evaluate' to work? A simplified version of the code is here: (the actual program is pretty long and complex so I posted something which is stripped down but I hope retains the essential features) http://lpaste.net/144762

Dear Dennis, note that the `evaluate` function only evaluates to weak head normal form (WHNF). A list may be in WHNF even when the head and tail are unevaluated expressions. What you want is to evaluate the list of notes to normal form (NF). The `Control.DeepSeq` module collects functions related to obtaining normal forms. In your case, changing the line to midiEvents <- evaluate $ force $ computeMidiEvents music will probably do the trick, but you may need to implement an instance NFData for your `MidiEvent` type. For more details on NF, WHNF and lazy evaluation in general, see also [1]. [1]: https://hackhands.com/lazy-evaluation-works-haskell/ Best regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com Dennis Raddle wrote:
I wrote a program in Haskell that does real-time MIDI playback. This involves computing what are called MIDI "events" (things like notes and volume controls) and then using the PortMidi library to play back the events. PortMidi also provides a time reading function that is accurate to 1 millisecond which is useful for timing the playback accurately.
I used 'evaluate' in the IO Monad to make sure that all events were fully computed before playback started. However I was still getting delays (timing errors). I added some code to the program that wrote the data to disk before playing it back, and the timing errors went away. Apparently 'evaluate' was not forcing a complete evaluation, while writing a disk file was. Or at least I think that's what happened.
But writing to disk is a hack. What can I do to get 'evaluate' to work?
A simplified version of the code is here: (the actual program is pretty long and complex so I posted something which is stripped down but I hope retains the essential features)

Thanks! I have a problem though. I read about automatic derivation of an NFData instance. I have GHC version 7.10.2. I tried the code below, but I get Can't make a derived instance of Generic RawMidiEvent You need DeriveGeneric to derive an instance of this class. In the data declaration for 'RawMidiEvent' {-# LANGUAGE DeriveGeneric, DeriveAnyClass #-} import GHC.Generics (Generic) import Control.DeepSeq data RawMidiEvent = RawMidiEvent { rmeStream :: Int , rmeChan :: Int , rmeStatus :: Int , rmeData1 :: Int , rmeData2 :: Int } deriving (Show,Eq,Generic,NFData)

Never mind, I realized that I use the pragma incorrectly -- it wasn't at
the top of the module.
On Fri, Nov 6, 2015 at 3:26 PM, Dennis Raddle
Thanks! I have a problem though. I read about automatic derivation of an NFData instance. I have GHC version 7.10.2. I tried the code below, but I get
Can't make a derived instance of Generic RawMidiEvent You need DeriveGeneric to derive an instance of this class. In the data declaration for 'RawMidiEvent'
{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}
import GHC.Generics (Generic) import Control.DeepSeq
data RawMidiEvent = RawMidiEvent { rmeStream :: Int , rmeChan :: Int , rmeStatus :: Int , rmeData1 :: Int , rmeData2 :: Int } deriving (Show,Eq,Generic,NFData)
participants (2)
-
Dennis Raddle
-
Heinrich Apfelmus