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  }