[linux-audio-dev] XAP: Cookies and Event Actions

New Message Reply About this list Date view Thread view Subject view Author view Other groups

Subject: [linux-audio-dev] XAP: Cookies and Event Actions
From: David Olofson (david_AT_olofson.net)
Date: Sat Jan 18 2003 - 05:00:50 EET


While hacking a more uniform control event type into Audiality, I
realized something: The event action *might* be better off as a part
of the cookie.

The voice mixers in Audiality have two types of controls; ramped
controls and controls without ramping. As it is, they're implemented
in different ways, use different arrays, different events and
different event handling code. You use SET for the non-ramped
controls, and ISET, IRAMP and ISTOP for the ramped controls. Same
index means one control for SET, and another for ISET.

Fine; no problem with that so far, since the Patch Plugins (that
drive the voices, implementing mono/poly, envelopes and whatnot) have
intimate knowledge of the voice controls. Everything's hardcoded,
basically.

However, when applied to "real" plugins, this scheme has a problem:
There are two kinds of controls, and they're not compatible in any
way. If you have ramped output, you need a ramped input, and vice
versa.

Now, the idea I had was to drop the event action/type field, and have
receivers encode that part as well, into the cookie. That way, if you
don't have ramping for some controls, you can just encode a different
action field into your cookies, so that when you get those events,
you end up in a different case in the decoding switch(), where you
"fake" the response in a suitable way. Taking some Audiality code as
an example:

        switch(ev->type)
        {
          case VE_START:
                voice_start(v, ev->arg1);
                ...
                break;
          case VE_STOP:
                voice_kill(v);
                aev_free(ev);
                return; /* Back in the voice pool! --> */
          case VE_SET:
                v->c[ev->index] = ev->arg1;
                if(VC_PITCH == ev->index)
                        v->step = calc_step(v);
                break;
          case VE_ISET:
                v->ic[ev->index].v = ev->arg1 << RAMP_BITS;
                v->ic[ev->index].dv = 0;
                break;
          case VE_IRAMP:
                v->ic[ev->index].dv = ev->arg1 << RAMP_BITS;
                v->ic[ev->index].dv -= v->ic[ev->index].v;
                v->ic[ev->index].dv /= ev->arg2;
                break;
          case VE_ISTOP:
                v->ic[ev->index].dv = 0;
                break;
        }

(which requires senders to special-case normal and ramped controls)
becomes:

        switch(ev->cookie & 0xf)
        {
          case VE_START:
                voice_start(v, ev->arg1);
                ...
                break;
          case VE_STOP:
                voice_kill(v);
                aev_free(ev);
                return; /* Back in the voice pool! --> */
          case VE_SET:
                v->c[ev->index] = ev->arg1;
                break;
          case VE_SET_PITCH:
                v->step = calc_step(v);
                v->c[ev->index] = ev->arg1;
                break;
          case VE_RAMP:
                v->c[ev->index] = ev->arg1 << RAMP_BITS;
          case VE_STOP:
                break;
          case VE_ISET:
                v->ic[ev->index].v = ev->arg1 << RAMP_BITS;
                v->ic[ev->index].dv = 0;
                break;
          case VE_IRAMP:
                v->ic[ev->index].dv = ev->arg1 << RAMP_BITS;
                v->ic[ev->index].dv -= v->ic[ev->index].v;
                v->ic[ev->index].dv /= ev->arg2;
                break;
          case VE_ISTOP:
                v->ic[ev->index].dv = 0;
                break;
        }

Notice the new VE_RAMP and VE_STOP actions? Those are where ramping
events go if you send them to a non-ramped control. Also note that
VE_SET_PITCH no longer needs an extra conditional to run (the rather
expensive) calc_step() for the pitch control.

Just encode whatever action you want into the cookie for each control
connected. A full control target now looks like this:

struct AEV_target
{
        AEV_queue *queue;
        Uint32 set_cookie;
        Uint32 ramp_cookie;
        Uint32 stop_cookie;
} AEV_target;

One cookie for each type of action there is for a control. This way,
you can encode *all* aspects of control handling into the cookie,
without adding any significant complexity or overhead to senders. You
could have only one set of control event handlers, or you could have
one set of cases for *each control*! You decide.

I'm definitely switching to this system internally in Audiality.

(And if it's a bad idea, you'll find out...! :-)

(Note that STOP is just to deal with the limited accuracy of the
integer math in Audiality - and that might actually have been a
"false fix" for another bug I found later. Will try without STOP
again, and/or tweak the ramping code. Or just ditch the bl**dy
integer code! :-)

//David Olofson - Programmer, Composer, Open Source Advocate

.- The Return of Audiality! --------------------------------.
| Free/Open Source Audio Engine for use in Games or Studio. |
| RT and off-line synth. Scripting. Sample accurate timing. |
`---------------------------> http://olofson.net/audiality -'
   --- http://olofson.net --- http://www.reologica.se ---


New Message Reply About this list Date view Thread view Subject view Author view Other groups

This archive was generated by hypermail 2b28 : Sat Jan 18 2003 - 05:00:35 EET