240 Hz is usually too slow for an envelope player, but it is appropriate for timing note starts, stops, and releases. To help you time these and other events, the Audio folio provides a set of timing calls that refer to the audio clock. The Audio folio also has a timing notification mechanism, the cue, which a timing call can send back to a task at the appropriate time.
Note: Do not depend on the audio clock being exactly 240Hz.
The audio clock keeps a running total of its ticks from the moment the Audio folio is started. The beginning total is 0. The running total, which gives elapsed time in ticks, is stored as an unsigned 32-bit integer. The clock wraps around when it reaches its maximum; that is, it stores up to 4,294,967,296 ticks, then jumps back to 0 and starts accumulating once again. At 240 ticks per second, 4,294,967,296 is enough ticks to measure the length of approximately 207 days.
Applications are not affected when the clock wraps around, because the Audio folio treats time as circular. That is, it understands that 23 ticks is 30 ticks after 4,294,967,290 ticks. And because time is circular, a 3DO system left running as a demo in a store window will not stop every 207 days when the clock resets itself.
Whenever an audio call returns a time from the audio clock, it uses the AudioTime
variable type, which is defined as a uint32
.
AudioTime GetAudioTime( void )
AudioTime
variable type.
To create a cue, use the Audio folio call CreateCue()
, which returns the item number of the created cue. The statement below is a CreateCue()
call used to create a cue. It stores the returned item number in the variable Cue
.
Cue = CreateCue(NULL)
uint32 GetCueSignal( Item Cue )
Err SignalAtTime( Item Cue, AudioTime Time )
SignalAtTime()
.
Whenit executes, SignalAtTime()
waits until the audio clock gets to the specified AudioTime value. At that point, the call sends a signal to the calling task using the signal bit allocated to the specified cue. The call returns 0 if successful, or a negative value (an error code) if unsuccessful.
After SignalAtTime()
is executed, the calling task can either put itself in wait state to wait for the cue's signal (using the call WaitSignal()
) or it can proceed to other business and check later to see if the cue's signal was received.
WaitSignal()
, you can use this convenience call:
Err SleepUntilTime( Item Cue, AudioTime Time )
SleepUntilTime()
puts the task in wait state until the specified time. At that point, the task leaves wait state and continues execution. SleepUntilTime()
returns 0 if successful, or a negative value (an error code) if unsuccessful.
SleepAudioTicks()
is not an accurate timing call when used repeatedly. For example, a task may want to start an instrument every 60 ticks. It uses SleepAudioTicks()
to sleep 59 ticks, then wakes and starts an instrument, uses SleepAudioTicks()
to sleep 59 more ticks, then wakes and starts an instrument, and so on. If, at any time, the process of waking and starting an instrument takes more than one cycle (which may happen during system hiccups such as drive access and so on), the time between instrument starts becomes erratic. If you are trying to keep many different instruments synchronized while playing a score, the accumulating timing error you get using SleepAudioTicks()
will soon turn your score into random burblings. Use SleepUntilTime()
for accurate timing of serial events.
Note: If you request a wake up call to the timer but you no longer want it, call AbortTimerCue()
to remove the request.
To set a signal frame within a sample attachment (or, if desired, a signal point within an envelope), use this call:
Err MonitorAttachment( Item Attachment, Item Cue, int32 Index )
Note: CUE_AT_END is the only supported index value.
When MonitorAttachment()
executes, it monitors the specified attachment playback. When playback reaches the signal frame or point, the call signals the calling task using the cue's allocated signal bit. If successful, it returns 0. If unsuccessful, it returns a negative value (an error code).
The calling task can choose to enter wait state to wait for the cue signal. While the task waits, instruments that are playing continue to play. The calling task can also choose to go on about its business and continue execution, checking later to see if the cue signal was received.
StopInstrument()
call.For situations like this, you can set one (or more) of the instrument's attachments as a stop linked attachment. The first stop linked attachment to finish playing stops the entire instrument along with all of its attachments. If, in the previous example, the envelope attachment was a stop linked attachment, then as soon as it had faded to 0 and finished playback, it would stop the sampled sound instrument so that it no longer used DSP cycles to play the now inaudible release loop of its sample.
int32 WhereAttachment( Item Attachment )
The byte offset returned by WhereAttachment()
is not a frame index but a byte index. It starts at 0 with the first byte of the sample and counts up byte by byte from there. To get the frame number, multiply the number of bytes per sample by the number of samples per frame, use the result to divide the byte offset, and then discard the remainder. For example, if the call returns byte 9657 of a 16-bit stereo sample, then divide by 4 (two bytes times two samples) to get a frame offset of 2414. If the sample has finished, it returns a value outside the range of valid bytes; the value can be negative or positive.