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
This archive was generated by hypermail 2b28 : pe maalis 10 2000 - 07:27:13 EST