Clocks

Clock objects are your interface to Max’s scheduler. More...

+ Collaboration diagram for Clocks:

Typedefs

typedef t_object t_clock
 A clock.
 

Functions

void * clock_new (void *obj, method fn)
 Create a new Clock object. More...
 
void clock_delay (void *x, long n)
 Schedule the execution of a Clock. More...
 
void clock_unset (void *x)
 Cancel the scheduled execution of a Clock. More...
 
void clock_fdelay (void *c, double time)
 Schedule the execution of a Clock using a floating-point argument. More...
 
void clock_getftime (double *time)
 Find out the current logical time of the scheduler in milliseconds as a floating-point number. More...
 
void setclock_delay (t_object *x, void *c, long time)
 Schedule a Clock on a scheduler. More...
 
void setclock_unset (t_object *x, void *c)
 Remove a Clock from a scheduler. More...
 
long setclock_gettime (t_object *x)
 Find out the current time value of a setclock object. More...
 
void setclock_fdelay (t_object *s, void *c, double time)
 Schedule a Clock on a scheduler, using a floating-point time argument. More...
 
void setclock_getftime (t_object *s, double *time)
 Find out the current time value of a setclock object in floating-point milliseconds. More...
 
double systimer_gettime (void)
 While most Max timing references "logical" time derived from Max's millisecond scheduler, time values produced by the systimer_gettime() are referenced from the CPU clock and can be used to time real world events with microsecond precision. More...
 
long gettime (void)
 Find out the current logical time of the scheduler in milliseconds. More...
 
double gettime_forobject (t_object *x)
 Find the correct scheduler for the object and return the current time in milliseconds. More...
 
void * scheduler_new (void)
 Create a new local scheduler. More...
 
void * scheduler_set (void *x)
 Make a scheduler current, so that future related calls (such as clock_delay()) will affect the appropriate scheduler. More...
 
void * scheduler_get ()
 Get the currently set scheduler. More...
 
void * scheduler_fromobject (t_object *o)
 Get the scheduler associated with a given object, if any. More...
 
void scheduler_run (void *x, double until)
 Run scheduler events to a selected time. More...
 
void scheduler_settime (void *x, double time)
 Set the current time of the scheduler. More...
 
void scheduler_gettime (void *x, double *time)
 Retrieve the current time of the selected scheduler. More...
 
void scheduler_shift (void *x, double amount)
 Shift scheduler's current time and run time for all pending clock. More...
 

Detailed Description

Clock objects are your interface to Max’s scheduler.

To use the scheduler, you create a new Clock object using clock_new in your instance creation function. You also have to write a clock function that will be executed when the clock goes off, declared as follows:

void myobject_tick (myobject *x);

The argument x is determined by the arg argument to clock_new(). Almost always it will be pointer to your object. Then, in one of your methods, use clock_delay() or clock_fdelay() to schedule yourself. If you want unschedule yourself, call clock_unset(). To find out what time it is now, use gettime() or clock_getftime(). More advanced clock operations are possible with the setclock object interface described in Chapter 9. We suggest you take advantage of the higher timing precision of the floating-point clock routines—all standard Max 4 timing objects such as metro use them.

When the user has Overdrive mode enabled, your clock function will execute at interrupt level.

Using Clocks

Under normal circumstances, gettime or clock_getftime will not be necessary for scheduling purposes if you use clock_delay or clock_fdelay, but it may be useful for recording the timing of messages or events.

As an example, here’s a fragment of how one might go about writing a metronome using the Max scheduler. First, here’s the data structure we’ll use.

typedef struct mymetro {
t_object *m_obj;
void *m_clock;
double m_interval;
void *m_outlet;
} t_mymetro;

We’ll assume that the class has been initialized already. Here’s the instance creation function that will allocate a new Clock.

void *mymetro_create (double defaultInterval)
{
t_mymetro *x;
x = (t_mymetro *)newobject(mymetro_class); // allocate space
x->m_clock = clock_new(x,(method)mymetro_tick); // make a clock
x->m_interval = defaultInterval; // store the interval
x->m_outlet = bangout(x); // outlet for ticks
return x; // return the new object
}

Here’s the method written to respond to the bang message that starts the metronome.

void mymetro_bang (t_mymetro *x)
{
clock_fdelay(x->m_clock,0.);
}

Here’s the Clock function.

void mymetro_tick(t_mymetro *x)
{
clock_fdelay(x->m_clock, x->m_interval);
// schedule another metronome tick
outlet_bang(x->m_outlet); // send out a bang
}

You may also want to stop the metronome at some point. Here’s a method written to respond to the message stop. It uses clock_unset.

void mymetro_stop (t_mymetro *x)
{
clock_unset(x->m_clock);
}

In your object’s free function, you should call freeobject on any Clocks you’ve created.

void mymetro_free (MyMetro *x)
{
freeobject((t_object *)x->m_clock);
}

Scheduling with setclock Objects

The setclock object allows a more general way of scheduling Clocks by generalizing the advancement of the time associated with a scheduler. Each setclock object’s "time" can be changed by a process other than the internal millisecond clock. In addition, the object implements routines that modify the mapping of the internal millisecond clock onto the current value of time in an object. Your object can call a set of routines that use either setclock or the normal millisecond clock transparently. Many Max objects accept the message clock followed by an optional symbol to set their internal scheduling to a named setclock object. The typical implementation passes the binding of a Symbol (the s_thing field) to the Setclock functions. By default, the empty symbol is passed. If the binding has been linked to a setclock object, it will be used to schedule the Clock. Otherwise, the Clock is scheduled using the main internal millisecond scheduler. The Setclock data structure is a replacement for void * since there will be no reason for external objects to access it directly.

Using the setclock Object Routines

Here’s an example implementation of the relevant methods of a metronome object using the Setclock routines.

typedef struct metro
{
t_object m_ob;
long m_interval;
long m_running;
void *m_clock;
t_symbol *m_setclock;
} t_metro;

Here’s the implementation of the routines for turning the metronome on and off. Assume that in the instance creation function, the t_symbol m_setclock has been set to the empty symbol (gensym ("")) and m_clock has been created; the clock function metro_tick() is defined further on.

void metro_bang(Metro *x) // turn metronome on
{
x->m_running = 1;
setclock_delay(x->m_setclock->s_thing,x->m_clock,0);
}
void metro_stop(Metro *x)
{
x->m_running = 0;
setclock_unset(x->m_setclock->s_thing,x->m_clock);
}

Here is the implementation of the clock function metro_tick() that runs periodically.

void metro_tick(Metro *x)
{
outlet_bang(x->m_ob.o_outlet);
if (x->m_running)
setclock_delay(x->m_setclock->s_thing,x->m_clock,x->m_interval);
}

Finally, here is an implementation of the method to respond to the clock message. Note that the function tries to verify that a non-zero value bound to the t_symbol passed as an argument is in fact an instance of setclock by checking to see if it responds to the unset message. If not, the metronome refuses to assign the t_symbol to its internal m_setclock field.

void metro_clock(Metro *x, t_symbol *s)
{
void *old = x->m_setclock->s_thing;
void *c = 0;
// the line below can be restated as:
// if s is the empty symbol
// or s->s_thing is zero
// or s->s_thing is non-zero and a setclock object
if ((s == gensym("")) || ((c = s->s_thing) && zgetfn(c,&s_unset)))
{
if (old)
setclock_unset(old,x->m_clock);
x->m_setclock = s;
if (x->m_running)
setclock_delay(c,x->m_clock,0L);
}
}

Creating Schedulers

If you want to schedule events independently of the time of the global Max scheduler, you can create your own scheduler with scheduler_new(). By calling scheduler_set() with the newly created scheduler, calls to clock_new() will create Clocks tied to your scheduler instead of Max’s global one. You can then control the time of the scheduler (using scheduler_settime()) as well as when it executes clock functions (using scheduler_run()). This is a more general facility than the setclock object routines, but unlike using the time from a setclock object to determine when a Clock function runs, once a Clock is tied to a scheduler.

Function Documentation

void clock_delay ( void *  x,
long  n 
)

Schedule the execution of a Clock.

clock_delay() sets a clock to go off at a certain number of milliseconds from the current logical time.

Parameters
xClock to schedule.
nDelay, in milliseconds, before the Clock will execute.
See also
clock_fdelay()
void clock_fdelay ( void *  c,
double  time 
)

Schedule the execution of a Clock using a floating-point argument.

clock_delay() sets a clock to go off at a certain number of milliseconds from the current logical time.

Parameters
cClock to schedule.
timeDelay, in milliseconds, before the Clock will execute.
See also
clock_delay()
void clock_getftime ( double *  time)

Find out the current logical time of the scheduler in milliseconds as a floating-point number.

Parameters
timeReturns the current time.
See also
gettime()
setclock_getftime()
setclock_gettime()
void* clock_new ( void *  obj,
method  fn 
)

Create a new Clock object.

Normally, clock_new() is called in your instance creation function—and it cannot be called from a thread other than the main thread. To get rid of a clock object you created, use freeobject().

Parameters
objArgument that will be passed to clock function fn when it is called. This will almost always be a pointer to your object.
fnFunction to be called when the clock goes off, declared to take a single argument as shown in Using Clocks.
Returns
A pointer to a newly created Clock object.
void clock_unset ( void *  x)

Cancel the scheduled execution of a Clock.

clock_unset() will do nothing (and not complain) if the Clock passed to it has not been set.

Parameters
xClock to cancel.
long gettime ( void  )

Find out the current logical time of the scheduler in milliseconds.

Returns
Returns the current time.
See also
clock_getftime()
double gettime_forobject ( t_object x)

Find the correct scheduler for the object and return the current time in milliseconds.

Returns
Returns the current time.
See also
clock_getftime()
void* scheduler_fromobject ( t_object o)

Get the scheduler associated with a given object, if any.

Parameters
oThe object who's scheduler is to be returned.
Returns
This routine returns a pointer to the scheduler or the passed in object,
See also
Creating Schedulers
void* scheduler_get ( )

Get the currently set scheduler.

Returns
This routine returns a pointer to the current scheduler,
See also
Creating Schedulers
void scheduler_gettime ( void *  x,
double *  time 
)

Retrieve the current time of the selected scheduler.

Parameters
xThe scheduler to query.
timeThe current time of the selected scheduler.
See also
Creating Schedulers
void* scheduler_new ( void  )

Create a new local scheduler.

Returns
A pointer to the newly created scheduler.
See also
Creating Schedulers
void scheduler_run ( void *  x,
double  until 
)

Run scheduler events to a selected time.

Parameters
xThe scheduler to advance.
untilThe ending time for this run (in milliseconds).
See also
Creating Schedulers
void* scheduler_set ( void *  x)

Make a scheduler current, so that future related calls (such as clock_delay()) will affect the appropriate scheduler.

Parameters
xThe scheduler to make current.
Returns
This routine returns a pointer to the previously current scheduler, saved and restored when local scheduling is complete.
See also
Creating Schedulers
void scheduler_settime ( void *  x,
double  time 
)

Set the current time of the scheduler.

Parameters
xThe scheduler to set.
timeThe new current time for the selected scheduler (in milliseconds).
See also
Creating Schedulers
void scheduler_shift ( void *  x,
double  amount 
)

Shift scheduler's current time and run time for all pending clock.

Could be used to change scheduler's time reference without impacting current clocks.

Parameters
xThe scheduler to affect.
amountNumber of milliseconds to shift by.
See also
Creating Schedulers
void setclock_delay ( t_object x,
void *  c,
long  time 
)

Schedule a Clock on a scheduler.

Schedules the Clock c to execute at time units after the current time. If scheduler x is 0 or does not point to a setclock object, the internal millisecond scheduler is used. Otherwise c is scheduled on the setclock object's list of Clocks. The Clock should be created with clock_new(), the same as for a Clock passed to clock_delay().

Parameters
xA setclock object to be used for scheduling this clock.
cClock object containing the function to be executed.
timeTime delay (in the units of the Setclock) from the current time when the Clock will be executed.
See also
Scheduling with setclock Objects
setclock_fdelay()
void setclock_fdelay ( t_object s,
void *  c,
double  time 
)

Schedule a Clock on a scheduler, using a floating-point time argument.

Parameters
sA setclock object to be used for scheduling this clock.
cClock object containing the function to be executed.
timeTime delay (in the units of the Setclock) from the current time when the Clock will be executed.
See also
Scheduling with setclock Objects
setclock_delay()
void setclock_getftime ( t_object s,
double *  time 
)

Find out the current time value of a setclock object in floating-point milliseconds.

Parameters
sA setclock object.
timeThe current time in milliseconds.
See also
Scheduling with setclock Objects
setclock_gettime()
long setclock_gettime ( t_object x)

Find out the current time value of a setclock object.

Parameters
xA setclock object.
Returns
Returns the current time value of the setclock object scheduler. If scheduler is 0, setclock_gettime is equivalent to the function gettime that returns the current value of the internal millisecond clock.
See also
Scheduling with setclock Objects
setclock_getftime()
void setclock_unset ( t_object x,
void *  c 
)

Remove a Clock from a scheduler.

This function unschedules the Clock c in the list of Clocks in the setclock object x, or the internal millisecond scheduler if scheduler is 0.

Parameters
xThe setclock object that was used to schedule this clock. If 0, the clock is unscheduled from the internal millisecond scheduler.
cClock object to be removed from the scheduler.
See also
Scheduling with setclock Objects
double systimer_gettime ( void  )

While most Max timing references "logical" time derived from Max's millisecond scheduler, time values produced by the systimer_gettime() are referenced from the CPU clock and can be used to time real world events with microsecond precision.

The standard 'cpuclock' external in Max is a simple wrapper around this function.

Returns
Returns the current real-world time.
  Copyright © 2015, Cycling '74