Re: [linux-audio-dev] API design again [code]

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

Subject: Re: [linux-audio-dev] API design again [code]
From: Roger Larsson (roger.larsson_AT_skelleftea.mail.telia.com)
Date: to loka   07 1999 - 19:35:45 EDT


Paul Barton-Davis wrote:
>
> >Yes but the event is supposed to affect the current executing plugin
> >only (my interpretation) and can then be coded as:
> > selfHandleEvent(event); // could be inlined by the compiler,
> >// or at least it is a static call, no miss in jump prediction.
> > engineGetNextEvent(this, event); // Have not seen this
>
> I don't think this is correct. If the event is, say, a MIDI continuous
> controller value change, then many plugins may need to know about it
> (i.e. all plugin's that want to use the CC value for something).

Yes, but all operators could get it in their code.
Note: the engineGetNextEvent does not free the data structure nor the
plugin itself. Allocating an freeing should be the responsibility of
the main engine.

>
> >shouldn't we be able to process more than one event during one
> >buffer....
> >(or was the event a linked list)
>
> we'd better be able to ... otherwise, its a stupid design. so yes, i
> think you can assume that the `event' is some kind of linked list/null
> terminated array etc.
>

Not using a linked list is probably a little more flexible.
* The engine could then 'insert' events into the queue - probably not a
good
  idea, but anyway...
* Events that are to be hadled in multiple plugins needs to be copied in
a
  simple linked list model.

> >It also does simplify coding for FFT since you get the same size all
> >the time, you would probably need less memory to keep state from
> >previous. (Especially if the plugin can specify buffer size)
>
> This is a very valid concern. I was trying to find an example of where
> the varying frame count would cause problems - this is a good
> one. Anyone else have comments on FFT (or other algorithms) and the
> problems that variable frame counts might cause ?
>
> >It should be easy to write a compatibility plugin that calls plugins
> >without event handling. The reverse is not true...
> >

> > [previous version removed]
>
> Excellent example. The question remains: should this be the
> responsibility of the plugin or the engine ? Do you really want
> *every* plugin derived from non-event-based code to contain this kind
> of wrapper ? Doesn't it remove most of the benefits of the approach ?
>

If the engine in your model can handle the sending of events to ALL
non-event-based code. Then this compatibility plugin is equaly well
suited
to do the same for ALL non-event-based code :-)
[Ohh, that code was missing in my first suggestion, this is needed to be
to be able to use more than one instance of any plugin...]

But you would probably only need one compatibility plugin for each
type of non-event-based code.

// Pseudocode... rev. 2
// longer variable names => longer lines...

--- in API .h file ---
struct NewEngineInstanceData; // forward decl. of plugin instance data
struct NewEngineEventDescription {
 unsigned ... atSample;
 - - -
}
inline signed ... sampleDiff(unsigned ... a, unsigned ... b)
{
   return (signed ...)(a - b);
}

// and decalare <NewEngineProcessFuntionType> too
void engineGetNextEvent(NewEngineEventDescription **eventDesc);

--- in wrappers .c (or local .h) file ---
struct InstanceData {
 <PluginType>ProcessFunction *process;
 <PluginType>EventFunction *processEvent;
}

-- in <PluginType>Wrapper.c ---
static inline void processEvent(InstanceData *this, NewEngineEventData
*event) // but may need time...
(
  // translate needed data from event (and this)

  this->processEvent(<translated data>);
}

<NewEngineProcessFunctionType>
<PluginType>CompatibilityPlugin(InstanceData *this, ...,
NewEngineEventDescription *eventDesc) {
   unsigned ... fullFrame = this->fullFrame;
   unsigned ... startAtSample = this->lastSample;
   unsigned ... endAtSample = startAtSample + fullFrame;

   // following match the type this->process(...) wants
   unsigned ... currentSample = 0; // or signed, "small" value
   signed ... remainingSamples;

   while ( (remainingSamples = fullFrame - currentSample) > 0) { //
note: assignment
      // strongly taken [fullRange > 2]

      signed ... samplesAfterEvent = -1; // no events before endAtSample
      if (eventDesc != NULL) samplesAfterEvent = sampleDiff(endAtSample,
eventDesc->atSample); // strongly not taken

      ASSERT(samplesAfterEvent <= remainingSamples);

      if (samplesAfterEvent < 0) { // strongly taken [with few events]
         // no more events within frame
         this->process(this->data, ..., currentSample,
remainingSamples);
         currentSample += remainingSamples;

         ASSERT(currentSample == fullFrame);
      } else {
         signed ... processSamples = remainingSamples -
samplesAfterEvent;

         if (processSamples > 0) {

            this->process(this->data, ..., currentSample,
processSamples);
            currentSample += processSamples;

         }
            
         processEvent(this, eventDesc);
         engineGetNextEvent(this, &eventDesc) // the last event is not
processed
      }
         
   }

   ASSERT(remainingSamples == 0);

   this->lastSample = endAtSample;

}

--- in wrappers .c (or local .h) file ---

struct InstanceData {
   ... param;
}

-- in <PluginType>.c ---
static inline void processEvent(InstanceData *this, NewEngineEventData
*event)
(
  this->param[event->attrib] = event->value; // todo: naive...
}

<NewEngineProcessFunctionType>
<PluginType>Plugin(InstanceData *this, ..., NewEngineEventDescription
*eventDesc) {
   unsigned remainingSamples = this->fullFrame;

   while (remainingSamples) {

      signed ... samplesAfterEvent = -1; // no events before endAtSample
      if (eventDesc != NULL) samplesAfterEvent = sampleDiff(endAtSample,
eventDesc->atSample); // strongly not taken

      ASSERT(samplesAfterEvent <= remainingSamples);

      while (remainingSamples > samplesAfterEvent) {
        // process sample here, inline
        remainingSamples--; // note: can't be in while since there might
be several events at the same time
      }

      if (remainingSamples > 0) {
         processEvent(this, eventDesc->data);
         engineGetNextEvent(this, &eventDesc);
      }
   }

Starts to look like real code...
I guess I have to take another look at Davids API and try to merge...
[where is it]

/RogerL

-- 

The Internet interprets Windows as damage, and routes around it.

Roger Larsson Skellefteċ Sweden


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

This archive was generated by hypermail 2b28 : pe maalis 10 2000 - 07:27:13 EST