Scheduling is the art of delaying actions (events) until later periods in time. In Marsyas time and event are are more general than many other systems. This allows for a wide range of user specified control rates and actions.
Time is simply a counter. What it counts is up to the writer of a new timer class. The two supplied timers, TmSampleCount and TmRealTime, count audio samples and system micro-seconds respectively.
There are a number of issues surrounding control rates in Marsyas and most other time-aware processing systems. Marsyas' primary task is to process audio data. This data passes through the network in buffers of size N. Usually the network is prompted to process the buffer of N samples by an outer loop. During processing control of the network is lost as the buffer of data passes through each MarSystem object. The scheduler checks for and dispatches events when the network is ticked and before the buffer of data passes through the network. Events are therefore dispatched at the start of each buffer processed.
Event dispatch is therefore governed by the audio sample rate. Ultimately every custom timer bears some relation to the audio sample rate. Since events are dispatched at the start of each tick, events are actually dispatched at a rate of every N samples. This implies that there is a granularity on event dispatch based on the sample rate and buffer size. If an event is to be dispatched at a point in time that falls inside a buffer, ie at 256 for a buffer size of 512 samples, then that event will not be dispatched until the next buffer boundary at which point its dispatch time will be <= current counter time.
We might wish to have sample accurate event timing. After all, there are other audio processing systems that can claim the accuracy we might desire. The major obstacle to achieving this accuracy is due to Marsyas' dataflow architecture. When a buffer of N samples passes through the network it is processed multiple times (normally once by each object in the network). This means that each sample recurs a number of times equal to the number of Marsystems that process it. More specifically, if the time is T when the network is ticked, then after the first MarSystem processes the buffer of N samples time will be at T+N. The next MarSystem will start processing the buffer at time T. In this way, time bounces between T and T+N as the buffer passes through the network. This situation makes it exceedingly difficult to make the network consistent for events that occur between T and T+N. If a control value C is to be changed at time T+K where 0<K<N then for C to remain consistent for all MarSystem objects that might be interested then it must be changed to the previous state at the start of buffer processing then to the new value at the event time - each time the buffer is processed. This would be somewhat difficult and computationally expensive to accomplish within the dataflow model. For this reason the scheduler only dispatches events on buffer boundaries - when the network is ticked - as this is the only point when all MarSystems are at the same point in time.
In many systems multiple control rates are desireable. Consider two timers based on separate sample rates such as 44.1kHz and 12.34kHz. Since both of these rates are regular, that is they repeat at a constant rate, then a simple conversion function can be used to convert between the two rates. By converting one of the rates to the other a single timer can be used in the scheduler. However for other timers an errorless conversion function may not be possible. Consider a control rate based on detecting someone tapping a drum stick. The rate of tapping could be described as irregular because it is not known exactly when the next tap will happen. Combining this timer with the audio sample rate creates the problem that no perfect conversion function is possible that can compute what the sample time will be for N taps in the future. In Marsyas this problem is bypassed through the support of multiple timers. Events are therefore posted on the timers they are specified on and no timer conversion takes place.
An event is simply something that happens at some point in time. In Marsyas an event is a class that contains a user-defined function. What this function contains is up to the writer and can act on the Marsyas network or outside of it. Marsyas is not threaded and neither is the scheduler so the scheduler will wait for the event to complete its action before resuming. Be careful not to do excessive processing during the dispatch of an event.