Max 5 API Reference
00001 /** 00002 @page chapter_anatomy Anatomy of a Max Object 00003 00004 Max objects are written in the C language, and the Max API is C-based. You could use C++ but we don't support it at the API level. Writing a Max object in C, you have five basic tasks: 00005 00006 1) including the right header files (usually ext.h and ext_obex.h) 00007 00008 2) declaring a C structure for your object 00009 00010 3) writing an initialization routine called main that defines the class 00011 00012 4) writing a new instance routine that creates a new instance of the class, when someone makes one or types its name into an object box 00013 00014 5) writing methods (or message handlers) that implement the behavior of the object 00015 00016 Let's look at each of these in more detail. It's useful to open the <a href="simplemax_8c-source.html">simplemax example project</a> as we will be citing examples from it. 00017 00018 00019 @section chapter_anatomy_includes Include Files 00020 00021 Most of the basic Max API is included in the files ext.h and ext_obex.h. These are essentially required for any object. Beyond this there are specific include files for more specialized objects. 00022 00023 The header files are cross-platform. 00024 00025 - jpatcher_api.h is required for any Max UI objects 00026 - z_dsp.h is required for MSP audio objects 00027 00028 @code 00029 #include "ext.h" // should always be first, followed by ext_obex.h and any other files. 00030 @endcode 00031 00032 00033 @section chapter_anatomy_object_decl The Object Declaration 00034 00035 Basic Max objects are declared as C structures. The first element of the structure is a #t_object, followed by whatever you want. The example below has one long structure member. 00036 00037 @code 00038 typedef struct _simp 00039 { 00040 t_object s_obj; // t_object header 00041 long s_value; // something else 00042 } t_simp; 00043 @endcode 00044 00045 Your structure declaration will be used in the prototypes to functions you declare, so you'll need to place above these prototypes. 00046 00047 @section chapter_anatomy_object_init Initialization Routine 00048 00049 The initialization routine, which must be called main, is called when Max loads your object for the first time. In the initialization routine, you define one or more classes. Defining a class consists of the following: 00050 00051 1) telling Max about the size of your object's structure and how to create and destroy an instance 00052 2) defining methods that implement the object's behavior 00053 3) in some cases, defining attributes that describe the object's data 00054 4) registering the class in a name space 00055 00056 Here is the simp class example initialization routine: 00057 00058 @code 00059 static t_class *s_simp_class; // global pointer to our class definition that is setup in main() 00060 00061 int main() 00062 { 00063 t_class *c; 00064 00065 c = class_new("simp", (method)simp_new, (method)NULL, sizeof(t_simp), 0L, 0); 00066 class_addmethod(c, (method)simp_int, "int", A_LONG, 0); 00067 class_addmethod(c, (method)simp_bang, "bang", 0); 00068 00069 class_register(CLASS_BOX, c); 00070 00071 s_simp_class = c; 00072 00073 return 0; 00074 } 00075 @endcode 00076 00077 class_new() creates a class with the new instance routine (see below), a free function (in this case there isn't one, so we pass NULL), the size of the structure, a no-longer used argument, and then a description of the arguments you type when creating an instance (in this case, there are no arguments, so we pass 0). 00078 00079 class_addmethod() binds a C function to a text symbol. The two methods defined here are int and bang. 00080 00081 class_register() adds this class to the #CLASS_BOX name space, meaning that it will be searched when a user tries to type it into a box. 00082 00083 Finally, we assign the class we've created to a global variable so we can use it when creating new instances. 00084 00085 More complex classes will declare more methods. In many cases, you'll declare methods to implement certain API features. This is particularly true for UI objects. 00086 00087 00088 @section chapter_anatomy_object_new New Instance Routine 00089 00090 The standard new instance routine allocates the memory to create an instance of your class and then initializes this instance. It then returns a pointer to the newly created object. 00091 00092 Here is the simp new instance routine 00093 00094 @code 00095 void *simp_new() 00096 { 00097 t_simp *x = (t_simp *)object_alloc(s_simp_class); 00098 00099 x->s_value = 0; 00100 00101 return x; 00102 } 00103 @endcode 00104 00105 The first line uses the global variable s_simp_class we defined in the initialization routine to create a new instance of the class. Essentially, the instance is a block of memory of the size defined by the class, along with a pointer to the class that permits us to dispatch messages correctly. 00106 00107 The next line initializes our data. More complex objects will do a lot more here, such as creating inlets and outlets. By default, the object being created will appear with one inlet and no outlets. 00108 00109 Finally, in the last line, we return a pointer to the newly created instance. 00110 00111 00112 @section chapter_anatomy_object_mess_handlers Message Handlers 00113 00114 We are now ready to define some actual behavior for our object by writing C functions that will be called when our object is sent messages. For this simple example, we will write only two functions. simp_int will be called when our object receives numbers. It will store the received number in the s_value field. simp_bang will be called when our object receives a bang. It will print the value in the Max window. So, yes, this object is pretty useless! 00115 00116 The C functions you write will be declared according to the arguments the message requires. All functions are passed a pointer to your object as the first argument. For a function handling the int message, a single second argument that is a long is passed. For a function handling the bang message, no additional arguments are passed. 00117 00118 Here is the int method: 00119 00120 @code 00121 void simp_int(t_simp *x, long n) 00122 { 00123 x->s_value = n; 00124 } 00125 @endcode 00126 00127 This simply copies the value of the argument to the internal storage within the instance. 00128 00129 Here is the bang method: 00130 00131 @code 00132 void simp_bang(t_simp *x) 00133 { 00134 post("value is %ld",x->s_value); 00135 } 00136 @endcode 00137 00138 The post() function is similar to printf(), but puts the text in the Max window. post() is very helpful for debugging, particularly when you cannot stop user interaction or real-time computation to look at something in a debugger. 00139 00140 You can also add a float message, which is invoked when a floating-point number is sent to your object. Add the following to your initialization routine: 00141 00142 @code 00143 class_addmethod(c, (method)simp_float, "float", A_FLOAT, 0); 00144 @endcode 00145 00146 Then write the method that receives the floating-point value as follows: 00147 00148 @code 00149 void simp_float(t_simp *x, double f) 00150 { 00151 post("got a float and it is %.2f", f); 00152 } 00153 @endcode 00154 00155 */
Copyright © 2008, Cycling '74