github.com/256dpi/max-go@v0.7.0/max.c (about) 1 #include "max.h" 2 3 #include "_cgo_export.h" 4 5 /* Basic */ 6 7 void maxgo_log(char *str) { 8 post(str); 9 free(str); 10 } 11 12 void maxgo_error(char *str) { 13 error(str); 14 free(str); 15 } 16 17 void maxgo_alert(char *str) { 18 ouchstring(str); 19 free(str); 20 } 21 22 t_symbol *maxgo_gensym(char *str) { 23 t_symbol *sym = gensym(str); 24 free(str); 25 return sym; 26 } 27 28 /* Initialization */ 29 30 extern void ext_main(void *r) { maxgoMain(); } 31 32 /* Classes */ 33 34 static t_class *class = NULL; 35 36 typedef struct { 37 t_pxobject obj; 38 long inlet; 39 void **proxies; 40 int num_proxies; 41 int num_signals; 42 unsigned long long ref; 43 void *clock; 44 } t_bridge; 45 46 static void bridge_tick(void *ptr) { 47 // get bridge 48 t_bridge *bridge = (t_bridge *)ptr; 49 50 // handle all queued events 51 for (;;) { 52 // retrieve next event 53 struct maxgoPop_return ret = 54 maxgoPop(bridge->ref); // (unsafe.Pointer, C.maxgo_type_e, *C.t_symbol, int64, *C.t_atom, bool) 55 56 // check result 57 if (ret.r0 == NULL) { 58 return; 59 } 60 61 // call outlet 62 switch (ret.r1) { 63 case MAXGO_BANG: 64 outlet_bang(ret.r0); 65 break; 66 case MAXGO_INT: 67 outlet_int(ret.r0, atom_getlong(ret.r4)); 68 break; 69 case MAXGO_FLOAT: 70 outlet_float(ret.r0, atom_getfloat(ret.r4)); 71 break; 72 case MAXGO_LIST: 73 outlet_list(ret.r0, NULL, ret.r3, ret.r4); 74 break; 75 case MAXGO_ANY: 76 outlet_anything(ret.r0, ret.r2, ret.r3, ret.r4); 77 break; 78 case MAXGO_SIGNAL: 79 // not supported 80 break; 81 } 82 83 // free atoms 84 if (ret.r4 != NULL) { 85 freebytes(ret.r4, ret.r3 * sizeof(t_atom)); 86 } 87 88 // return if there are no more events 89 if (!ret.r5) { 90 return; 91 } 92 } 93 } 94 95 static void *bridge_new(t_symbol *name, long argc, t_atom *argv) { 96 // allocate bridge 97 t_bridge *bridge = object_alloc(class); 98 99 // initialize object 100 struct maxgoInit_return ret = maxgoInit(&bridge->obj, argc, argv); // ref, proxies, signals 101 102 // set reference 103 bridge->ref = ret.r0; 104 105 // check reference 106 if (bridge->ref == 0) { 107 return NULL; 108 } 109 110 // set number of signals 111 bridge->num_signals = ret.r2; 112 113 // setup dsp 114 if (bridge->num_signals > 0) { 115 dsp_setup(&bridge->obj, bridge->num_signals); 116 } 117 118 // save number of proxies 119 bridge->num_proxies = ret.r1; 120 121 // allocate proxy list 122 bridge->proxies = (void **)getbytes(bridge->num_proxies * sizeof(void *)); 123 124 // create proxies 125 for (int i = 0; i < bridge->num_proxies; i++) { 126 bridge->proxies[i] = proxy_new(&bridge->obj, bridge->num_proxies - i, &bridge->inlet); 127 } 128 129 // create clock 130 bridge->clock = clock_new(bridge, (method)bridge_tick); 131 132 return bridge; 133 } 134 135 static void bridge_bang(t_bridge *bridge) { 136 // get inlet 137 long inlet = proxy_getinlet(&bridge->obj.z_ob); 138 139 // handle message 140 maxgoHandle(bridge->ref, "bang", inlet, 0, NULL); 141 } 142 143 static void bridge_int(t_bridge *bridge, long n) { 144 // get inlet 145 long inlet = proxy_getinlet(&bridge->obj.z_ob); 146 147 // prepare args 148 t_atom args[1] = {0}; 149 atom_setlong(args, n); 150 151 // handle message 152 maxgoHandle(bridge->ref, "int", inlet, 1, args); 153 } 154 155 static void bridge_float(t_bridge *bridge, double n) { 156 // get inlet 157 long inlet = proxy_getinlet(&bridge->obj.z_ob); 158 159 // prepare args 160 t_atom args[1] = {0}; 161 atom_setfloat(args, n); 162 163 // handle message 164 maxgoHandle(bridge->ref, "float", inlet, 1, args); 165 } 166 167 static void bridge_gimme(t_bridge *bridge, t_symbol *msg, long argc, t_atom *argv) { 168 // get inlet 169 long inlet = proxy_getinlet(&bridge->obj.z_ob); 170 171 // handle message 172 maxgoHandle(bridge->ref, msg->s_name, inlet, argc, argv); 173 } 174 175 static void bridge_dsp_perform(t_bridge *bridge, t_object *dsp64, double **ins, long numIns, double **outs, 176 long numOuts, long samples, long flags, void *param) { 177 // process audio 178 maxgoProcess(bridge->ref, ins, outs, numIns, numOuts, samples); 179 } 180 181 static void bridge_dsp(t_bridge *bridge, t_object *dsp64, short *count, double sampleRate, long maxVectorSize, 182 long flags) { 183 // add dsp handler 184 object_method(dsp64, gensym("dsp_add64"), bridge, bridge_dsp_perform, 0, NULL); 185 } 186 187 static void bridge_loadbang(t_bridge *bridge) { 188 // handle message 189 maxgoHandle(bridge->ref, "loadbang", -1, 0, NULL); 190 } 191 192 static void bridge_dblclick(t_bridge *bridge) { 193 // handle message 194 maxgoHandle(bridge->ref, "dblclick", -1, 0, NULL); 195 } 196 197 static void bridge_assist(t_bridge *bridge, void *b, long io, long i, char *buf) { 198 // get info 199 struct maxgoDescribe_return ret = maxgoDescribe(bridge->ref, io, i); // (*C.char, bool) 200 201 // copy label 202 strncpy_zero(buf, ret.r0, 512); 203 204 // free string 205 free(ret.r0); 206 } 207 208 static void bridge_inletinfo(t_bridge *bridge, void *b, long i, char *v) { 209 // get info 210 struct maxgoDescribe_return ret = maxgoDescribe(bridge->ref, 1, i); // (*C.char, bool) 211 212 // set cold if not hot 213 if (!ret.r1) { 214 *v = 1; 215 } 216 217 // free string 218 free(ret.r0); 219 } 220 221 static void bridge_free(t_bridge *bridge) { 222 // free object 223 maxgoFree(bridge->ref); 224 225 // free dsp 226 dsp_free(&bridge->obj); 227 228 // free proxies 229 for (int i = 0; i < bridge->num_proxies; i++) { 230 object_free(bridge->proxies[i]); 231 } 232 233 // free list 234 freebytes(bridge->proxies, bridge->num_proxies * sizeof(void *)); 235 236 // free clock 237 clock_unset(bridge->clock); 238 freeobject((t_object *)bridge->clock); 239 } 240 241 void maxgo_init(char *name) { 242 // check class 243 if (class != NULL) { 244 error("class has already been initialized"); 245 return; 246 } 247 248 // create class 249 class = class_new(name, (method)bridge_new, (method)bridge_free, (long)sizeof(t_bridge), 0L, A_GIMME, 0); 250 251 // init dsp 252 class_dspinit(class); 253 254 // add generic methods 255 class_addmethod(class, (method)bridge_bang, "bang", 0); 256 class_addmethod(class, (method)bridge_int, "int", A_LONG, 0); 257 class_addmethod(class, (method)bridge_float, "float", A_FLOAT, 0); 258 class_addmethod(class, (method)bridge_gimme, "list", A_GIMME, 0); 259 class_addmethod(class, (method)bridge_gimme, "anything", A_GIMME, 0); 260 class_addmethod(class, (method)bridge_dsp, "dsp64", A_CANT, 0); 261 class_addmethod(class, (method)bridge_loadbang, "loadbang", 0); 262 class_addmethod(class, (method)bridge_dblclick, "dblclick", 0); 263 class_addmethod(class, (method)bridge_assist, "assist", A_CANT, 0); 264 class_addmethod(class, (method)bridge_inletinfo, "inletinfo", A_CANT, 0); 265 266 // register class 267 class_register(CLASS_BOX, class); 268 269 // free name 270 free(name); 271 } 272 273 void maxgo_notify(void *ptr) { 274 // get bridge 275 t_bridge *bridge = (t_bridge *)ptr; 276 277 // schedule clock 278 clock_delay(bridge->clock, 0); 279 } 280 281 /* Threads */ 282 283 void maxgo_yield(void *p, void *ref) { 284 // yield back 285 maxgoYield((unsigned long long)ref); 286 } 287 288 void maxgo_defer(unsigned long long ref) { 289 // defer function call 290 defer_low(NULL, (method)maxgo_yield, (void *)ref, 0, NULL); 291 }