Subject: [linux-audio-dev] Re: Quasimodo (Was: Re: LADSPA GUI)
From: Paul Barton-Davis (pbd_AT_Op.Net)
Date: la maalis 11 2000 - 16:36:17 EST
heh. where to start ? lets start with the fun stuff ..
>imagine making the conditionals, multiplies, etc. that are inside the
>script explicit opcodes.
Welcome to the world of Csound (and thus Quasimodo). Everything you
saw in the script for the mixer is implemented via an opcode. Every
multiply, every assignment, every if, etc.
>the obvious thing to worry about here would be that the host is
>spending all it's instruction cycles jumping in and out of one line
>plugins. my thought is that a reasonably intelligent host can
>optimize this away. imagine the network of plugins as equivalent to
>the intermediate representation in some modern, multi-target
>compiler. there are a million temporary variables floating around,
>everything looks very inefficient etc. however, because the IR code
>is the lowest common denominator, the code generation phase can
>easily tile over sets of operations with effecient, platform specific
>implementations yielding pretty optimal solutions. if code is
>trapped inside modules then you may never realize you're performing
>duplicate computations which could be coalesced.
Can I say "been there, done that" ? :) There is a really hairy chunk
of code in the heart of Quasimodo that is a compiler. Not just "sort
of a compiler", but a real compiler. Its not a very good one, but
everything it does is expressed in source code terms that refer to
compiler technology. I had the dragon book by my side for quite a
while as I was working on that :)
I took a few liberties with the everything-is-an-opcode model: in the
interest of efficiency: an opcode can be declared as "inline", in
which case we jump into a switch block, and execute the right code
inline, no function calls. Even so, everything else about the `*' or
the `if' is handled as if it were an opcode.
That said, the Quasimodo "compiler" could benefit from many other
modern compiler optimizations. In particular, automatic recognition of
expressions that can be more efficiently executed when
rearranged. Here is the most common example:
a = b * c * d * e;
This would normally translate into 3 intermediate values, 3 mult
opcode calls and one assignment.
If you happen to have an instruction/opcode around that can execute a
4 way multiply, this is better written as:
a = mmult (b, c, d, e)
This is one mult opcode call, one assignment and no
intermediates. *Much* faster.
In "machine code" (which is how it ends up):
push e ; push args
push d
push c
push b
push 4 ; num of arguments
call mmult ; opcode instruction
pop a ; put result in a
Quasimodo has opcodes like mmult (inlined), but its compiler can't use
them them automatically when the module writer forget to.
>a mixer channel is just the multiplication of some controll signals
>with an audio signal. the variables become implicit (captured by the
>interconnections). this makes things like unpackaging / repackaging
>very easy. you can package up a fader for a single channel then let
>someone else repackage them into an 8 channel mixer without ever
>having to look at code.
Precisely. The only reason this is not done in Quasimodo right now is
that the Csound language that it uses does not support the semantic
constructs to allow it. As I have pointed out several times on the
Csound list and occasionally here, I am continually on the look out
for a better language to use, or use as inspiration.
>so i think this gets close. what happens if i want an 8 channel
>mixer ? it looks like you probably go in and duplicate the code for
>each channel fader as many times as needed. but, you've got to
>invent a bunch of new variable names etc. what you really want is a
>nice clean way to nest modules without duplicating code.
e.g:
declare mixer (int nchannels, int nbusses)
{
.
.
.
}
mixer (24, 8);
Its something like this that I want for the new language. I can
implement it pretty easily, but I haven't found the right language
model yet.
>how effecient can the scripting be ? it's probably powerfull enough
>to implement something like a convolution but would it ever be fast
>enough ? how do you decide what should be an opcode and what should
>be done with the script ?
Csound is a "magnificent" example of this. What frequently happens is
that a Csound guru (e.g. Hans Mikelson, Gabriel Maldonado) will
initially implement something as a Csound "script". He will tune it
and play with using the interpreted language. If it turns out to be
useful, they typically recode it as an opcode. There is a lot of stuff
that the script can run in real time, but once you get into serious
math, its normally better to switch to the opcode
implementation. Han's version of the Moog filter, for example, evolved
this way.
>it strikes me as advantageous to give the backend a nice flatened
>representation to work with rather than nested modules mixed in with
>a bunch of script to interpret.
no, the script still has to be interpreted even in the scenario you
are suggesting. a textual list of plugins is not something anything
can execute - something has to take that list and convert it into some
kind of representation that can be used by the host. I don't think
that a textual form that is just a list is very helpful - people
already complain that Csound is too close to assembler (a very quirky
assembler too!), and what you're suggesting seems even closer to
me. Besides, how would you write a conditional as a "flat" structure ?
Typically the representation you end up with a is linked list of some
kind; Quasimodo ends up with a linked list of modules which consist of
linked lists of function pointers.
My plan, when and if we get LADSPA worked out, is to make this
representation into a linked list of plugins which contain linked
lists of plugins. Both modules and opcodes will be handled as plugins.
--p
This archive was generated by hypermail 2b28 : su maalis 12 2000 - 09:14:06 EST