play package:synthesizer-core
First, we define a play routine for lazy storable vectors. Storable
lazy vectors are lazy lists of low-level arrays. They are both
efficient in time and memory consumption, but the blocks disallow
feedback by small delays. Elements of a storable vector must be of
type class Storable. This means that elements must have fixed size and
advanced data types like functions cannot be used.
For the following examples we will stick to monophonic sounds played
at 44100 Hz. Thus we define a function for convenience.
The next signal type we want to consider is the stateful signal
generator. It is not a common data structure, where the sample values
are materialized. Instead it is a description of how to generate
sample values iteratively. This is almost identical to the
Data.Stream module from the stream-fusion package.
With respect to laziness and restrictions of the sample type (namely
none), this signal representation is equivalent to lists. You can
convert one into the other in a lossless way. That is, function as
sample type is possible. Combination of such signal generators is
easily possible and does not require temporary storage, because this
signal representation needs no sample value storage at all. However at
the end of such processes, the signal must be materialized. Here we
write the result into a lazy storable vector and play that. What the
compiler actually does is to create a single loop, that generates the
storable vector to be played in one go.