Standards Questions.

From: Robin Davies (rerdavies@msn.com)
Date: Fri May 05 2000 - 09:25:09 EDT


Hmmmm.

Well. This isn't quite the way I wanted to announce this, but, I think this
is probably the best forum for these questions, so I'll let the cat
out of the bag.

I am very close to prereleasing a new SAOL compiler. Full details will be
forthcoming in a general announcement shortly. Briefly, the Sfx compiler is
a C++ front-end compiler that uses classic optimization strategies
(primarily heavy inlining, and loop unravelling) to generate real-time
orchestras. Preliminary results are excellent. I currently have a number
of very satisfying real-time orchestras running with very reasonable
processor loads.

Although I am able to compile all of the generally avaiable sample programs
without problem, I have some serious problems with one of the sample SAOL
orchestras that I wrote.

I've tried to run the program on SAOLC. Some errors that, when fixed produce
no audio output.

I've run the program on SFRONT. Result: a long list of errors not detected
by SAOLC.

Here are the general issue as reported by SFRONT and/or SAOLC.

1) Precedence of argument declarations, variable declarations, standard
names.

The sample program uses 'input' as an opcode argument which conflicts with
the standard name 'input'. SFRONT compains; SAOLC does not.

The sample program uses 'gain' as a variable in an opcode which conflicts
with the core opcode 'gain'. SFRONT complains; SAOLC does not.

Are these legitimate errors? Does the standard define precedence rules for
the various scopes avaiable in SOAL (argument, variable declaration,
standard names, core opcode.. any others?).

For what it's worth, Sfx performs as follows: variable declarations and
argument declarations hide hidden names (the argument or variable
declaration takes precedence); core opcodes names and variable/argument
names are in seperate namespaces; user-defined opcodes cannot override core
opcodes when in iso-compatible mode; with extensions enabled, user-defined
opcodes can overload core opcodes, but not replace them (declare them with a
different number of arguments, different signal rates, different type
arguments similar to Java or C++ overloading). I'm not saying that's the
right way to do it; it probably isn't. I'd just like to know which way to
fix it.

2) Use of i-rate expression in kopcodes.

// Equal-power panpot.
aopcode Pan(asig input, ivar angle) {
    ivar phi;
    ivar leftVol;
    ivar rightVol;

    phi = kPI*0.25*(angle+0.5);
    leftVol = sin(phi);
    rightVol = cos(phi);
    return (input*leftVol, input*rightVol);
}

SFRONT reports:
    "I-rate assignment in aopcode will never run."

Is this opcode legal or not?

2) Use of i-rate expressions in k-rate if clauses.

Although i-rate expressions are not allowed in if statements with k-rate
guard statements by the Sfx compiler, i-rate expressions within kopcodes
within the body of an if statement *are* allowed by Sfx.

Consider the following code fragment (not an actual live code example):

kopcode ADSR(ivar attack, ivar decay, ivar sustain, ivar release) {
    ivar iPrecalculatedValue;
            // gratuitious i-rate expressions.
    iPrecalculatedValue = log((1-sustain)*release);
    return (kline(0, 0, 1, attack*2, sustain, log(decay), 0, release) );
}

instr AnInstrument(...){
    if (kGaurdCondition) {
        aOutput = ADSR(1,1,1,1)*SawWave();
    }
};

Admittedly the use of a K-rate guard isn't very compelling here, but I'm
sure I could come up with a highly compelling example for this.

Briefly here's how this is implemented in Sfx. I-Rate expressions within
ADSR are within the body of a k-rate guarded if statement (or else
statement, or while statement) are executed unconditionally at i-rate, but
conditionally at k-rate and a-rate. Because each core opcode has state data
associated with it's invocation, it's straightforward to do this for
user-defined opcodes as well: the compiler generates state data (e.g.
storage for iPrecalculateValue) that is unconditionally pre-calculated at
i-rate on the assumption that it will eventually be used at k-rate at some
point or another (otherwise the guard would have been i-rate).

Q: Is this behaviour required by the standard or not? Admittedly it's not
explicitly required. A clarification is required here. I can understand
restrictions on a-rate expression in a kopcode, but restricting i-rate
expressions in kopcodes seems to ignore the purpose of rate-tags on opcode
arguments.

3) a-rate expressions in kopcodes.

Sfxx doesn't explicitly disallow a-rate expressions in kopcodes. It's
conceivable that a core specialop could be used to downsample the kopcode.
Admittedly this would be a specialop if it were a core opcode, but I'm not
sure I really see the difficulty in supporting user-defined opcodes like
these. Do I need to add code to detect these opcodes and reject them?

e.g.:
       kopcode VuMeter(asig aAudio) {
            return (downsamp(aAudio));
       };

Q: Is this required behaviour or illegal in SAOL?

4) Calculation of opcode rates from arguments.

The standard defines how x-opcode rates are determined for core opcodes (the
maximum rate of the arguments). It doesn't, however, explicitly define how
x-opcode rates are determined for user-defined opcodes.

Consider the following opcode:

opcode SawWave(xsig kCps) {
    return (oscil(tblSaw, kCps) );
}

SOALC doesn't seem to like this kind of opcode (it gives an error to the
effect that expressions within the opcode run *faster* than the opcode rate
and will never get executed, suggesting strongly that the opcode has been
resolved as kopcode.

There are two potential ways to determine the rate of the opcode: option 1
is to use the same method used to calculate core opcode rates; option 2 is
to evaluate the opcode and use the rate of the highest-rate return
expression within the body of the opcode. This really isn't a big deal since
we must already analyze return statements to determine the width of the
opcode: e.g.

    aopcode Stereo(asig audio) { return ( audio, audio) }

returns asig[2]. I understand that array returns were a late addition to
SAOL (and a bitch to implement, I might add); now that the hard work has
been done, doesn't it make sense to do the right thing with x-opcode return
rate evaluation?

User-defined opcodes of the form opcode Op(asig aAudio, xsig param1, xsig
param2) provide *dramatic* opportunities for optimization while still
allowing very powerful user-defined opcodes. My favorite current example,
which neither SAOLC nor SFRONT seem to like is:

    opcode ResonantFilter(asig aInput, xsig xCps, xsig xDbResonance) ...

As declared this opcode is almost free to use with i-rate parameters,
reasonable with k-rate parameters (the k-rate expressions are expensive
enough that they compare to the cost of a-rate expressions), and bordering
on impractical at a-rate, but, who's to say.

Regards,

Robin Davies.



This archive was generated by hypermail 2b29 : Mon Jan 28 2002 - 12:03:54 EST