Re: turnoff statement

From: John Lazzaro (lazzaro@CS.Berkeley.EDU)
Date: Sat Nov 20 1999 - 14:57:24 EST


> just a question about the way in which the turnoff statement should be
> executed.

First, as always, this is only my interpetation of the standard, and
hopefully someone else will step in to correct me. It also mirrors what
sfront currently implements ...

...

Let's start in a simple world, one where there are no extend() statements
in your code, just turnoff statements, and where the duration of the
instance was -1 (all MIDI notes, and SASL and dynamic notes set to -1).

In sfront, there are two internal boolean variables for each instance,
"turnoff" and "released". Both are initialized to zero. The value of the
standard name "released" mirrors the current value of the released
state variable.

Executing a turnoff() statement during a kpass results in:

 if (!released)
   turnoff = 1;

At the end of each execution cycle (technically, sfront does it at the
beginning of the following one, but the result is the same -- I'm using
the "end of the execution cycle" to correspond to step 12 in section
5.7.3.3.6 of the standard, pages 25-26), the following action happens,
depending on the current values of turnoff and released

   released turnoff action
--------------------------------------
      0 0 do nothing
      0 1 set released to 1
      1 1 terminate the instrument

So, this table answers your question, if a turnoff is executed, two
sets of s_rate/kcycle apasses happen before the instrument actually
gets terminated, assuming no action happens in the meantime to save
it. Also note that the released flag is not set immediately when
the turnoff() command is executed, but just in time for the next
kpass -- this isn't explicitly stated in the standard, but seemed
to be the right thing.

...

The extend() statement implementation is more complex, because it
gets used for all sorts of things:

-- for notes with a duration of -1 (all MIDI, and dynamic and SASL
instances with duration set to -1), an extend() call signals its
end, either by mimicing the turnoff statement described above (with
negative or zero argument) or after a set period of time after the
call.

-- for notes with a positive duration that is still in progress,
extend() "tacks on" additional time to the end of the note, or
"subtracts it" from the end of the note, depending on the sign
of the argument. this has the added complication that the extend
argument is in units of seconds (not affected by tempo) while the
remaining duration is in beats (modulated by tempo).

-- for notes previously subject to turnoff statements, it cancels
the impending turnoff, and schedules a new one for some time in
the future, if the argument to extend is positive.

These multiple uses means the actual state machine in sfront to
terminate notes (that happens at the end of each execution cycle)
as well as the code that runs when extend() executes, is quite
complex -- I tried distilling it down to a simple state machine
for this email, and gave up, since it would involve explaining
a lot of sfront-specific items. Note that this complexity also
covers the case where turnoff() gets called for a note with a
duration != -1, which I didn't cover in the initial turnoff
explanation above.

Finally, the complexity of this state machine deals with the fact
that although the standard is written as describing tempo changes
as resulting in "relabel the timestamps of SASL commands", an
efficient implementation won't do that, but instead will change
the function that maps beats to seconds. The most efficient
implementation tends to work its way into the state machine.

...

Hope this helps, I'm sure there's at least one bug in the description
above and maybe more, hopefully Eric will chime in with a simpler
description that covers all the cases that an implementer has to
handle to get a compliant decoder!

                                                --john lazzaro



This archive was generated by hypermail 2b29 : Wed May 10 2000 - 12:15:47 EDT