views:

405

answers:

3

I'm writing an audio program in Haskell using Portaudio. I have a function that generates a list of samples I'd like to play, and I'm trying to play them using the following snippet inside main:

curSamps <- return (chunk 1 (sineWave 440 44100))
forever $ do
  Right numSampsAvail <- getStreamWriteAvailable paStream
  Right NoError <- writeStream paStream curSamps numSampsAvail
  curSamps <- return (drop numSampsAvail curSamps)

sineWave is a function I've created to generate an infinite list of Int16 samples of a sinewave at a specified frequency and sample rate.

When I debug this code, by replacing the audio output code with a putStrLn, it prints all 0s, which is the first sample from the function.

How can I iterate over this list with the audio output functions? I don't think I can use recursion or a map.

Edit: Code copying mistake

+2  A: 

Using the same API functions one can do this:

let playSamples curSamps = do
      Right numSampsAvail <- getStreamWriteAvailable paStream
      Right NoError <- writeStream paStream curSamps numSampsAvail
      playSamples (drop numSampsAvail curSamps)
playSamples (chunk 1 (sineWave 440 44100))

I'm not familiar with the Portaudio API, so it might provide a more convenient, higher-level way of doing what you're trying to achieve.

Reid Barton
+4  A: 

Use recursion:

play []       = return ()
play curSamps = do Right numSampsAvail <- getStreamWriteAvailable paStream
                   Right NoError <- writeStream paStream curSamps numSamps
                   play (drop numSampsAvail curSamps)

main = do ...
          play (chunk 1 (sineWave 440 44100))
          ...
Dave Hinton
+4  A: 

Consider using map's monadic cousins mapM/forM.

Dario
Each recursion/loop drops a variable number of samples from the list (`drop numSampsAvail`). I think that makes it difficult to use mapM.
Nefrubyr
@Nefrubyr: We need a monadic fold then.
Dario