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.