I've been using the CCA package with good results so far.  Several people
(including myself) appear to have tried performing the CCA transformations
with a GADT rather than Template Haskell, without much success.  Although
the code is transformed to normal form, performance isn't good.  I suspect
that the transformations must be done in a pre-compilation stage in order to
present the normal form to GHC for the optimizer to produce the best
results.  In effect, this is similar to Henning's work with LLVM in that
both involve metaprogramming.

Currently, I've put together a small language that allows for constructions
like the following:

fir1 = 0.5*x + 0.5*x `z` 1
iir1 = 0.8*x + 0.2 * y `z` 1

fir2 = fir1 <.> fir1

filt1 = (0.1*iir1 + 0.9*fir2) + y `z` var 0

The compileArr function generates arrow code that is suitable for the ccap
preprocessor, then ccap's output is compiled.  The resulting core is optimal
so far as I can tell.  Best of all, since the result is just a function, you
can use it with nearly any sort of stream representation (lazy
bytestring-alikes, lists, iteratees).

I have a plan to make long delays efficient, but I haven't had a chance to
implement it yet as I've been working on another project.  Hopefully it'll
work out.

The other big problem is the name of the "z" function.  I would like to call
it "z-", but that's not an allowed name.  Unfortunately "-z" is allowed as
an operator name either.  So for now it's backwards for convenience.

Finally, in a blog post a while back sigfpe mentioned using comonads for
lazy audio.  I spent about 20 minutes on this and although the semantics are
nice, I couldn't figure out a way to get good performance for recursive
functions (iir filters etc.).  Has anyone else tried this?

John

On Tue, Jan 4, 2011 at 3:45 AM, Hudak, Paul <paul.hu...@yale.edu> wrote:

> (Since I don't read Haskell Cafe, I dropped it from the cc list.)
>
> I just wanted to mention that at Yale we are still working on CCA (causal
> commutative arrows) to get higher performance digital audio.  Although it
> may seem objectionable to use arrows at all, it has some key advantages.
>  For example, you can write recursive signals with no problem, and they will
> (theoretically) get optimized as well as straight-line code.
>
> Unfortunately, there are some major hurdles still in front of us.  We'd
> like to use an automated system like Template Haskell to do the
> optimizations for us, but it has some annoying limitations that have made it
> difficult to use in practice.  Furthermore, if you have structural recursion
> (for example a nested filter) then it needs to be unwound at compile time
> (perhaps using inlining).  Finally, it's not entirely clear how to handle
> things like delay lines and multiple clock rates.
>
> But the good news if that these problems can be solved, then every program
> can be optimized / normalized into a single loop with NO arrow combinators,
> which is then highly amenable to good code generation.
>
> Best,    -Paul Hudak
>
> Sent from my iPad
>
> On Jan 2, 2011, at 9:04 AM, "Henning Thielemann" <
> lemm...@henning-thielemann.de> wrote:
>
> >
> > On Sun, 2 Jan 2011, Stephen Tetley wrote:
> >
> >> I'm trying to make a Stream library, hopefully efficient enough for
> >> audio synthesis in the style of Jerzy Karczmarczuk's Clarion.
> >
> > I am trying to code real-time audio synthesis in Haskell for some years
> > now. I can tell at least, that it is not so easily done. Even with the
> > right data structure, GHC's optimizer does not always make, what you
> need.
> > Thus the most efficiency I get by using LLVM to construct signal
> > processing code at run time, so far. (see synthesizer-llvm package)
> >
> >> As performance is important, the obvious model is the Stream-Fusion
> >> library, but 'cons' is problematic in this style.
> >
> > Yes, 'cons' is problematic. I think efficient 'cons' needs a material
> data
> > structure, not just a generator function as in stream-fusion:Stream.
> >
> >> data Stream a = forall st. Stream !(st -> Step a st) !st
> >>
> >> For infinite Streams the Done constructor can be removed from the Step
> >> type, a truly infinite is never done:
> >
> > For audio synthesis you need also finite signals. Or am I missing
> > something?
> >
> > At least I found that the 'Skip' constructor can be omitted for audio
> > synthesis:
> >
> http://hackage.haskell.org/packages/archive/synthesizer-core/0.4.0.4/doc/html/Synthesizer-State-Signal.html
> >
> >
> >>> bad_loopy :: [Int]
> >>> bad_loopy = S.append1 (S.take 10 v) []
> >>>  where
> >>>    v = 1 `S.cons` v
> >
> > The problem is that S.cons must take the internal state type of 'v' and
> > must wrap it in a new type. Thus every S.cons makes the internal state
> > more complicated. This is inefficient for several applications of S.cons
> > and impossible for infinitely many calls.
> >
> >
> > In order to get both elegant laziness and efficiency I played around with
> > a head-strict list implemented via Storable. Here an efficient 'cons'
> > seems to be doable:
> >   http://code.haskell.org/storablevector/Data/StorableVector/Cursor.hs
> >
> > However if there remains only one bit of laziness in an inner loop, you
> > will not get good efficiency.
> > _______________________________________________
> > haskell-art mailing list
> > haskell-art@lurk.org
> > http://lists.lurk.org/mailman/listinfo/haskell-art
> _______________________________________________
> haskell-art mailing list
> haskell-art@lurk.org
> http://lists.lurk.org/mailman/listinfo/haskell-art
>
_______________________________________________
haskell-art mailing list
haskell-art@lurk.org
http://lists.lurk.org/mailman/listinfo/haskell-art

Reply via email to