Re: [linux-audio-dev] Re: Plug-in API progress?

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

Subject: Re: [linux-audio-dev] Re: Plug-in API progress?
From: Benno Senoner (sbenno_AT_gardena.net)
Date: ma syys   27 1999 - 09:05:46 EDT


On Sun, 26 Sep 1999, David Olofson wrote:
>
> An RTL driver can easily catch events and time them within 5 µs or so on an
> average Celeron box. The hardware can be more troublesome...

Yes, but audiality will run as a userspace process on most systems,
therefore we should include a solution optimized for that case:
ignore (do not generate/process) timestamps for realtime data,
like MIDI input.

>>
> > in short, you can't get sample accurate timestamping unless you reduce
> > the control cycle to 1, which we're agreed is a bad idea.
>
> Still don't agree. You can't get single sample latency without a single sample
> cycle, but you *can* timestamp events as precicely as the hardware and OS
> allows, and you *can* use that information to handle the events with a fixed,
> sample accurate delay.

I agree with David:
a MIDI/audio sequencer which generates timestamped events a few msecs ahead,
can provide sample accurate audio output.
The only effect of the scheduling jitter is that the output buffers get more or
less filled ( = no effect at all) , but the audio output will be 100% sample
accurate.
For realtime MIDI input we have to live with the scheduling jitter, but since
it is below/within the MIDI byte transfer time, we are better/as good as
hardware counterparts.
Therefore I'm not worried about this issue.

> > When someone tweaks a MIDI CC, I expect the effect to take place right
> > *now*. When someone twiddles an on-screen control element, I expect
> > the effect to take place right *now*. I don't see where a notion of
> > "when to do things" enters into the area of parameter updates.
>
> Automation. Live systems are obviously *very* different from studio systems...
> :-)
>

>> > (+) NOTE: this doesn't mean that the plugin can't contain conditional
> > code. But this is just handled with a parameter update. Consider a
> > plugin with a switch that toggles between two different choices. Right
> > now, the parameter that models the switch state is set to 1. Someone
> > clicks the GUI representation, and we decide to change it to a 2. No
> > problem: no timestamping needed - we just alter the parameter
> > asynchronously, and the plugin keeps running.
> >
> > process (MyClosureType *closure)
> > {
> >
> > while (samples_to_generate) {
> >
> > if (*closure->switch_state == 1) {
> > ... foo ...
> > } else {
> > ... bar ...
> > }
> > }
> >
> > }
> >
> > There - we just told the plugin to do something, and it did it. No
> > events, no timestamps. What am I missing ?
>
> 1) The engine will most likely block the GUI code on a single CPU
> machine, so you'll never recieve events in the middle of the
> process loop.

Agreed.

>
> 2) An any machine (UP or SMP), this plug-in may execute within a
> fraction of the time it takes to play the buffer it's changing.
> That is, the time at which the plug-in recieves the event, and
> acts upon it has a very unlinear relation to the buffer time.

Agreed.
>
> Besides, having the conditional code inside the inner loop isn't very nice from
> a code optimisation POV. Even if the jump predictor will be right most of the
> time on a modern CPU, it will fail two or three times in the start of a change,
> and that may be a significant ammount of pipeline flushes with a small buffer
> size. (A pipeline flush on a Pentium MMX, P-II/III or Celeron costs around 3
> instruction cycles IIRC...)
>
> And if you have more switches, you get more trouble... For such situations, you
> would be better off using a function pointer that you change when you recieve an
> event, or a swith() with an ordered list of cases, as that gets optimized into
> a jump table. (And if the CPU and/or compiler is smart, there are no pipeline
> flushes on jump tables, as other instructions can be executed while the jump
> address is being calculated.)

Yes, all this overhead for only reaching a bit better realtime response ?
No thanks.
I *STRONGLY* dislike conditionals in the innermost loop,
plus the unlinear relation to the buffer time makes this almost worthless to me.
Not to mention weird things like plugin-B getting the new parameter change,
while plugin-A was already processed and generated data with the old parameter
settings
= unwanted "analog feel" ??
:-)

With David's event approach, not only you get almost all the time the same
performance as with non-sample accurate processing (per-fragment parameter
changes), since the parameter density most of the time is much lower than
the fragment cycle-frequency,
but things will stay perfectly in sync, since all plugins get the events at the
right time, regardless of the order of processing.

the sample accurate event positioning, adds only a conditional buffer-split at
the begin of the fragment processing, like David described.

event_time=event.time; (in samples)
samples_before_event=actual_time-event_time;
rest_samples=samples_per_buffer=samples_before_event;
while(--samples_before_event)
{
  process_sample()
}
process the event (change parameters etc)
while(--rest_samples)
{
  process_sample();
}

as you see , just setting samples_before_event=0, just quantizes
events to fragment boundaries.
The overhead of the first while is very low, compared to Paul's
"event-happened" checking at the innermost loop.
Of the above example doesn't cover the "more than 1 event per fragment" case
but it's almost trivial to implement, without adding much overhead.
(can be implemented by wrapping the above code fragment around a
while(--num_events_in_this_fragment) { ... } or so)
Right David ?
I too, was sceptical about the sample accurate event system but I'm
now almost 100% convinced, since it doesn't seem to have conceptual
design flaws to me.
Of course the sample accurate event processing will slow down very much,
if you send a huge number of events per fragment, but that's another story,
and we assume that it will not happen in real world.
For oscillator modulations we will use low frequency wavetables, instead
of sending myriads of events, stressing the David's poor memory management
system.
:-)

> I think Quasimodo's system makes a lot of sense, especially for pure low
> latency real time applications. There's no way my system will beat it WRT
> performance in that kind of situations.

Agreed, the goal is to make a framework which is flexible *AND* doesn't add
much overhead compared to Quasimodo.

>
> My goal is to design and implement a system that can cover the whole range
> from ultra low latency real time to off-line processing - without ending up as
> something that doesn't do anything too well... (Simple, eh? ;-) The low overhead
> system of Quasimodo is very inspiring when trying to turn an inherently complex
> design into something nice, efficient and useful. Remains to see what all this
> results in...

To me the event overhead seems not too heavy compared to other processing
tasks you have to do when doing DSP stuff in software.

regards,
Benno.


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:12 EST