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

2009-12-24 Thread Vladimir Zlatanov
 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?

I wonder if data-parallel haskell won't be able to help here, mod
rendering is a
scatter-gather style of processing, the problem is that the different channels
trigger different processing.
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-23 Thread Patai Gergely
 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?

Gergely

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

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-23 Thread Henning Thielemann
Patai Gergely schrieb:

 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.

Right. The conversion from storablevector to stream-fusion:Stream is
such a good producer.

 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.

Yes, I would also do it this way. So in the end you will have some
storablevectors as intermediate data structures.

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-22 Thread Henning Thielemann
Patai Gergely schrieb:
 I would do resampling (with some of the Interpolation routines) and
 mixing in two steps, that is I would prepare (lazy) storable vectors
 with the resampled sounds and mix them.

 And is that straightforward considering the peculiarities of tracked
 music? After all, frequency can change between ticks thanks to
 portamento effects, and samples can loop or end in the middle of a tick.
 Do I have to trim and pad the samples manually to be able to describe
 these transformations?

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. 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.
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-20 Thread Patai Gergely
Hello all,

I did some refactoring, and separated the device independent part of
Hemkay into a package of its own, hemkay-core [1]. This is a library
that provides facilities to load MOD music and render it in various
ways, including a direct-to-buffer option that's considerably more
efficient than creating a list of samples. You can use it to create a
MOD player with any sound-making API or even write the mixer output into
a wav file.

The hemkay package [2] is now reduced to an example that shows how to
use the core library with PortAudio. It is also considerably faster than
the previous version, because now I push as many samples as possible at
a time without blocking. I had no luck with Mietek's callback interface
so far, because it keeps randomly segfaulting on me, but when it works,
it's about four times as fast as the current player. You are encouraged
to try adapting it (using mixToBuffer) to other systems.

Gergely

[1] http://hackage.haskell.org/package/hemkay-core
[2] http://hackage.haskell.org/package/hemkay

-- 
http://www.fastmail.fm - Choose from over 50 domains or use your own

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-18 Thread Henning Thielemann
Patai Gergely schrieb:

 I have a function for mixing sounds at different (relative) start times.
 I feel that it does not get maximum speed in GHC, but is still ready for 
 realtime application.

 http://hackage.haskell.org/packages/archive/synthesizer-core/0.2.1/doc/html/Synthesizer-Storable-Cut.html#v%3Aarrange
 And how can you mix that with changing frequencies (effectively
 resampling on the fly)?

I would do resampling (with some of the Interpolation routines) and
mixing in two steps, that is I would prepare (lazy) storable vectors
with the resampled sounds and mix them. Since Haskell is lazy, this is
still somehow on the fly, although one could still wish to eliminate
the interim storable vectors.
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-18 Thread Vladimir Zlatanov
 I would do resampling (with some of the Interpolation routines) and
 mixing in two steps, that is I would prepare (lazy) storable vectors
 with the resampled sounds and mix them. Since Haskell is lazy, this is
 still somehow on the fly, although one could still wish to eliminate
 the interim storable vectors.

You could use stream fusion, although you will need to adapt that for
the interpolation, but it should work.
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-18 Thread Patai Gergely
 I would do resampling (with some of the Interpolation routines) and
 mixing in two steps, that is I would prepare (lazy) storable vectors
 with the resampled sounds and mix them.
And is that straightforward considering the peculiarities of tracked
music? After all, frequency can change between ticks thanks to
portamento effects, and samples can loop or end in the middle of a tick.
Do I have to trim and pad the samples manually to be able to describe
these transformations?

-- 
http://www.fastmail.fm - The way an email service should be

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-17 Thread Patai Gergely
Hello again,

 Your message has motivated me to publish my own PortAudio binding,
 which provides a simpler, more efficient callback-based interface:
 http://github.com/mietek/portaudio
I tried this, and after rewriting the code a bit, I managed to decrease
CPU load by 70-80%, which is not bad for starters. However, I'm getting
random segfaults, and I've no idea why.

Here's the modified player module (hpaste kindly rearranged the empty
lines for some reason):

http://hpaste.org/fastcgi/hpaste.fcgi/view?id=14347

Instead of building a list of samples right away, I use an unfoldr-style
generator to fill the buffer, whose initial state is created by
mixGenerator, and its stepper function is nextSample.

In order to get this working, I renamed your module to avoid conflict
with the other PortAudio binding, and I had to change the dependencies
in the cabal file to base = 4   5 because of the exception handling
code.

There's also some broken MVar-based code to handle the end of the song,
you can ignore that for the time being.

Gergely

-- 
http://www.fastmail.fm - The professional email service

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-17 Thread Henning Thielemann


On Mon, 14 Dec 2009, Patai Gergely wrote:


Hello all,

I just uploaded the fruit of a little side project. Hemkay [1] is an
oldschool module music [2] player that performs all the hard work in
Haskell.


Cool.
 The most complicated I tried was to import OctaMED printout to Haskore:
  http://darcs.haskell.org/haskore/src/Haskore/Interface/MED/Text.hs
  
http://hackage.haskell.org/packages/archive/haskore/0.1/doc/html/Haskore-Interface-MED-Text.html


Still, I'd be curious to see how the overall quality of the code could
be improved. In particular, retrieving and updating record fields is
somewhat inconvenient. Also, the actual mixing (limited to the mixChunk
function) is embarrassingly slow, and I wonder how much it could be
improved without leaving the pure world.


I have a function for mixing sounds at different (relative) start times. I 
feel that it does not get maximum speed in GHC, but is still ready for 
realtime application.

  
http://hackage.haskell.org/packages/archive/synthesizer-core/0.2.1/doc/html/Synthesizer-Storable-Cut.html#v%3Aarrange
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-17 Thread Patai Gergely
   The most complicated I tried was to import OctaMED printout to Haskore:
http://darcs.haskell.org/haskore/src/Haskore/Interface/MED/Text.hs

 http://hackage.haskell.org/packages/archive/haskore/0.1/doc/html/Haskore-Interface-MED-Text.html
Oh, I'll have to try that too!

 I have a function for mixing sounds at different (relative) start times.
 I feel that it does not get maximum speed in GHC, but is still ready for 
 realtime application.

 http://hackage.haskell.org/packages/archive/synthesizer-core/0.2.1/doc/html/Synthesizer-Storable-Cut.html#v%3Aarrange
And how can you mix that with changing frequencies (effectively
resampling on the fly)?

By the way, the latest code I have in my hands typically uses 2-3% CPU
time on my machine (Core 2 Duo at 2 GHz), which is okay for now, but I
think going at least ten times as fast is a realistic goal.

Gergely

-- 
http://www.fastmail.fm - Accessible with your email software
  or over the web

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-15 Thread Patai Gergely
 Patai, I asked a similar question about a week ago, inquiring about
 efficient buffers for audio. I got a good response:
 
 http://thread.gmane.org/gmane.comp.lang.haskell.cafe/67258/focus=67293
Well, the general lesson seems to be that using stream fusion or
something analogous is the way to go. In this particular case I don't
need any fancy processing, and I have no feedback loops. All I do in my
mixing routine is to calculate a weighted (volume+panning) sum of
samples and stretch them in time as dictated by their frequency. The
song is flattened into a series of play states first, so all the
information required for mixing is readily available.

I could try rewriting the mixer to return an iterative generator
function instead, which could be passed to an appropriate sound
interface. The latter would have to be written once and for all.

Gergely

-- 
http://www.fastmail.fm - Does exactly what it says on the tin

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-15 Thread Mietek Bąk
Hi Patai,

Your message has motivated me to publish my own PortAudio binding,
which provides a simpler, more efficient callback-based interface:
http://github.com/mietek/portaudio

The documentation is incomplete, but along with the example program,
it should be enough to get you going:
http://github.com/mietek/portaudio/blob/master/examples/Play.hs

Best regards,

-- 
Mietek Bąk
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-15 Thread Patai Gergely
 The documentation is incomplete, but along with the example program,
 it should be enough to get you going:
 http://github.com/mietek/portaudio/blob/master/examples/Play.hs
Yes, it looks like something worth giving a go. I'll try it soon,
thanks.

Gergely

-- 
http://www.fastmail.fm - The way an email service should be

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-14 Thread Patai Gergely
Hello all,

I just uploaded the fruit of a little side project. Hemkay [1] is an
oldschool module music [2] player that performs all the hard work in
Haskell. If there was any goal, it was to express the transformation
from the song structure to the output of the mixer as a series of
function compositions, maintaining a style that one might call idiomatic
Haskell. Considering the dirtiness of the format in question, I'm quite
pleased with the initial version.

Still, I'd be curious to see how the overall quality of the code could
be improved. In particular, retrieving and updating record fields is
somewhat inconvenient. Also, the actual mixing (limited to the mixChunk
function) is embarrassingly slow, and I wonder how much it could be
improved without leaving the pure world.

The program uses Portaudio for playback, but that might easily change in
the future. The problem is that I couldn't get sound to work smoothly
when producing samples in batches, so I'm sending them off one by one
(!) at the moment, which doesn't help with performance either. I'm open
to suggestions as to what library to use to push data to the sound card.

Gergely

[1] http://hackage.haskell.org/package/hemkay
[2] http://en.wikipedia.org/wiki/MOD_(file_format)

-- 
http://www.fastmail.fm - Or how I learned to stop worrying and
  love email again

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-14 Thread Peter Verswyvelen
Nice work!

Did you try the OpenAL binding? Not sure if that works.


2009/12/14 Patai Gergely patai_gerg...@fastmail.fm:
 Hello all,

 I just uploaded the fruit of a little side project. Hemkay [1] is an
 oldschool module music [2] player that performs all the hard work in
 Haskell. If there was any goal, it was to express the transformation
 from the song structure to the output of the mixer as a series of
 function compositions, maintaining a style that one might call idiomatic
 Haskell. Considering the dirtiness of the format in question, I'm quite
 pleased with the initial version.

 Still, I'd be curious to see how the overall quality of the code could
 be improved. In particular, retrieving and updating record fields is
 somewhat inconvenient. Also, the actual mixing (limited to the mixChunk
 function) is embarrassingly slow, and I wonder how much it could be
 improved without leaving the pure world.

 The program uses Portaudio for playback, but that might easily change in
 the future. The problem is that I couldn't get sound to work smoothly
 when producing samples in batches, so I'm sending them off one by one
 (!) at the moment, which doesn't help with performance either. I'm open
 to suggestions as to what library to use to push data to the sound card.

 Gergely

 [1] http://hackage.haskell.org/package/hemkay
 [2] http://en.wikipedia.org/wiki/MOD_(file_format)

 --
 http://www.fastmail.fm - Or how I learned to stop worrying and
                          love email again

 ___
 Haskell-Cafe mailing list
 Haskell-Cafe@haskell.org
 http://www.haskell.org/mailman/listinfo/haskell-cafe

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-14 Thread Patai Gergely
 Nice work!
Thanks! :)

 Did you try the OpenAL binding? Not sure if that works.
No, I haven't really looked hard, to be honest. Portaudio looked simple
enough, so I picked it. But it could be anything, since the mixing is
done on my side anyway, and all I need is a way to push (preferably
Float) samples to the sound unit. I'm sure there are several viable
options, so the deciding factor is rather portability, and secondly ease
of use.

-- 
http://www.fastmail.fm - The professional email service

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-14 Thread Patai Gergely
 The more of these I see, the more guilt I feel over the condition of the
 portaudio module. There's a good chance that the performance issue you're
 seeing is a bad implementation of the portaudio library. Do you have any
 specific problems you ran into with portaudio? I'd love to revisit at
 some point...
Well, when I tried to push whole blocks instead of individual samples,
it seemed to miss some of these writes. It might do the same even now,
but it wouldn't be noticeable with a sample missing here and there
anyway.

The interface for writeStream is not very fortunate. It forces me to
pack samples into lists no matter what, even if the interleaved list is
actually easier to produce. So it should probably provide alternative
interfaces for interleaved lists (which would actually be possible right
away if writeStream didn't ignore its third argument altogether), and
maybe an array interface as well. I don't know if the callback interface
works better, maybe that's also worth a shot.

Ultimately, it would be probably best if it gave the programmer a higher
abstraction, where it is passed a potentially infinite list of samples,
and takes care of all the buffering duties. Also, this could be made to
play nice with stream fusion in order to get the maximum performance out
of it.

Gergely

-- 
http://www.fastmail.fm - One of many happy users:
  http://www.fastmail.fm/docs/quotes.html

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-14 Thread John Van Enk
It's been well over a year. I'll see what I can do when I get some free(er)
time.

2009/12/14 Patai Gergely patai_gerg...@fastmail.fm

  The more of these I see, the more guilt I feel over the condition of the
  portaudio module. There's a good chance that the performance issue you're
  seeing is a bad implementation of the portaudio library. Do you have any
  specific problems you ran into with portaudio? I'd love to revisit at
  some point...
 Well, when I tried to push whole blocks instead of individual samples,
 it seemed to miss some of these writes. It might do the same even now,
 but it wouldn't be noticeable with a sample missing here and there
 anyway.

 The interface for writeStream is not very fortunate. It forces me to
 pack samples into lists no matter what, even if the interleaved list is
 actually easier to produce. So it should probably provide alternative
 interfaces for interleaved lists (which would actually be possible right
 away if writeStream didn't ignore its third argument altogether), and
 maybe an array interface as well. I don't know if the callback interface
 works better, maybe that's also worth a shot.

 Ultimately, it would be probably best if it gave the programmer a higher
 abstraction, where it is passed a potentially infinite list of samples,
 and takes care of all the buffering duties. Also, this could be made to
 play nice with stream fusion in order to get the maximum performance out
 of it.

 Gergely

 --
 http://www.fastmail.fm - One of many happy users:
  http://www.fastmail.fm/docs/quotes.html

 ___
 Haskell-Cafe mailing list
 Haskell-Cafe@haskell.org
 http://www.haskell.org/mailman/listinfo/haskell-cafe

___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


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

2009-12-14 Thread M Xyz


--- On Mon, 12/14/09, M Xyz functionallyharmoni...@yahoo.com wrote:

From: M Xyz functionallyharmoni...@yahoo.com
Subject: Re: [Haskell-cafe] ANN: Hemkay, the 100% Haskell MOD player
To: Patai Gergely patai_gerg...@fastmail.fm
Date: Monday, December 14, 2009, 5:50 PM




--- On Mon, 12/14/09, Patai Gergely patai_gerg...@fastmail.fm wrote:
Also, the actual mixing (limited to the mixChunk
function) is embarrassingly slow, and I wonder how much it could be
improved without leaving the pure world.

The program uses Portaudio for playback...

Patai, I asked a similar question about a week ago, inquiring about efficient 
buffers
for audio. I got a good response:

http://thread.gmane.org/gmane.comp.lang.haskell.cafe/67258/focus=67293

Working with immutable trees instead of arrays still freaks me out, but page 
289 of RWH
actually made me feel a little better about it. :)



  


  ___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe