[Haskell-cafe] ANN: Hemkay, the 100% Haskell MOD player

Patai Gergely patai_gergely at fastmail.fm
Wed Dec 23 07:29:59 EST 2009

> I see no problem. I would generate a frequency and a volume control
> curve for each channel and apply this to the played instrument, then I
> would mix it.
Yes, that's basically what I do now: I flatten the song into a series of
play states where for each active channel I store the pointer to the
current sample, its frequency, volume and panning (none of these three
parameters change within a chunk), and use that information to perform
mixing. The mixing step is quite ad hoc, but at least it's simple
enough, so it doesn't get out of hand.

> It is the strength of Haskell to separate everything into
> logical steps and let laziness do things simultaneously. Stream fusion
> can eliminate interim lists, and final conversion to storable vector
> using http://hackage.haskell.org/package/storablevector-streamfusion/
> can eliminate lists at all.
But in my understanding that elimination is only possible if lists are
not used as persistent containers, only to mimic control structures. Now
I rely on samples being stored as lists, so I can represent looping
samples with infinite lists and not worry about the wrap-around at all.
So in order to have any chance for fusion I'd have to store samples as
vectors and wrap them in some kind of unfold mechanism to turn them into
lists that can be potentially fused away. In other words, besides a
'good consumer', I need a 'good producer' too.

However, there seems to be a conflict between the nature of mixing and
stream processing when it comes to efficiency. As it turns out, it's
more efficient to process channels one by one within a chunk instead of
producing samples one by one. It takes a lot less context switching to
first generate the output of channel 1, then generate channel 2 (and
simultaneously add it to the mix) and so on, than to mix sample 1 of all
channels, then sample 2 etc., since we can write much tighter loops when
we only deal with one channel at a time. On the other hand, stream
fusion is naturally fit to generate samples one by one. It looks like
the general solution requires a fusable transpose operation, otherwise
we're back to hand-coding the mixer. Have you found a satisfying
solution to this problem?


http://www.fastmail.fm - A no graphics, no pop-ups email service

More information about the Haskell-Cafe mailing list