On Wed, 2 Feb 2011, alex wrote:

So, why not hit reply and introduce yourself (even if you've posted
already), and reveal your interest in haskell and/or art, whatever
that may be.  I'll do it too, but someone else go first :)

Ok, where to start - at the very beginning? I first tried to make sound
with the ZX Spectrum from 1986 to 1990 with assembly programming, then with Amiga, various BASICs and assembly programming, then with a Modula-II
derivative called Cluster until around 2001:
   http://www.assampler.com/

Then I tried Modula-3 on Linux. When I later got to know Haskell, I found that I had reinvented lazy evaluation for Assampler. Consequently I moved to the original. I wanted to integrate music composition and signal processing. I wanted programming features for music arrangement, since the many trackers known from Amiga did not offer much structuring and thus required a lot of copy and paste. I wanted programming features also for signal processing, since the interactive graph editing became cumbersome for repetitive signal algorithms like vocoders, although I already added some support for them to Assampler. At a long weekend in 2004 I put together a song using Haskore and custom signal processing functions working on lists:
   http://users.informatik.uni-halle.de/~thielema/Music/winterade/winterade.mp3
Composing this piece was really crazy, since due to a bug in a SuSE upgrade, I could not play sounds. Thus I transfered every rendered stream to an Amiga via FTP and played it there.

Starting from this example I wrote more signal processes, tried to make them safer, cleaner, more flexible, faster, aware of physical units, adaptive to sample rates. I extended Haskore by Paul Hudak, wrote packages haskore-realtime, haskore-supercollider, supercollider-midi, event-list, midi, midi-alsa, streamed (realtime MIDI event manipulation in ALSA), sample-frame, sox, synthesizer-core, synthesizer-dimensional, synthesizer-alsa, synthesizer-llvm, extended and maintained storablevector (based on Spencer Janssen's work), numeric-prelude (based on Dylan Thurston's work), alsa-seq, alsa-pcm (based on Iavor Diatchki's work), jack (based on Sönke Hahn's work).

Using plain lists for signal processing I got perfect integration of signal processing and music and hours to wait for rendering results. In contrast to that, the hsc3 package by Rohan Drape allowed me to get realtime sound:
  http://www.youtube.com/watch?v=d2JvOwS26Zg
    (YouTube is great in making the audio track sound awful.
     Better follow the links in the video description to the original files.)

Using storablevector, stream-fusion:Stream like signal generators, and arrows for causal processes I got eventually realtime sound with plain Haskell:
  http://www.youtube.com/watch?v=KA6DE9jlpSY
Unfortunately this turned out to be really fragile. You can never predict what the optimizer will do and you easily get code that is no longer realtime. In many times the problem is as follows: If you use a function more than one time, then GHC may no longer inline it, and with the overhead of a real function call and lost opportunities for unboxing the performance drops dramatically. Maybe GHC-7.0 is better in this respect, I still have to check that.

2010 I started to use a DSL targeting LLVM JIT.
  http://www.youtube.com/watch?v=GNiAqBTVa6U
  http://www.youtube.com/watch?v=cuzYgJGfMfY
Performance is excellent, also due to vector unit support (SSE or AltiVec), but every release of LLVM surprises me with things that worked before and do not work any longer. Integration with Haskell is quite good, but it has the usual problems, that every DSL has. In contrast to a connection to SuperCollider or CSound, I can feed signal data from Haskell to LLVM code and pull it back. I would be very happy to use the same code for list based processing, storablevector based processing and LLVM based processing by some type class framework. That's not very easy, but I already managed to employ some computations both for pure Haskell and LLVM processing. I also spent a lot of time of hunting memory leaks. It is very easy to get them when relying on lazy evaluation. It is even hard or impossible to avoid them, even if you know, where they are. I am uncertain whether this problem is specific to GHC or whether this is hard and unsolved in general. I came to the suspicion that memory leaks are _the_ reason, why the garbage collector is considered to be not ready for real-time applications: The more memory is orphaned the more has the garbage collector to check for liveliness. The typical memory leak works as follows:
  let (prefix, suffix) = splitAt largeNumber xs
  in  processA prefix ++ processB suffix
Although this can be perfectly processed in a streaming manner, sometimes GHC does not manage to release the pointer to the beginning of prefix and thus prefix is kept until the processing of suffix starts. I wonder whether the problem could be solved if the garbage collector would be able to trigger evaluations if somewhere the memory consumption grows. My current plan is to move completely to causal arrows. I have already written a lot of code the Arrow way, but the remaining lazy processing still has hard to track leaks. I have to get rid of lazy evaluation completely, which is sad, since it allows for a very elegant style of programming.

_______________________________________________
haskell-art mailing list
haskell-art@lurk.org
http://lists.lurk.org/mailman/listinfo/haskell-art

Reply via email to