[Haskell-beginners] audio generation

Daniel Bergey bergey at alum.mit.edu
Sat Apr 30 18:00:11 UTC 2016


The entire topic of space use in Haskell is not simple, but the part you
need here may be.  As long as GHC can tell that values already written
to disk may be garbage collected, memory use is quite reasonable.

For example, here's a short program that prints a long-ish list:

xs :: [Double]
xs = map cos [1..1e7]

main :: IO ()
main = traverse_ print $ map sin xs

It runs in constant space, of less than 1 MB.  (I ran it on a few
smaller cases to confirm that max residency stays the same order of
magnitude.)  Note the difference between "bytes allocated" and "total
memory in use".

$ ./laziness +RTS -sstderr  > /dev/null
 181,493,398,808 bytes allocated in the heap
     414,623,400 bytes copied during GC
         131,736 bytes maximum residency (2 sample(s))
          23,520 bytes maximum slop
               1 MB total memory in use (0 MB lost due to fragmentation)

This next program generates random numbers.  You could use the State
monad; here I've just used the infinite list generator in System.Random.

main = do
  g <- newStdGen
  let xs = take 100000 (randoms g) :: [Int]
  traverse_ print xs

This one also runs in constant space:

$ ./.cabal-sandbox/bin/lazyRandom +RTS -sstderr > /dev/null
     380,128,240 bytes allocated in the heap
         238,472 bytes copied during GC
          44,312 bytes maximum residency (2 sample(s))
          21,224 bytes maximum slop
               1 MB total memory in use (0 MB lost due to fragmentation)

Based on these tests, I'd recommend trying to structure your program as
a map or fold over a (lazy) list.  If that structure makes sense for your
problem, I'd expect managing memory usage to be as simple as the cases
above.  I expect that memory usage will be constant in the number of
samples, although higher than my examples because each sample is bigger
than the Int or Double I used.

Let me know if you want me to elaborate on any of this.

bergey

On 2016-04-29 at 23:58, Dennis Raddle <dennis.raddle at gmail.com> wrote:
> I'm writing a program that will use functions to generate audio. The Haskell code will
> write the audio samples to disk---no need for real time playback. I see some useful
> libraries for writing audio files. 
>
> My question concerns efficiency when generating several million to 20 million samples
> (or even many times more than that if I use high-resolution sampling rates). They can be
> generated one at a time in sequence, so there's no need to occupy a lot of memory or
> postpone thunk evaluation. I'm going to need efficient disk writing. Note that I may
> need some pseudorandom numbers in my calculations, so I might want to calculate samples
> by state monadic computations to carry the generator state. What is my general strategy
> going to be for memory and time efficiency? I am pretty confused by Haskell "strictness"
> and normal head form and all that, which often doesn't seem to be very strict. Or bang
> patterns, etc. Is it going to be simple to understand what I need? 
>
> Dennis
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://mail.haskell.org/cgi-bin/mailman/listinfo/beginners


More information about the Beginners mailing list