Re: [linux-audio-dev] Re: Csound rates

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

Subject: Re: [linux-audio-dev] Re: Csound rates
From: Paul Barton-Davis (pbd_AT_Op.Net)
Date: to tammi  27 2000 - 20:21:55 EST


In message <200001280000.TAA11868_AT_ginette.musique.umontreal.ca>you write:
>Paul Barton-Davis wrote:
>> This is why I am disappointed that SAOL, which has brilliantly
>> included the concept of "width" in its specification, has continued to
>> talk about "rate" as if it really mattered at the language level. It
>> doesn't.
>
>I am interested in hearing more, since I'm planning to build rate (and
>width, too) into the type system.

Well, this duplicates some of my response to PW, but here's a copy of
the message I sent to Eric Scheirer and the sfront folks. Note: there
is an error in this re: the G4/Altivec unit in terms of the precise
numbers quoted for "vector transparency", but the principle remains
true, I think.

--p

--------------------------------------------------
To: eds_AT_media.mit.edu
cc: johnw_AT_CS.Berkeley.EDU, John Lazzaro <lazzaro_AT_CS.Berkeley.EDU>
Subject: SAOL and the concept of rates
In-reply-to: Your message of "Tue, 23 Nov 1999 10:52:34 PST."
             <199911231852.KAA12202_AT_snap.CS.Berkeley.EDU>
Date: Tue, 23 Nov 1999 15:42:43 -0500
From: Paul Barton-Davis <pbd_AT_op.net>

Eric -

as i said in my last message, i understand that this is really water
under the bridge, but its water i need to get off my chest :)

Interestingly, the sfront book notes:
(http://www.cs.berkeley.edu/~lazzaro/sa/book/saol/exstat/index.html#summary)

  The SAOL toolkit is limited because there is so much information to
  remember about each construct: program semantics, width
  semantics, and rate semantics. Three core statement types is a
  manageable number to remember how to use, while 6 or 7 might
  not be.

In the opposite box of the same URL, it notes a bunch of rules for
expression rates.

Although its clearly too late, I would suggest that if SAOL dropped
the entire concept of an expression having a rate, it would reduce a
considerably the amount of information one would have to remember
about each construct, and simplify any implementer's task.

As I said last time, I think the idea of an expression having a "rate"
is mostly a carryover from Csound; if you approach a synthesis
language more from a pure programming language point of view, the
concept evaporates. I think the key elements can be take from C:

        float[BLOCKSIZE] avar;
        float kvar;
        const float ivar;

        void opcode_taking_arate (float *);
        void opcode_taking_krate_val (float); /* strange concept */
        void opcode_taking_krate (float*);
        void opcode_taking_irate (const float *);

        opcode_taking_arate (avar); /* legal */
        opcode_taking_arate (ivar); /* illegal - type mismatch */
        opcode_taking_arate (kvar); /* illegal - type mismatch */
        opcode_taking_arate (&kvar); /* legal, but will probably core dump */
        opcode_taking_krate (&ivar); /* ditto */

        opcode_taking_krate_val (kvar); /* legal, kvar unchanged */
        opcode_taking_krate_val (avar); /* illegal - type mismatch */
        opcode_taking_krate_val (avar[0]); /* legal, but won't alter avar */

        opcode_taking_krate (avar); /* legal */
        opcode_taking_krate (&kvar); /* legal */
        opcode_taking_krate (&ivar); /* illegal - ivar is "const" */

        opcode_taking_irate (&ivar); /* legal */
        opcode_taking_irate (&kvar); /* legal, but won't alter kvar */
        opcode_taking_irate (&avar); /* legal, but won't alter avar */

The crucial point: the value of "arate" changes at most once per
function call, just like the value of "krate".

There only possible exception: if you have a multi-processor
system. One processor could read from the memory location(s) referred
to by "arate" at the same time as another is writing to it. Under such
circumstances, the rate at which "krate" is modified (in terms of the
time between any two of its values changing) is much faster than the
rate of change to the value of "scalar" during a similar function call.

However, this is situation is not supported by SAOL either: there is
no provision for the data referred to by an a-rate signal to be valid
at any time between a call to an opcode and the return from that
opcode. It might work, but as they say throughout so many language
manuals, it would be "implementation dependent". If you had a
BLOCKSIZE of less than 128 for example, and were using a G4 processor,
its not impossible that the entire contents of "arate" would change
during the same processor cycle c/o the altivec vector pipeline unit;
very different behaviour than on a non-pipelined processor.

So, I say with wanton heed, "rates" are irrelevant: data changes at
the rate of once-per-function-call, and if there is a 1:1 ratio
between a SAOL opcode and an implementation language's function call,
then it changes once-per-opcode call.

i-rate expressions are constants, just like in C, but thats an
internal compiler detail, not a language level concept. For example,
there is no reason except efficiency why a C compiler could not take
the following code:

    if (10 < 20) {
          .. do something ..
    }

and actually generate real machine code for it! No self-respecting
compiler would do this, of course, but thats not part of the
language, just an implementation detail.

As for the conditions associated with guard clauses and conditional
bodies, I think that C++ makes it clear that these are dubious. What
matters about a guard clause is the return type of the operator, not
the types of the arguments:

   bool operator< (SomeFunkyClass &, SomeOtherFunkyClass &);
   
   SomeFunkyClass sfc;
   SomeOtherFunkyClass sofc;
   SomeFinalFunkyClass sffc;

   if (sfc < sofc) {
        sffc.do_something ();
   }

This is true for every arithmetic, relational and logical operator. As
long as there are operators to combine various different types,
anything is OK:

   if (asig < 10) {
       ksig = (asig > 12) + ksig / 3;
   }

that expression requires (in C++ notation):

   ksig& operator/ (ksig&, ivar&);
   asig& operator+ (asig&, ksig&);
   ksig& operator= (ksig&, asig&);
   asig& operator< (asig&, ivar&);
   asig& operator> (asig&, ivar&);

again, no notion of "rate" is necessary. There are just a series of
opcode calls to each operator, at the end of which some scalars have
had their value changed (or not) and some vectors have had all or none
of their values changed. what could be simpler ? :)

The only difference between an vector and a scalar value is its
size. Thus, more memory locations have been altered by a call that
modifies an vector variable than one that modifies a scalar
variable. A vector can be implicitly converted to a scalar by using
its first element, but not vice versa.

I suppose that implementations of SAOL that want to pay attention to
expression rates because of tight scheduling issues might provide
support for the rate concept - you know that an expression with a-rate
variables will take about BLOCKSIZE times longer than the
expression using k-rate variables. But you still don't need the
concept of a "rate" to determine this - you just have to know that one
thing operates on a vector, and the other on a scalar.

So far, however, in writing a real-time compiler for Csound, I have
not found any reason to pay any attention to the notion of rate.

Just my $0.02. Having said all this, its part of my plan to port SAOL
"into" Quasimodo in the new year. Its just too close to the language I
want to be able to use with Quasimodo to not use it!

- --p

------- End of Blind-Carbon-Copy


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:23:27 EST