[chuck-dev] Block execution of ugens?

Robin Davies rerdavies at rogers.com
Thu Sep 1 01:25:05 EDT 2005


ok.. I've been happily hacking away at Chuck 1.2.0.0 sources, with good
results so far. I have a set of band-limited oscillaters: currently,
bltsawosc, bltsqrosc, and blitosc (impulse train), based on "Alias-Free
Digital Synthesis of Classic Analog WaveForms", Stilson/Smith. Also,
buzzosc -- a band-limited DSF, similar to SAOL and CSound buzz. All are
ready and waiting for access to the load function. I'll probably drop in a
bltrectosc (with a width control), soon, as well.

(You can have them now, if you like -- a .cpp and .h file, with a query
function to register the ugens, all in the same style as current ugens; but
I'd like to do a little more testing if you do want it now).

Next on the slab: VSTs. And there, things didn't go so well.

The key issue is the VSTs like to operate on blocks of audio data rather
than running sample at a time. This isn't a huge problem with VST
instruments: fetching data in small blocks (say 30 or 40 samples at a time)
introduces a small (< 1ms) disconnect between controls and generated audio.
But buffering input and output of effects probably isn't going to work as
well. I'm really not confident that delaying audio effect output isn't going
to produce odd side-effects.

I supposed it is possible to try running VSTs one sample at a time. I may
give this a try, anyway, in the meantime. But, having written a few VSTs, I
don't think I'd be happy if somebody called my VSTs one sample at a time.

This probably isn't a priority for you guys right now, but I'd like to raise
the idea anyway.

What do you think about converting Chuck_VM::run( ) to execute Ugens on
blocks of samples at a time? As far as I can see, it's do-able. And the
across-the-board performance gains would probably be worth the effort.

Roughly, I think the revised code would look like this:

#define MAX_UGEN_BLOCKSIZE 32  // or so
    while( m_running )
        run shreds for 1 tick
        broadcast queued events
        determine how many ticks we can run ugens for:
        int ugenBlockSize;
        if (shreds active) {
            ugenblocksize = 1;
        } else {
            ugenblocksize = min(MAX_UGEN_BLOCKSIZE,ticks_to_next_shred())
        }
        Run_ugens(ugenblocksize);
        process messages
   }

Ugens would be modified to have input and output buffers of
SAMPLE[MAX_UGEN_BLOCKSIZE). Existing UGens would inherit a method that
converts Ugen block ticks into single-cycle ticks.

The only breaking change I can see is Ugens that are chucked into loops,
which is, I think, legal in the current implementation, but would work with
buffered input. I seem to remember seeing a mention of this somewhere in the
docs.

I imagine this might significantly complicate the implementation of ugens
written in chuck, too. I'm not sure that I have any decent theories as to
how that one would be tackled. (Separate schreduling queues for UGEN tick
methods, maybe?)

I'm willing to take a crack at an experimental version some time, but I
don't imagine your sources are too stable right now. I'd be a bit concerned
about making this kind of wide-ranging change on a very active source tree,
with no prospect of ever being able to merge it back into mainline sources.

Thoughts?








More information about the chuck-dev mailing list