[LAD] Conciderations of Design

David Olofson david at olofson.net
Fri Nov 11 23:42:35 UTC 2011


On Friday 11 November 2011, at 23.19.44, harryhaaren at gmail.com wrote:
> Hi All,
> 
> Recent thoughts of mine include changing the "direction" of operations in
> real-time program design:
> Eg: Don't call a set() on a Filter class to tell it its cutoff, every time
> there's a change,
> but make it ask a State class what its cutoff should be every time it runs.

There are issues with both methods, depending on what you want to do.

Function calls add overhead that can become significant if you're doing very 
frequent parameter changes.

Polling, as I understand the latter approach to be, might be a great idea if 
you're only reading the parameter once per "block" of processing. You'll need 
to get that number from *somewhere* no matter what; be it a private closure, 
or some more public structure. However, if there are expensive calculations 
between that parameter and what you actually need inside the DSP loop, it 
might not be all that great. Things get even worse if you want to handle 
parameter changes with sample accurate timing. (Function calls can handle that 
just fine; just add a timestamp argument, and have plugins/units handle that 
internally in whatever way is appropriate.)

Some sort of event queues can offer some of the advantages of both of these, 
if designed properly. If they're delivered in timestamp order (either by 
system design or by means of priority queues or similar), processing them 
becomes very efficient and scalable the large numbers of "control targets"; 
you only have to check the timestamp of the next event, then process audio 
until you get there, and you only ever consider changes that actually occured 
- no polling.

All that said, how far do you need to take it? Unless you're going to throw 
tens of thousands of parameter changes at your units while processing, this 
overhead may not be as significant as one might think at first. It might be a 
better idea to focus on features and interfaces first. Remember, premature 
optimization is the root of all evil... :-)


> Along the same lines, say I have a single linked list of AudioElements, and
> the 3rd element needs info, should
> it request it, be told it, or have some other system to inform it of
> events?

I tend to go with "connection" logic and some sort of direct references when 
designing that sort of things - but again, that depends on the application and 
usage patterns you're designing for.

For example, in a physics engine (game or simulation), you have potentially 
hundreds or even thousands of bodies moving around, and you have to rely on 
spatial partitioning of some sort to figure out which bodies *can* potentially 
collide within the time frame currently being evaluated. In a naïve design, 
you essentially have to check every body against every other body, every 
single frame, and that... doesn't scale very well at all. :-)

As a more relevant (I think) extreme in the other direction, we have musical 
synthesis systems: Hundreds or even thousands of units processing audio in 
various ways (I'm thinking modular synthesis here, obviously - no way any sane 
person would use that many units otherwise... I think ;-) - but you won't 
normally see random communication between arbitrary units! What you will 
normally have is a number of (relatively) long "conversations" between units, 
usually best abstracted as some sort of persistent connections. Obviously, 
this saves a lot of time, as there is no overhead for looking units up, except 
possibly when making new connections. (Probably no need for that if you wire 
things as you build the graph.)


> I'm seeing downsides to each approach:
> 1: Tell it on every change -> performance hit

How are you going to avoid that anyway? Even if you do want to filter high 
frequency control data down, you'll need to deal with all data there is, or 
risk "random" behavior due to aliasing distortion. (Like downsampling audio 
without filtering or interpolation.)

Or, if you're going to use a lot of potentially high frequency control data, 
why not use audio rate control ports? Or some sort of hybrid, allowing you to 
switch as needed - but that quickly becomes a complexity explosion...


> 2: Request it every time it runs -> Keeping control over the many values &
> unique ID's of class instances

Well, if designed properly, this should scale with the graph. Basically, each 
connectable entity should only ever need to know what it's connected to - if 
even that. (See LADSPA ports.) Also, keeping such connection state data along 
with the state data of units might be a good idea performance wise, as it can 
make memory access more cache friendly.

But of course, the ultimate answer to all such questions is: Benchmarking! 
Though having a rough idea about how modern hardware works can help getting 
the initial design reasonably non-broken.


-- 
//David Olofson - Consultant, Developer, Artist, Open Source Advocate

.--- Games, examples, libraries, scripting, sound, music, graphics ---.
|   http://consulting.olofson.net          http://olofsonarcade.com   |
'---------------------------------------------------------------------'



More information about the Linux-audio-dev mailing list