In the example below an event is created and posted to the network to set the
gain control to 0 (silence) two seconds after the network starts processing.
This is accomplished by creating a new EvValUpd event which performs a
setctrl call when dispatched.
The EvValUpd event requires a MarSystem pointer to
act on - we use the topmost series object because we have a pointer to
it. The event also requires a control path referenced to the supplied MarSystem
pointer. Finally, it requires a MarControlValue to set the control value to on
dispatch. This value should have the same type as the one specified in the
control path otherwise the Marsyas system will report an error at dispatch
time.
To post the event to a timer the MarSystem updctrl call is used. The
first parameter to updctrl is the dispatch time. This indicates a
scheduled event call to the MarSystem and it is passed on to the scheduler.
In this case the TmTime class is supplied the name of the timer that the
event is to be posted on along with the time of event dispatch. The default
timer for every MarSystem is a TmSampleCount timer, which counts the
number of samples processed, with the name Virtual. The TmSampleCount timer
understands the units us, ms, s, m, h corresponding to microseconds,
milliseconds, seconds, minutes, hours, respectively. The supplied time is
converted to samples by calling the static method
mrs_natural Marsyas::time2samples(string time, mrs_real srate)
in the Conversions.cpp.
MarSystemManager mng;
MarSystem* series = mng.create("Series", "series");
series->addMarSystem(mng.create("SineSource", "src"));
series->addMarSystem(mng.create("Gain", "g"));
series->addMarSystem(mng.create("AudioSink", "snk"));
series->updctrl("AudioSink/snk/mrs_bool/initAudio", true);
series->updctrl("SineSource/src/mrs_real/frequency",440.0);
series->updctrl("Gain/g/mrs_real/gain",1.0);
EvValUpd* ev = new EvValUpd(series,"Gain/g/mrs_real/gain",0.0);
series->updctrl(TmTime("TmSampleCount/Virtual","2s"),ev);
while(true) series->tick();
Figure 9.1: Program using the scheduler to set gain to 0 after two seconds.
We can repeat events using the event set_repeat method of the event. This
method takes a Repeat value which is essentially a (rate,count) tuple. In
the example below, two events are posted. One sets the volume to 0, the other to
1. By staggering their dispatch we can achieve a gating effect. Here we repeat
the events forever by specifying the repeat rate only as in Repeat("1s").
To specify a finite repeat count we could set the repeat count to five as in
Repeat("1s",5). Gaze wonderously at the example.
MarSystemManager mng;
MarSystem* series = mng.create("Series", "series");
series->addMarSystem(mng.create("SineSource", "src"));
series->addMarSystem(mng.create("Gain", "g"));
series->addMarSystem(mng.create("AudioSink", "snk"));
series->updctrl("AudioSink/snk/mrs_bool/initAudio", true);
series->updctrl("SineSource/src/mrs_real/frequency",440.0);
series->updctrl("Gain/g/mrs_real/gain",1.0);
EvValUpd* ev_off = new EvValUpd(series,"Gain/g/mrs_real/gain",0.0);
ev_off->set_repeat(Repeat("1s")); // repeat forever
//ev_off->set_repeat(Repeat("1s",4)); // repeat four times
EvValUpd* ev_on = new EvValUpd(series,"Gain/g/mrs_real/gain",1.0);
ev_on->set_repeat(Repeat("1s"));
// stagger the dispatch of the events, off by 1 second
series->updctrl(TmTime("TmSampleCount/Virtual","1s"),ev_off);
series->updctrl(TmTime("TmSampleCount/Virtual","2s"),ev_on);
while(true) series->tick();
Figure 9.2: Program using two events that toggle the gain between 0 and 1 every second.
But how does this work under the hood, uhh, so to speak, you ask. For a pending
event (whose time is now), the scheduler will remove it from the queue, call its
dispatch method, check whether it should be repeated by calling its repeat
method. If it is to be repeated, the rate will be read by calling the
repeat_interval() method which reads the rate from the Repeat
value originally supplied through the set_repeat method. A calculation of
the next dispatch time is made and the event is reposted to the queue. See the
void TmTimer::dispatch() method of TmTimer.cpp for the exact
method.