// // Programmer: Ichiro Fujinaga (ich@music.mcgill.ca) // Modified by: Craig Stuart Sapp (craig@ccrma.stanford.edu) // Creation Date: Sat Mar 8 04:33:15 PST 2003 // Last Modified: Sat Mar 8 04:45:37 PST 2003 // Filename: ichmetro.c // Source: David Zicarelli: Writing External Objects for Max // 4.0 and MSP 2.0, revision 11 (2001), pages 55-56 // Web Address: http://peabody.sapp.org/class/dmp2/lab/mymetro/ichmetro.c // Syntax: C; Max4/MSP2 External Object; CodeWarrior 6.0 // OS: Mac OS 9; PPC // // Description: Demonstration of event scheduling. // #include "ext.h" #define DEFAULT_INTERVAL 1000 #define MIN_INTERVAL 40 typedef struct { t_object max_data; // must always be the first field; used by Max void* clock; // clock data structure pointer long duration; // duration between metronome ticks void* bangOutput; // pointer to outlet, need one for each outlet void* timeOutput; // pointer to outlet, need one for each outlet } MyObject; void* object_data; // pointer to data for object (created in setup()); // function declarations: void main (void); void* create_object (float defaultDuration); void destroy_object (MyObject *mo); void InputBang (MyObject *mo); void InputDuration (MyObject *mo, long value); void ClockFunction (MyObject *mo); void MessageStop (MyObject *mo); ////////////////////////////////////////////////////////////////////////// // // Initialization functions: // void main(void) { setup((t_messlist**)&object_data, (method)create_object, (method)destroy_object, (short)sizeof(MyObject), NULL, A_DEFFLOAT, A_NOTHING); addbang((method)InputBang); addinx((method)InputDuration, 1); addmess((method)MessageStop, "stop", A_NOTHING); finder_addclass("All Object", "ichmetro"); } ////////////////////////////// // // create_object -- // void* create_object(float defaultInterval) { MyObject *mo = (MyObject*)newobject(object_data); if (defaultInterval > MIN_INTERVAL) { mo->duration = defaultInterval; post("ichmetro tempo set to %ld", defaultInterval); } else { mo->duration = DEFAULT_INTERVAL; post("ichmetro set to default tempo of %ld ms", DEFAULT_INTERVAL); } mo->clock = clock_new(mo, (method)ClockFunction); mo->timeOutput = bangout(mo); mo->bangOutput = bangout(mo); intin(mo, 1); return mo; } ////////////////////////////// // // destroy_object -- what to do when the object is deleted from the patch. // In this case, you must free the clock object. // void destroy_object(MyObject *mo) { clock_unset(mo->clock); // remove clock routine from scheduler clock_free(mo->clock); // also can use: freeobject((t_object*)mo->clock); } ////////////////////////////////////////////////////////////////////////// // // Behavior functions: // ////////////////////////////// // // InputBang -- What to do when a bang message arrives into the object: // if a bang is received from the object input, then send out a bang. // void InputBang(MyObject* mo) { long time = gettime(); clock_delay(mo->clock, 0); // set clock to go off now post("clock started at %ld", time); } ////////////////////////////// // // InputDuration -- input the duration between metronome ticks. // void InputDuration(MyObject* mo, long value) { if (value < MIN_INTERVAL) { mo->duration = MIN_INTERVAL; } else { mo->duration = value; } post("metronome duration changed to %ld", mo->duration); } ////////////////////////////// // // ClockFunction -- called when clock coes off. // void ClockFunction(MyObject *mo) { long time = gettime(); clock_delay(mo->clock, mo->duration); // schedule another metronome tick outlet_int(mo->timeOutput, mo->duration); // send out a time message outlet_bang(mo->bangOutput); // send out a bang message post("ClockFunction called at time %ld", time); } ////////////////////////////// // // MessageStop -- what to do when a "stop" message arrives // void MessageStop(MyObject *mo) { long time = gettime(); clock_unset(mo->clock); outlet_int(mo->timeOutput, time); post("metronome stopped at %ld", time); }