This is the sort of thing that most people would put in a blog post,
but I don't have a blog so I'm sending it to this list, since I think
most readers would be interested.

I've recently been doing some tests of different sound file I/O
packages in Haskell, and I would like to share the results.  My test
script involves reading a 66MB Wave file, a stereo recording at 44,100
/ 16.  The entire file is processed to determine the peak sample
value.  This is of particular instance to me because it involves
scanning a large amount of data in its entirety, the file format is
extremely common, and the process seems representative of the sort of
operations often encountered doing audio work.

I tested the following packages:


in addition, I tested two experimental interfaces to my library,
HSoundFile.  I did not test the current published interface,
HSoundFile v. 2.  The first interface I am experimenting with uses a
"smart handle" approach, and in some ways is very similar to a Haskell
implementation of libsndfile.  I refer to this as HSoundFile-3.   The
second interface uses an enumerator streams overlaid on a Word8
enumerator, derived from Oleg's Iteratee package.  I refer to this as

All packages are haskell only, except hsndfile, which is a binding to
the C libsndfile library.

Test harnesses:
HSoundFile-3 - a stream type is created to hold AudioBuffers.  A
recursive reader function uses unsafeInterleaveIO to read the entire
file on demand.  A strict foldl processes the Stream chunks to achieve
the final value.
Enumerator - An Iteratee is processes all values as received
Codecs - the data list is processed by a strict foldl
WAVE - the data list is processed by a strict foldl
hsndfile - a recursive I/O function reads a chunk from the file (using
IOCArray type) and accumulates the maximum values from each chunk.  I
attempted to create a framework like used for HSoundFile-3, however
performance dropped dramatically; I suspect the slowdown is mostly
from the process of freezing mutable arrays to immutable arrays.

API type:
HSoundFile-3 - strict reads/writes of buffers
Enumerator - enumerator-based strict I/O
Codecs - read/write entire file into data structure
WAVE - lazily read file into list
hsndfile - strict reads/writes of buffers

Data Types:
HSoundFile-3 -  custom AudioBuffer class.  Implementations are
provided for UArr Double, List Double, and StorableVector Double
Enumerator - enumerates Doubles
Codecs - array of Doubles
WAVE - [[Int32]]
hsndfile - custom Buffer class with Array constraint.  Implementations
are provided for IOCArray and StorableVector.

For chunked data types, all data is with chunk size 1000.
All timing/memory data is the median value from multiple runs.  In
general different runs had very similar performance.

Timing results:
HSoundFile-3, StorableVector - real 16.5s
HSoundFile-3, UArr                    - real 15.7s
HSoundFile-3, List                      - real 17.6s
Codecs                                         - real 1m20s
Enumerator                                  - real 19s
WAVE                                            - real 29.1s
hsndfile                                         - real 2.0s

Memory results (running test program with -hT)
HSoundFile-3, StorableVector  - 457,674,398 bytes x seconds
HSoundFile-3, UArr                     - 531,452,404 bytes x seconds
HSoundFile-3, List                       - 532,806,405 bytes x seconds
Codecs                                           - 5,869,214,258 bytes x seconds
Enumerator                                   - 957,845 bytes x seconds
WAVE                                             - 986,310,412 bytes x seconds
hsndfile                                          - 23,160 bytes x seconds

A few notes:
I did make an HSoundFile-3 implementation that used only UArrs, not
the AudioBuffer class.  This implementation was about 2 seconds faster
for this test than the shown implementation, however I didn't think
the extra efficiency was worth the more restrictive API.

Anyway, that's what I've found so far.  I was very hopeful that at
least one of  the pure haskell packages would be similar to hsndfile,
but unfortunately I haven't found anything at this time.  It's
certainly beyond my ability.

haskell-art mailing list

Reply via email to