Max 5 API Reference
00001 /** 00002 00003 @defgroup sched Timing 00004 00005 00006 */ 00007 00008 00009 /** 00010 @defgroup clocks Clocks 00011 @ingroup sched 00012 00013 Clock objects are your interface to Max’s scheduler. To use the 00014 scheduler, you create a new Clock object using clock_new in your 00015 instance creation function. You also have to write a clock function that 00016 will be executed when the clock goes off, declared as follows: 00017 00018 @code 00019 void myobject_tick (myobject *x); 00020 @endcode 00021 00022 The argument x is determined by the arg argument to clock_new(). 00023 Almost always it will be pointer to your object. 00024 Then, in one of your methods, use clock_delay() or clock_fdelay() to 00025 schedule yourself. If you want unschedule yourself, call 00026 clock_unset(). To find out what time it is now, use gettime() or 00027 clock_getftime(). More advanced clock operations are possible with 00028 the setclock object interface described in Chapter 9. We suggest you 00029 take advantage of the higher timing precision of the floating-point 00030 clock routines—all standard Max 4 timing objects such as metro use 00031 them. 00032 00033 When the user has Overdrive mode enabled, your clock function will 00034 execute at interrupt level. 00035 00036 00037 @section clocks_using_clocks Using Clocks 00038 00039 Under normal circumstances, gettime or clock_getftime will not 00040 be necessary for scheduling purposes if you use clock_delay or 00041 clock_fdelay, but it may be useful for recording the timing of 00042 messages or events. 00043 00044 As an example, here’s a fragment of how one might go about writing a 00045 metronome using the Max scheduler. First, here’s the data structure 00046 we’ll use. 00047 00048 @code 00049 typedef struct mymetro { 00050 t_object *m_obj; 00051 void *m_clock; 00052 double m_interval; 00053 void *m_outlet; 00054 } t_mymetro; 00055 @endcode 00056 00057 We’ll assume that the class has been initialized already. Here’s the 00058 instance creation function that will allocate a new Clock. 00059 00060 @code 00061 void *mymetro_create (double defaultInterval) 00062 { 00063 t_mymetro *x; 00064 x = (t_mymetro *)newobject(mymetro_class); // allocate space 00065 x->m_clock = clock_new(x,(method)mymetro_tick); // make a clock 00066 x->m_interval = defaultInterval; // store the interval 00067 x->m_outlet = bangout(x); // outlet for ticks 00068 return x; // return the new object 00069 } 00070 @endcode 00071 00072 Here’s the method written to respond to the bang message that starts 00073 the metronome. 00074 00075 @code 00076 void mymetro_bang (t_mymetro *x) 00077 { 00078 clock_fdelay(x->m_clock,0.); 00079 } 00080 @endcode 00081 00082 Here’s the Clock function. 00083 00084 @code 00085 void mymetro_tick(t_mymetro *x) 00086 { 00087 clock_fdelay(x->m_clock, x->m_interval); 00088 // schedule another metronome tick 00089 outlet_bang(x->m_outlet); // send out a bang 00090 } 00091 @endcode 00092 00093 You may also want to stop the metronome at some point. Here’s a 00094 method written to respond to the message stop. It uses clock_unset. 00095 00096 @code 00097 void mymetro_stop (t_mymetro *x) 00098 { 00099 clock_unset(x->m_clock); 00100 } 00101 @endcode 00102 00103 In your object’s free function, you should call freeobject on any 00104 Clocks you’ve created. 00105 00106 @code 00107 void mymetro_free (MyMetro *x) 00108 { 00109 freeobject((t_object *)x->m_clock); 00110 } 00111 @endcode 00112 00113 00114 @section setclock Scheduling with setclock Objects 00115 00116 The setclock object allows a more general way of scheduling Clocks by 00117 generalizing the advancement of the time associated with a scheduler. 00118 Each setclock object’s "time" can be changed by a process other than the 00119 internal millisecond clock. In addition, the object implements routines 00120 that modify the mapping of the internal millisecond clock onto the 00121 current value of time in an object. Your object can call a set of routines 00122 that use either setclock or the normal millisecond clock transparently. 00123 Many Max objects accept the message clock followed by an optional 00124 symbol to set their internal scheduling to a named setclock object. The 00125 typical implementation passes the binding of a Symbol (the s_thing 00126 field) to the Setclock functions. By default, the empty symbol is passed. 00127 If the binding has been linked to a setclock object, it will be used to 00128 schedule the Clock. Otherwise, the Clock is scheduled using the main 00129 internal millisecond scheduler. The Setclock data structure is a 00130 replacement for void * since there will be no reason for external 00131 objects to access it directly. 00132 00133 @subsection setclock_using_the_routines Using the setclock Object Routines 00134 00135 Here’s an example implementation of the relevant methods of a 00136 metronome object using the Setclock routines. 00137 00138 @code 00139 typedef struct metro 00140 { 00141 t_object m_ob; 00142 long m_interval; 00143 long m_running; 00144 void *m_clock; 00145 t_symbol *m_setclock; 00146 } t_metro; 00147 @endcode 00148 00149 Here’s the implementation of the routines for turning the metronome 00150 on and off. Assume that in the instance creation function, the 00151 #t_symbol m_setclock has been set to the empty symbol (gensym 00152 ("")) and m_clock has been created; the clock function 00153 metro_tick() is defined further on. 00154 00155 @code 00156 void metro_bang(Metro *x) // turn metronome on 00157 { 00158 x->m_running = 1; 00159 setclock_delay(x->m_setclock->s_thing,x->m_clock,0); 00160 } 00161 00162 void metro_stop(Metro *x) 00163 { 00164 x->m_running = 0; 00165 setclock_unset(x->m_setclock->s_thing,x->m_clock); 00166 } 00167 @endcode 00168 00169 Here is the implementation of the clock function metro_tick() that 00170 runs periodically. 00171 00172 @code 00173 void metro_tick(Metro *x) 00174 { 00175 outlet_bang(x->m_ob.o_outlet); 00176 if (x->m_running) 00177 setclock_delay(x->m_setclock->s_thing,x->m_clock,x->m_interval); 00178 } 00179 @endcode 00180 00181 Finally, here is an implementation of the method to respond to the 00182 clock message. Note that the function tries to verify that a non-zero 00183 value bound to the #t_symbol passed as an argument is in fact an 00184 instance of setclock by checking to see if it responds to the unset 00185 message. If not, the metronome refuses to assign the #t_symbol to its 00186 internal m_setclock field. 00187 00188 @code 00189 void metro_clock(Metro *x, t_symbol *s) 00190 { 00191 void *old = x->m_setclock->s_thing; 00192 void *c = 0; 00193 00194 // the line below can be restated as: 00195 // if s is the empty symbol 00196 // or s->s_thing is zero 00197 // or s->s_thing is non-zero and a setclock object 00198 if ((s == gensym("")) || ((c = s->s_thing) && zgetfn(c,&s_unset))) 00199 { 00200 if (old) 00201 setclock_unset(old,x->m_clock); 00202 x->m_setclock = s; 00203 if (x->m_running) 00204 setclock_delay(c,x->m_clock,0L); 00205 } 00206 } 00207 @endcode 00208 00209 00210 00211 @section creating_schedulers Creating Schedulers 00212 00213 If you want to schedule events independently of the time of the global 00214 Max scheduler, you can create your own scheduler with 00215 scheduler_new(). By calling scheduler_set() with the newly created 00216 scheduler, calls to clock_new() will create Clocks tied to your scheduler 00217 instead of Max’s global one. You can then control the time of the 00218 scheduler (using scheduler_settime()) as well as when it executes 00219 clock functions (using scheduler_run()). This is a more general 00220 facility than the setclock object routines, but unlike using the time 00221 from a setclock object to determine when a Clock function runs, once 00222 a Clock is tied to a scheduler. 00223 00224 */ 00225 00226 00227 00228 00229 /** 00230 @defgroup qelems Qelems 00231 @ingroup sched 00232 00233 Your object’s methods may be called at interrupt level. This happens 00234 when the user has Overdrive mode enabled and one of your methods is 00235 called, directly or indirectly, from a scheduler Clock function. This 00236 means that you cannot count on doing certain things—like drawing, 00237 asking the user what file they would like opened, or calling any 00238 Macintosh toolbox trap that allocates or purges memory—from within 00239 any method that responds to any message that could be sent directly 00240 from another Max object. The mechanism you’ll use to get around this 00241 limitation is the Qelem (queue element) structure. Qelems also allow 00242 processor-intensive tasks to be done at a lower priority than in an 00243 interrupt. As an example, drawing on the screen, especially in color, 00244 takes a long time in comparison with a task like sending MIDI data. 00245 00246 A Qelem works very much like a Clock. You create a new Qelem in 00247 your creation function with qelem_new and store a pointer to it in 00248 your object. Then you write a queue function, very much like the clock 00249 function (it takes the same single argument that will usually be a 00250 pointer to your object) that will be called when the Qelem has been set. 00251 You set the Qelem to run its function by calling qelem_set(). 00252 00253 Often you’ll want to use Qelems and Clocks together. For example, 00254 suppose you want to update the display for a counter that changes 20 00255 times a second. This can be accomplished by writing a Clock function 00256 that calls qelem_set() and then reschedules itself for 50 milliseconds 00257 later using the technique shown in the metronome example above. 00258 This scheme works even if you call qelem_set() faster than the 00259 computer can draw the counter, because if a Qelem is already set, 00260 qelem_set() will not set it again. However, when drawing the counter, 00261 you’ll display its current value, not a specific value generated in the 00262 Clock function. 00263 00264 Note that the Qelem-based defer mechanism discussed later in this 00265 chapter may be easier for lowering the priority of one-time events, 00266 such as opening a standard file dialog box in response to a read 00267 message. 00268 00269 If your Qelem routine sends messages using outlet_int() or any other 00270 of the outlet functions, it needs to use the lockout mechanism 00271 described in the Interrupt Level Considerations section. 00272 */ 00273 00274 00275 00276 00277 /** 00278 @defgroup systime Systime API 00279 @ingroup sched 00280 00281 The Systime API provides the means of getting the system time, 00282 instead of the scheduler time as you would with functions like gettime(). 00283 */ 00284 00285 00286 /** 00287 @defgroup time ITM Time Objects 00288 @ingroup sched 00289 00290 ITM Time Objects are a high-level interface to ITM, a tempo-based scheduler API. They provide an abtraction so your object can schedule events either in milliseconds (as traditional clock objects) or ticks (tempo-relative units). 00291 00292 */ 00293
Copyright © 2008, Cycling '74