I couldn't resist it so I hacked up a quick script to try the blockless,
dynamicly compiled processing we were discussing the other day.
http://plugin.org.uk/blockless/
just "make" if you want to test it
Its really hacky insomnia perl code, so dont look at it ;)
It works by defining graphs (.g), that are made up of atoms (C code) and
other graphs. The perl script turns it all into one giant lump of C and
builds it.
Graph files look like eg (pinknoise.g):
noise n(); // declares an instance n
zm1 d();
mix2to1 m();
gain half(0.5f);
n:out -> m:in1; // connect the 'out' port of n to the 'in' port of m
n:out -> d:in;
d:out -> m:in2;
m:out -> half:in;
half:out -> this:out; // an output from this module to the parent graph
I went as far as defining a biquad filter in the graph format
(http://plugin.org.uk/blockless/blockless/modules/biquad.g), but it
dosen't quite work because the execution order is more or less random.
I used the biquad in a simple toplevel graph
(http://plugin.org.uk/blockless/blockless/graphs/test4.g), it takes about
50 cycles per sample on PIII (interestingly its compiles to slightly worse
code in gcc3.2), the source my script produces is very tangled and
funtion-y, but gcc manages to untagle it and inline it all, eg.
http://plugin.org.uk/blockless/blockless/intem/test4.c
Its too much work to create a reasonably complex synth or anything in this
as theres no UI and keeping all the links straight in your head is
painful, so I dont know how well it scales up.
Its quite cool building up modules from gain and z^-1 units though :)
- Steve
Somehow I got unsubbed and didn't realize it. I've missed a few month of
discussion, and it seems like I've missed a lot, and yet not much has
changed :)
I regret that I can not completely read 4 months of archive, so if I need to
read something more than the skimming I've done, just point me at it, please
:)
It seems that people are still bandying about the idea of extending or
building from LADSPA, in several respects. A while back, I said I was, too.
I thought it only fair to solicit input from people here.
My goal has always been to implement a music app that tastes somewhat like
FruityLoops. Something that is easy to get started with, but has much depth
and complexity if you know how to ask for it. I envisioned it as an
all-in-one music studio application with synths, FX, etc.
LADSPA has a strong base, but I wanted a plugin API that was explicit about
note-control, multiple inputs/outputs and multi-channel audio. I wanted to
keep it pure C and truly as simple as possible, but no more. I wanted to
take away some complexity from the host without burdening the plugin too
much.
That said, here is the header file I've been dinking with. I haven't spent
a whole lot of time on it, just a few weekends thinking and
proof-of-concepting. I'd really like to get feedback on it. I've tried to
make it resemble LADSPA, as much as possible. There are a couple FIXME
notes where I've been undecided or haven't experimented completely yet.
I know there are probably other people who are writing similar apps. If we
have similar goals, I'd be happy to collaborate instead.
Thanks for the time. I'm tired of waiting for new versions of Windows music
apps, only to find the features I want STILL not implemented. Linux needs a
TRULY GOOD music studio project.
Tim
/*
* Tim Hockin <thockin(a)hockin.org>
* Copyright (c) 2001-2002 Tim Hockin
*
* This header file defines the API for the Open Audio Plugin Interface
* (OAPI).
*
* Goals:
* The main goal of this API is to provide a system that is full-featured
* enough to be the primary plugin system for an audio-development
* application, while remaining as simple, lightweight, and self-contained
* as possible.
*
* Credits:
* This API is based largely on LADSPA by Richard W.E. Furse et al.
*
* Overview:
* Plugins are loaded from shared object files. A shared object file holds
* one or more plugin descriptors, accessed by index. Each descriptor holds
* all the information about a single plugin - it's identification,
* capabilities, controls, and access methods.
*/
#ifndef OAPI_H__
#define OAPI_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/*
* A single audio sample: this datatype is used for passing audio data
* between plugins and hosts. Data is normalized between -1.0 and 1.0
* as the 0dB value, with 0.0 being silence.
*/
typedef float OAPI_sample;
/* forward declarations of the fundamental OAPI types */
typedef struct OAPI_descriptor OAPI_descriptor;
typedef struct OAPI_control OAPI_control;
typedef struct OAPI_ctrl_int OAPI_ctrl_int;
typedef struct OAPI_ctrl_float OAPI_ctrl_float;
typedef struct OAPI_ctrl_enum OAPI_ctrl_enum;
typedef struct OAPI_ctrl_string OAPI_ctrl_string;
typedef struct OAPI_state OAPI_state;
/* Plugin types: all OAPI plugins are one or more of these. */
#define OAPI_TYPE_SOURCE 0x01
#define OAPI_TYPE_EFFECT 0x02
#define OAPI_TYPE_SINK 0x04
/*
* A plugin descriptor: this structure describes what an plugin can do.
* Every plugin has exactly one descriptor, which the host must treat as
* READ-ONLY.
*/
struct OAPI_descriptor {
/*
* The label is a file-unique, non-whitespace, string identifier for
* the plugin. Hosts can use the filename and label to identify a
* plugin uniquely.
*/
const char *oapi_label;
/*
* The type is a bitmask of OAPI_TYPE_* values. A plugin may
* specify more than one type, for example a synth that can be a
* vocoder.
*/
//FIXME: needed? if note_on: SRC, if ins+outs: FX, if !outs: SINK
uint_32_t oapi_type;
/*
* The serial is simply a number by which the host can compare two
* versions of a plugin and pick the later version. The actual
* value has no meaning to the host. The only requirement for this
* field is that the value never gets smaller in new releases.
*/
unsigned oapi_serial;
/*
* The name is an arbitrary string, which hosts can display to
* users.
*/
const char *oapi_name;
/*
* These are display-friendly fields, which hosts can display to
* users.
*/
const char *oapi_version;
const char *oapi_author;
const char *oapi_copyright;
const char *oapi_license;
const char *oapi_url;
const char *oapi_notes;
/*
* Plugins can have multiple inputs and outputs (in/outs). These
* fields identify the capabilities of the plugin. Negative values
* mean no limit, all other values are literal.
*/
int oapi_inputs_min;
int oapi_inputs_max;
int oapi_outputs_min;
int oapi_outputs_max;
/*
* Each input or output consists of 1 or more audio channels. These
* values are the limits per in/out.
*/
int oapi_channels_min;
int oapi_channels_max;
/*
* Plugins can have controllable variables, things that would be
* knobs, buttons, and switches in hardware. Controls are presented
* as an array of the base control type, with enough information to
* be cast to the proper specific type.
*/
int oapi_ncontrols;
OAPI_control **oapi_controls;
//FIXME: instead of void *, make it return a descriptor, which is a
//clone of this with a 'priv' field, and status fields ? eliminates
//'query' method, which is broken anyway
//FIXME: explicit negative return values == better error reporting
/*
* create: instantiate the plugin
*
* This method is used to create an instance of the plugin described
* by the descriptor. Memory will be allocated and state will be
* initialized in this method. After this method is called, but
* before the plugin's activate() method is called, the host must
* call the plugin's set_rate() method.
*
* Arguments:
* descriptor: a pointer to the plugin descriptor.
*
* Returns:
* This method returns a pointer to a plugin-private handle. If
* initialization fails for any reason, this method must return
* NULL.
*/
void *(*oapi_create)(OAPI_descriptor *descriptor);
/*
* destroy: destroy an instance
*
* This method is used to destroy and clean up after an instance of
* the plugin. All allocated resources must be released. After
* this method is invoked, the plugin handle is no longer valid.
* This function can not fail.
*
* Arguments:
* plugin: a pointer to the plugin instance.
*
* Returns:
* This method does not return a value.
*/
void (*oapi_destroy)(void *plugin);
/*
* set_rate: set the sample rate
*
* This method must be called between the create() and activate()
* methods, or the plugin will not know the host's sample rate.
* It may be called again at any time, though changing the sample
* rate on an activated plugin may be delayed by the plugin until it
* is no longer active. There is no required set of supported
* sample rates, but plugins should support the common sample
* rates (44100, 48000, 96000) to be generally useful. Hosts should
* always check that all plugins support the desired sample rate.
*
* Arguments:
* plugin: a pointer to the plugin instance.
* rate: the desired sample rate.
*
* Returns:
* This method returns 0 on success and -1 if the sample rate is
* not supported or some error occurred.
*/
int (*oapi_set_rate)(void *plugin, int rate);
/*
* activate: prepare a plugin for running
*
* This method is used to prepare a plugin before being run. This
* is an optional method, and if provided, will be called once
* before the first call to the run() method. This method will not
* be called again by the host until the deactivate() method is
* called.
*
* Arguments:
* plugin: a pointer to the plugin instance.
*
* Returns:
* This method returns 0 on success and -1 on error.
*/
int (*oapi_activate)(void *plugin);
/*
* deactivate: stop a plugin after running
*
* This method is used to shut down a plugin when the host is done
* running it. This method, if provided, will be called at least
* once some time after a call to the activate() method and before
* the destroy() method. Hosts may use the deactivate()/activate()
* pair as a way to reset the plugin's state.
*
* Arguments:
* plugin: a pointer to the plugin instance.
*
* Returns:
* This method returns 0 on success and -1 on error.
*/
int (*oapi_deactivate)(void *plugin);
/*
* connect_input,connect_output: connect buffers for data
*
* Each in/out consists of one or more audio channels. Hosts must
* connect in/outs to buffers in order for a plugin to operate. The
* plugin should use these methods to flag in/outs as active or
* inactive and to recognize the desired number of channels (up to
* the plugin maximums specified in the descriptor). Plugins are
* expected to handle the case of the input buffer being the same as
* the output buffer (in-place operation) transparently to the host.
*
* Arguments:
* plugin: a pointer to the plugin instance.
* index: the in/out number (zero-based value)
* channel: the audio channel within the in/out (zero-based value)
* buffer: the buffer in which to read/write audio data
*
* Returns:
* These methods return 0 on success and -1 on error.
*/
int (*oapi_connect_input)(void *plugin, int index, int channel,
OAPI_sample *buffer);
int (*oapi_connect_output)(void *plugin, int index, int channel,
OAPI_sample *buffer);
/*
* run: use the plugin
*
* This method invokes the plugin for a number of audio samples,
* which are provided on connected in/outs.
*
* Arguments:
* plugin: a pointer to the plugin instance.
* nsamples: the number of samples available on in/out buffers.
*
* Returns:
* This method returns 0 on success and -1 on error.
*/
int (*oapi_run)(void *plugin, int nsamples);
#if 1 //two options for note-control
/*
* voice_on: trigger a note
*
* This method is provided by source plugins, such as synthesizers
* and samplers.
*
* Arguments:
* plugin: a pointer to the plugin instance
* note: a MIDI compatible note number. MIDI specifies that note
* number 60 is middle C, and all other notes are relative, with
* half-steps assigned at whole number increments. Hosts should
* support at least 128 note values (0-127) as designated by
* MIDI, but are free to support more. Plugins may respond to
* less than the full 128 note range.
*
* Returns:
* This method returns a non-negative voice-id on success and -1 on
* error. The voice-id is per-instance and has no meaning to the
* host. Voice-ids are unique, and if a plugin returns a duplicate
* voice-id, the prior instance of that voice has been stopped.
* Plugins and hosts can both use this to control polyphony.
*/
int (*oapi_voice_on)(void *plugin, int note);
/*
* manipulate a playing voice
*/
int (*oapi_note_off)(void *plugin, int voice);
//FIXME: how to indicate that a voice has finished?
#else
typedef enum OAPI_voice_op OAPI_voice_op;
enum OAPI_voice_op {
OAPI_VOICE_NONE = 0
OAPI_VOICE_ON = 1,
OAPI_VOICE_OFF = 2,
OAPI_VOICE_ISON = 3,
};
int (oapi_voice_ctrl)(void *plugin, OAPI_voice_op, ...);
//voice_ctrl(plug, OAPI_VOICE_ON, note); /* voice-id or -1 */
//voice_ctrl(plug, OAPI_VOICE_OFF, voice); /* 0, 1 if already off, -1 */
//voice_ctrl(plug, OAPI_VOICE_ISON, voice); /* 0 or 1 */
#endif
/* query the current state */
//FIXME: need to identify channels per in/out - this is b-r-o-k-e-n
int (*oapi_query)(void *plugin, OAPI_state *state);
};
/* the various types that a control may be */
typedef enum {
OAPI_CTRL_INT = 1,
OAPI_CTRL_FLOAT,
OAPI_CTRL_ENUM,
OAPI_CTRL_STRING,
} OAPI_ctrl_type;
/* for declaring ctrl sub-types */
#define OAPI_CONTROL_COMMON_FIELDS \
/* unique (within this plugin), non-whitespace string identifier */ \
const char *ctrl_label; \
/* display-friendly name */ \
const char *ctrl_name; \
/* the type of control */ \
OAPI_ctrl_type ctrl_type; \
/*
* all ctrl types have the following methods
* int (*ctrl_set)(void *instance, <type> value);
* <type> (*ctrl_get)(void *instance);
*/
/* a knob, button, etc. of a plugin */
struct OAPI_control {
OAPI_CONTROL_COMMON_FIELDS
};
/* to help in declaring arrays of pointers to structs statically */
#define OAPI_DECL_CONTROL(type) (OAPI_control *)&(OAPI_ctrl_ ## type)
/* the expanded structs for each control type */
struct OAPI_ctrl_int {
OAPI_CONTROL_COMMON_FIELDS
int ctrl_min;
int ctrl_max;
int ctrl_default;
uint_32_t ctrl_flags;
int (*ctrl_set)(void *plugin, int value);
int (*ctrl_get)(void *plugin);
};
struct OAPI_ctrl_float {
OAPI_CONTROL_COMMON_FIELDS
float ctrl_min;
float ctrl_max;
float ctrl_default;
uint_32_t ctrl_flags;
int (*ctrl_set)(void *plugin, float value);
float (*ctrl_get)(void *plugin);
};
struct OAPI_ctrl_enum {
OAPI_CONTROL_COMMON_FIELDS
int ctrl_min;
int ctrl_max;
int ctrl_default;
const char **ctrl_options;
int (*ctrl_set)(void *plugin, int value);
int (*ctrl_get)(void *plugin);
};
struct OAPI_ctrl_string {
OAPI_CONTROL_COMMON_FIELDS
const char *ctrl_default;
uint_32_t ctrl_flags;
int (*ctrl_set)(void *plugin, const char *value);
char *(*ctrl_get)(void *plugin);
};
/* flags for various control types */
#define OAPI_CTRL_FL_SCALAR 0x01 /* is scalar to the sample rate */
#define OAPI_CTRL_FL_LOG 0x02 /* is logarithmic */
#define OAPI_CTRL_FL_FILE 0x04 /* is a file name */
#define OAPI_CTRL_FL_DIR 0x08 /* is a directory */
#define OAPI_CTRL_FL_BOOL 0x10 /* is a boolean */
#define OAPI_CTRL_FL_FRAMES 0x20 /* is a measurement of frames */
#define OAPI_CTRL_FL_RDONLY 0x40 /* is read-only */
/* how a host queries the state of a plugin */
struct OAPI_state {
int st_inputs;
int st_outputs;
int st_channels;
};
/* how the host learns about the plugin */
OAPI_descriptor *oapi_descriptor(int index);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* OAPI_H__ */
I (still) don't think musical time belongs in timestamps of your
average event in XAP. Those events are meant to act as an alternative
to audio rate controls or blockless processing. The host gives you a
time frame to work with (expressed as a number of audio frames), and
that's the timeframe you're meant to work with. This applies to audio
as well as events.
If an analog synth does not need timestamps at all on CV changes, why
should our plugins?
A sequencer must obviously think in terms of transport or musical
time, or something else that is not free running. A sequencer will
also most probably need some form of editor to be useful. This may be
a replica of diode programming matrix, a piano roll, various
parametric selection and event processing tools, or all of those.
Thinking about this, one realizes that these tools must probably have
more or less random access to the sequencer's database to do anything
useful.
One might argue that the event processing tools should be the same
thing as the real time event processor plugins. However, for that to
be of much use, plugins would have to be able to see events from
virtually the whole timeline, or you wouldn't be able to do
*anything* you couldn't just as well do in real time, with audio time
timestamps.
So, imagine a simple, function call based Sequencer DataBase API.
Sequencer plugins could implement that, and then editors could use it
to manipulate the events in the sequencer in any way they like. The
API could be designed so that sequencers may make the calls RT safe,
so the API could be used from within the RT thread of a running host.
(Most users of audio/MIDI sequencers will definitely expect editing
during playback to work properly!)
It would probably be possible to implement the Sequencer DataBase API
as a protocol over the XAP event system, but I don't think it makes
much sense to take it any further than that - if even that far.
Now, are there *still* things you can't do with this, and if so,
what? I'd like a list of operations and effects, or something...
//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 -'
.- M A I A -------------------------------------------------.
| The Multimedia Application Integration Architecture |
`----------------------------> http://www.linuxdj.com/maia -'
--- http://olofson.net --- http://www.reologica.se ---
Hi all,
Partly on the recommendation of Conrad Parker (Sweep, Aube), I'm posting this to
inform you of the existence of http://devdsp.net - my news site for computer
musicians. If you're looking to post info on projects you're working on (not
every change in CVS, please, but for new tarball releases and such, please do),
you may want to consider submitting an announcement. The site is read primarily
by musicians, most of whom don't use Linux yet, but with your help we may just
be able to change that (*grin*)
take care,
Matthijs de Jonge
http://devdsp.net -- news for computer musicians
1. getTimeInfo() does *not* take a time argument of any kind;
only a 32 bit filter, to say which fields you actually need.
That is, you can only get the full info for the start of
the buffer. There is a tempoAt() call, that gives you the
tempo at the specified sample frame in the buffer.
2. The VstTimeInfo struct is interesting. I like the unit
for musical time: pulses with 1 PPQN. :-) Tempo is in
BPM. (Why not QN/s? ;-) There is a field that says where
the last bar starts. There's also time signature, SMPTE,
MIDI clock (samples to next clock) and a bunch of flags.
Flags include transport changed, playing and "cycle
active". (The latter come with loop start and end positions,
obviously.) And automation reading + writing... It is also
interesting to note that the "sample position" field in
here is timeline bound - it may jump! There's a nanoseconds
field as well, holding the "system time" corresponding to
the first sample in the buffer.
Conclusion:
a. The information is there, but you have to *pull*
it from the host. Doesn't seem like you're ever
notified about tempo changes or transport events.
b. Since you're asking the host, and there are no
other arguments, there is no way that one plugin
can keep track of more than one timeline. It
seems that it is assumed that there is only one
timeline in a net.
3. There are calls that allow plugins to get the audio input
and output latency.
Conclusion:
c. I'm assuming that this is mostly useful for
VU-meters and other stuff that needs to be
delayed appropriately for correct display.
Obviously not an issue when the audio latency
is significantly shorter than the duration of
one video frame on the monitor! ;-) Seriously
though, this is needed for "high latency"
applications to display meters and stuff
correctly. They're not very helpful if they're
half a second early!
4. There is a feature that allows plugins to tell the host
which "category" they would fit in. (There is some
enumeration for that somewhere.) Might be rather handy
when you have a large number of plugins installed...
5. A getCurrentProcessLevel() host call lets the plugin ask
what kind of context it's being called from. Can return
values corresponding to "not supported", "user/GUI",
"audio/irq", "sqeuncer/irq" and "user/offline". Other
values are possible and "probably" (as they say) mean
something that pre-empts the user thread.
6. There is support for using the whole process() call
asynchronously. This is for external DSPs and stuff. The
plugin is expected to return "instantly" from process(),
and then the host wanders off to do something else. The
host will use another plugin call to poll, to see if the
data from the external DSP (or whatever) is available.
Conclusion:
d. I think we can ignore this feature. We don't
do external DSP, and we don't feel like having
hosts poll/busy-wait for data, do we...?
7. There's a bunch of calls specifically meant for off-line
processing. This is basically about accessing the host's
"open" files, setting markers and stuff, being notified
when files are opened, closed, changed, when markers are
changed etc. A plugin API in itself.
8. You can ask the host about the speaker arrangement,
for surround stuff...
9. There is a bypass feature, so that hosts can have
plugins implement sensible bypass for mono -> surround
and other non-obvious in/out relations. (As if in/out
relations ever were to be assumed "obvious"!)
10.Finally, the states. There are 2 calls related to this;
suspend() and resume(). Nothing much is said about these,
and they're not used for much in the examples. Just for
clearing delay buffers and the like. Memory is generally
allocated in the constructors and freed in the destructors,
but I'm not sure when and where you're supposed to
reallocate buffers if you need to... (This is when you
start realizing why compatibility problems with VST are
so common. Where are the reference docs!? *heh*)
//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 -'
.- M A I A -------------------------------------------------.
| The Multimedia Application Integration Architecture |
`----------------------------> http://www.linuxdj.com/maia -'
--- http://olofson.net --- http://www.reologica.se ---
Aaargh! Can't seem to find anything more interesting than a PDF with
a very basic overview... Is there a freely available SDK anywhere?
Would just like to say that I find some parts of that PDF a bit
scary... We're *not* talking about a lean and mean low overhead API
here, that's for sure!
//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 ---
http://plugin.org.uk/meterbridge/
Changes
* Greatly improved the readability of the VU meter
* Made the VU meter conform the the AES analogue equivalent levels. This
should make it more generally useful without adjustment and if you
have properly calibrated DA converters and analogue equipment then
the levels should agree.
* Made the DPM meter look nicer and easier to read.
* Cured a handful of segfaults (thanks to Melanie and Mark K.).
* Reduced the maximum CPU usage of the UI. It should never have caused RT
problems before, but it could have stolen cycles from other UI
threads that needed them more.
* Cleaned up and optimised the port insertion (input monitoring) code, its
still hacky but cleaner and more reliable now.
* Added a "set jack name" option, -n.
* Will now make a meter for every non-flag argument, even if there is no port
matching that name, so, eg. you can create an unconnected 4
channel meter with "meterbridge - - - -".
* More reliable cleanup on exit.
Before it goes to 1.0 I'd like some sort of documentation, and maybe to
improve the input port monitoring situation. So don't hold your breath ;)
If anyone wants to write anything for the docs I would be extremely
greatful.
I will look at any tricky things, like meter labelling, and antialiased
needles after 1.0.
- Steve
Well, this might be early, but I needed to do something slightly less
demanding for a while. So I hacked a small presentation:
http://olofson.net/xap/
Please, check facts and language (not my native tongue), and suggest
changes or additions.
(Oops! Clicked on dat doggy-like animal in da process... ;-)
//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 -'
.- M A I A -------------------------------------------------.
| The Multimedia Application Integration Architecture |
`----------------------------> http://www.linuxdj.com/maia -'
--- http://olofson.net --- http://www.reologica.se ---
Actually, it may not be all that hairy after all. Consider these
events:
XAP_A_BUFFER
Function: Someone just gave you an audio
buffer of the standard size used
by the Host. It's all yours now;
do what you like with it. Don't
forget to free it eventually!
Arguments: Pointer to the buffer.
Cookie. (So you know what it's for.)
Size. (# of BYTES actually used.)
XAP_A_REQUEST_DATA
Function: Ask for a number of buffers.
The API doesn't guarantee anything
about when they'll arrive; that's
something you and that guy in the
other end will have to discuss.
Arguments: Size. (# of BYTES of data you want.)
Cookie. (So the other guy knows)
When. (Your deadline. Be sensible...!)
If you want data streamed to your plugin, you'll send
XAP_A_REQUEST_DATA events, and (eventually) receive XAP_A_BUFFER
events. Connections are made by the host (as usual), although each
streaming connection actually needs *two* connections; one in each
direction. (The API should probably cover this, so hosts and/or users
don't have to mess with it manually.)
Ok?
//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 -'
.- M A I A -------------------------------------------------.
| The Multimedia Application Integration Architecture |
`----------------------------> http://www.linuxdj.com/maia -'
--- http://olofson.net --- http://www.reologica.se ---
> Steve Harris <S.W.Harris(a)ecs.soton.ac.uk> writes:
>
> SAOL is still block based AFAIK.
See:
http://www.cs.berkeley.edu/~lazzaro/sa/pubs/pdf/wemp01.pdf
Sfront does no block-based optimizations. And for many
purposes, sfront is fast enough to do the job.
It may very well be that sfront could go even faster
with blocking, although the analysis is quite subtle --
in a machine with a large cache, and a moderate-sized
SAOL program, you're running your code and your data
in the cache most of the time.
Remember, blocking doesn't save you any operations, it
only improves memory access and overhead costs. If those
costs are minimal for a given decoder implementation,
there is not as much to gain.
-------------------------------------------------------------------------
John Lazzaro -- Research Specialist -- CS Division -- EECS -- UC Berkeley
lazzaro [at] cs [dot] berkeley [dot] edu www.cs.berkeley.edu/~lazzaro
-------------------------------------------------------------------------