Max 5 API Reference
00001 /** 00002 @file 00003 pictmeter~ - audio meter that works by resizing an image 00004 00005 @ingroup examples 00006 */ 00007 00008 #include "ext.h" // standard Max include, always required 00009 #include "ext_obex.h" // required for new style Max object 00010 #include "jpatcher_api.h" 00011 #include "jgraphics.h" 00012 #include "z_dsp.h" // should be after jpatcher_api.h 00013 #include "ext_drag.h" 00014 00015 typedef struct _pictmeter 00016 { 00017 t_pxjbox p_obj; 00018 t_jsurface *p_surface; 00019 void *p_clock; 00020 double p_value; 00021 double p_max; 00022 char p_startclock; 00023 } t_pictmeter; 00024 00025 void *pictmeter_new(t_symbol *s, long argc, t_atom *argv); 00026 void pictmeter_free(t_pictmeter *x); 00027 void pictmeter_assist(t_pictmeter *x, void *b, long m, long a, char *s); 00028 void pictmeter_paint(t_pictmeter *x, t_object *patcherview); 00029 void pictmeter_read(t_pictmeter *x, t_symbol *s); 00030 void pictmeter_doread(t_pictmeter *x, t_symbol *s, long argc, t_atom *argv); 00031 long pictmeter_acceptsdrag_unlocked(t_pictmeter *x, t_object *drag, t_object *view); 00032 void pictmeter_dsp(t_pictmeter *x, t_signal **sp, short *count); 00033 t_int *pictmeter_perform(t_int *w); 00034 void pictmeter_tick(t_pictmeter *x); 00035 void pictmeter_free(t_pictmeter *x); 00036 void *pictmeter_new(t_symbol *s, long argc, t_atom *argv); 00037 00038 static t_class *s_pictmeter_class; 00039 00040 int main(void) 00041 { 00042 t_class *c; 00043 00044 c = class_new("pictmeter~", (method)pictmeter_new, (method)pictmeter_free, sizeof(t_pictmeter), 0L, A_GIMME, 0); 00045 00046 c->c_flags |= CLASS_FLAG_NEWDICTIONARY; 00047 jbox_initclass(c, 0); 00048 class_dspinitjbox(c); 00049 00050 class_addmethod(c, (method)pictmeter_dsp, "dsp", A_CANT, 0); 00051 class_addmethod(c, (method)pictmeter_paint, "paint", A_CANT, 0); 00052 class_addmethod(c, (method)pictmeter_assist, "assist", A_CANT, 0); 00053 class_addmethod(c, (method)pictmeter_acceptsdrag_unlocked, "acceptsdrag_unlocked", A_CANT, 0); 00054 class_addmethod(c, (method)pictmeter_acceptsdrag_unlocked, "acceptsdrag_locked", A_CANT, 0); 00055 class_addmethod(c, (method)pictmeter_read, "read", A_DEFSYM, 0); 00056 00057 CLASS_ATTR_DEFAULT(c,"patching_rect",0, "0. 0. 128. 128."); 00058 00059 class_register(CLASS_BOX, c); 00060 s_pictmeter_class = c; 00061 return 0; 00062 } 00063 00064 void pictmeter_assist(t_pictmeter *x, void *b, long m, long a, char *s) 00065 { 00066 if (m == ASSIST_INLET) //inlet 00067 sprintf(s, "(signal) Audio Input"); 00068 } 00069 00070 void pictmeter_paint(t_pictmeter *x, t_object *patcherview) 00071 { 00072 t_rect src, dst, rect; 00073 t_jgraphics *g = (t_jgraphics*) patcherview_get_jgraphics(patcherview); // obtain graphics context 00074 jbox_get_rect_for_view((t_object *)x, patcherview, &rect); 00075 00076 if (!x->p_surface) 00077 return; 00078 00079 // draw if the value is non zero 00080 if (x->p_value) { 00081 src.width = jgraphics_image_surface_get_width(x->p_surface); 00082 src.height = jgraphics_image_surface_get_height(x->p_surface); 00083 src.x = 0; 00084 src.y = 0; 00085 dst.width = rect.width * x->p_value; 00086 dst.height = rect.height * x->p_value; 00087 if (dst.width < 1 || dst.height < 1) 00088 return; 00089 dst.x = 0 + ((rect.width * 0.5) - (dst.width * 0.5)); 00090 dst.y = 0 + ((rect.height * 0.5) - (dst.height * 0.5)); 00091 00092 jgraphics_image_surface_draw(g, x->p_surface, src, dst); 00093 } 00094 } 00095 00096 void pictmeter_read(t_pictmeter *x, t_symbol *s) 00097 { 00098 defer((t_object *)x, (method)pictmeter_doread, s, 0, NULL); 00099 } 00100 00101 void pictmeter_doread(t_pictmeter *x, t_symbol *s, long argc, t_atom *argv) 00102 { 00103 char filename[MAX_PATH_CHARS]; 00104 long *type,ntype,outtype; 00105 t_max_err err; 00106 char alloc; 00107 short path; 00108 t_jsurface *surface; 00109 00110 jgraphics_getfiletypes(x, &ntype, &type, &alloc); 00111 if (s == gensym("")) { 00112 err = open_dialog(filename, &path,(void *)&outtype, (void *)type, ntype); 00113 if (err) 00114 return; 00115 } else { 00116 strcpy(filename,s->s_name); 00117 err = locatefile_extended(filename, &path, &outtype, type, ntype); 00118 if (err) 00119 return; 00120 } 00121 surface = jgraphics_image_surface_create_referenced(filename, path); 00122 if (surface) 00123 x->p_surface = surface; 00124 if (alloc) 00125 sysmem_freeptr((char *)type); 00126 } 00127 00128 long pictmeter_acceptsdrag_unlocked(t_pictmeter *x, t_object *drag, t_object *view) 00129 { 00130 if (jdrag_matchdragrole(drag, gensym("imagefile"), 0)) { 00131 jdrag_box_add(drag, (t_object *)x, gensym("read")); 00132 return true; 00133 } 00134 return false; 00135 } 00136 00137 void pictmeter_dsp(t_pictmeter *x, t_signal **sp, short *count) 00138 { 00139 x->p_value = 0.; 00140 x->p_max = 0.; 00141 // only put perf func on dsp chain if sig is connected 00142 if (count[0]) { 00143 dsp_add(pictmeter_perform, 3, x, sp[0]->s_vec, sp[0]->s_n); 00144 x->p_startclock = true; 00145 } 00146 } 00147 00148 t_int *pictmeter_perform(t_int *w) 00149 { 00150 t_pictmeter *x = (t_pictmeter *)(w[1]); 00151 t_float *in = (t_float *)(w[2]); 00152 int n = (int)(w[3]); 00153 double xn, max; 00154 00155 if (x->p_obj.z_disabled) 00156 goto out; 00157 00158 max = x->p_max; 00159 00160 while (n--) { 00161 xn = *in++; 00162 if (xn < 0) 00163 xn = -xn; 00164 if (xn > max) 00165 max = xn; 00166 } 00167 x->p_max = max; 00168 00169 if (x->p_startclock) { 00170 x->p_startclock = 0; 00171 clock_delay(x->p_clock,0); 00172 } 00173 out: 00174 return w + 4; 00175 } 00176 00177 void pictmeter_tick(t_pictmeter *x) 00178 { 00179 // for the astute student of the Max SDK: 00180 // 00181 // this method is called by the scheduler thread 00182 // x->p_max is also accessed by the perform method in the audio thread 00183 // we could use a mutex or critical region to protect the following block of code from having the value of x->p_max modified during its execution. 00184 // however, mutexes and critical regions carry a performance penalty. 00185 // 00186 // in this case, due to the nature of what we are doing (drawing something every tenth of second showing the history of the previous samples), 00187 // the mutex or critical region will not add anything to the object, or protect us from crashes, and it carries a performance penalty. 00188 // so we have made a conscious decision to not use the aforementioned thread locking mechanisms. 00189 00190 if (x->p_value != x->p_max) { 00191 x->p_value = x->p_max; 00192 if (x->p_value > 1.) 00193 x->p_value = 1.; 00194 x->p_max = 0; 00195 jbox_redraw((t_jbox *)x); 00196 } 00197 00198 if (sys_getdspstate()) // if the dsp is still on, schedule a next pictmeter_tick() call 00199 clock_fdelay(x->p_clock, 100); 00200 } 00201 00202 void pictmeter_free(t_pictmeter *x) 00203 { 00204 dsp_freejbox((t_pxjbox *)x); 00205 freeobject((t_object *)x->p_clock); 00206 jbox_free((t_jbox *)x); 00207 } 00208 00209 void *pictmeter_new(t_symbol *s, long argc, t_atom *argv) 00210 { 00211 t_pictmeter *x = NULL; 00212 t_dictionary *d=NULL; 00213 long boxflags; 00214 00215 if (!(d=object_dictionaryarg(argc,argv))) 00216 return NULL; 00217 00218 x = (t_pictmeter *)object_alloc(s_pictmeter_class); 00219 boxflags = 0 00220 | JBOX_DRAWFIRSTIN 00221 | JBOX_NODRAWBOX 00222 | JBOX_DRAWINLAST 00223 | JBOX_TRANSPARENT 00224 // | JBOX_NOGROW 00225 // | JBOX_GROWY 00226 | JBOX_GROWBOTH 00227 // | JBOX_HILITE 00228 // | JBOX_BACKGROUND 00229 // | JBOX_DRAWBACKGROUND 00230 // | JBOX_NOFLOATINSPECTOR 00231 // | JBOX_TEXTFIELD 00232 // | JBOX_MOUSEDRAGDELTA 00233 // | JBOX_TEXTFIELD 00234 ; 00235 00236 jbox_new((t_jbox *)x, boxflags, argc, argv); 00237 x->p_obj.z_box.b_firstin = (void *)x; 00238 dsp_setupjbox((t_pxjbox *)x,1); 00239 x->p_clock = clock_new(x,(method)pictmeter_tick); 00240 x->p_value = x->p_max = 0; 00241 x->p_startclock = false; 00242 jbox_ready((t_jbox *)x); 00243 return x; 00244 }
Copyright © 2008, Cycling '74