Next: , Up: Using and Extending the Scheduler


9.6.1 Using the Scheduler

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.

9.6.1.1 Repeating Events

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.