CreateObject()
calls and methods to set the objects' characteristics or the MIDI score interpretation tools described in Playing MIDI Scores can be used. After the Juggler objects have been created, playing them with the Juggler is a simple process. This section describes the process used to play objects with the Juggler.
Absolute and Relative Event Times
Each Juggler object contains events, whether it is a sequence with its own event list, or a collection that contains sequences as constituents. Each event comes with a timestamp that gives the relative time in ticks for the start of each event. Relative time is reckoned as the number of ticks after starting time: 30 ticks after playback starts, 486 ticks after playback starts, 1090 ticks after playback starts, and so on. These relative event times are converted to absolute event times when an object becomes active.
When an object is activated with a Start message, the message provides an absolute starting time, which the object uses to determine subsequent times for all events. This absolute starting time is usually read from the audio clock when the object is started, but can be any arbitrary value in ticks. For example, an object has three events with timestamps at the relative times 0, 30, and 600 ticks. The object is started with a Start message that provides an absolute starting time of 34,765. The object executes its events at the absolute times 34,765 (34,765+0), 34,795 (34,765+30), and 35,365 (34,765+300).
If the object had a start delay specified when it was started (using the tag argument JGLR_TAG_START_DELAY), the specified delay ticks are added to the start time, effectively delaying all absolute event times by that amount. If the start delay was 300 ticks and the provided start time was 34,765, then the delayed start time would be 35,065 (34,765+300). The absolute event times would then be 35,065 and 35,095 and 35,695.
The time call comes from the task that runs the Juggler, a process called bumping the Juggler. Each call indicates the time in ticks, such as 20,045 or 34,765 or something similar. The calling task usually gets its time values from the audio timer, which provides a steady measure of time. However, the task can come up with time values from any source, such as vertical blanks. Or it can, if it wants, make up completely arbitrary time values to give to the Juggler, a convenient testing technique, as shown in the sample code in An Example Program.
If the calling task sends time values infrequently, consecutive events in an event list can be played simultaneously. For example, if a sequence has an event list with events occurring every 30 ticks and the calling task provides current time values 300 ticks apart, the object executes ten simultaneous events each time it receives a time value.
When each active object receives the current time value from the Juggler, it executes the events that need execution and also looks to see what events are yet to be executed. A sequence finds the next event following the current time and reports the execution time of that event. A collection gathers the next event execution times from all of its constituent objects and reports the execution time of the earliest event. The Juggler gathers the next event execution times from all the active objects in its list and reports the earliest time back to the calling task.
When the calling task receives the absolute time of the next event, it can put itself into wait state or go on to do other things until that time occurs. When the time comes, the task calls the Juggler with the current time. The Juggler informs all the active objects of the time; they execute the event (or events) that need execution and report the time of the next event, which the Juggler returns to the calling task. The task waits again for the next event time and repeats this cycle until there are no more events to execute.
int32 BumpJuggler( Time CurrentTime, Time *NextTime, int32 CurrentSignals, int32 *NextSignals )
CurrentTime
, the current time value supplied by the calling task; *NextTime
, a pointer to a time variable where the Juggler stores the next event time; CurrentSignals
, a signal mask containing the current signals received; and *NextSignals
, a pointer to a signal mask variable where the Juggler stores the next event signal.
Note: The current version of the Juggler does not support signal designated events. The CurrentSignals
argument should be set to 0 and the *NextSignals
argument should point to a dummy variable.
A task making this call usually gets the current time value from the audio timer, but can supply whatever arbitrary value it wishes.
When executed, BumpJuggler()
passes the CurrentTime
value to the Juggler, which passes it on to the active objects in its list. The objects then execute unexecuted events that should have been executed by the supplied time. BumpJuggler()
stores the time of the next event to be executed in the NextEvent
variable, where the calling task can retrieve the time.
BumpJuggler()
returns a 1 if every object is finished playing or if there are no active objects. It returns a 0 if it was successful and it executed events in active objects. It returns a negative value (an error code) if unsuccessful.
int32 TermJuggler( void )