PageRenderTime 63ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/mapper/mapper.c

https://github.com/malloch/mapper-max-pd
C | 1157 lines | 967 code | 99 blank | 91 comment | 323 complexity | ab042959623972cb281c8c30f1263b0c MD5 | raw file
Possible License(s): LGPL-2.1
  1. //
  2. // mapper.c
  3. // a maxmsp and puredata external encapsulating the functionality of libmapper
  4. // http://www.idmil.org/software/libmapper
  5. // Joseph Malloch, IDMIL 2010
  6. //
  7. // This software was written in the Input Devices and Music Interaction
  8. // Laboratory at McGill University in Montreal, and is copyright those
  9. // found in the AUTHORS file. It is licensed under the GNU Lesser Public
  10. // General License version 2.1 or later. Please see COPYING for details.
  11. //
  12. // *********************************************************
  13. // -(Includes)----------------------------------------------
  14. #ifdef WIN32
  15. #define _WINSOCKAPI_ //for winsock1/2 conflicts
  16. #endif
  17. #ifdef MAXMSP
  18. #include "ext.h" // standard Max include, always required
  19. #include "ext_obex.h" // required for new style Max object
  20. #include "ext_critical.h"
  21. #include "ext_dictionary.h"
  22. #include "jpatcher_api.h"
  23. #else
  24. #include "m_pd.h"
  25. #define A_SYM A_SYMBOL
  26. #endif
  27. #include <mapper/mapper.h>
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <math.h>
  32. #ifndef WIN32
  33. #include <arpa/inet.h>
  34. #include <unistd.h>
  35. #endif
  36. #define INTERVAL 1
  37. #define MAX_LIST 256
  38. #ifdef MAXMSP
  39. #define POST(x, ...) { object_post((t_object *)x, __VA_ARGS__); }
  40. #else
  41. #define POST(x, ...) { post(__VA_ARGS__); }
  42. #endif
  43. // *********************************************************
  44. // -(object struct)-----------------------------------------
  45. typedef struct _mapper
  46. {
  47. t_object ob;
  48. #ifdef WIN32
  49. #ifdef PD
  50. int pad; /* protect the object against observed writing beyond
  51. the bounds of t_object on Windows versions of PureData. */
  52. #endif
  53. #endif
  54. void *outlet1;
  55. void *outlet2;
  56. void *clock; // pointer to clock object
  57. char *name;
  58. mpr_graph graph;
  59. mpr_dev device;
  60. mpr_time timetag;
  61. int updated;
  62. int ready;
  63. int learn_mode;
  64. union {
  65. t_atom atoms[MAX_LIST];
  66. int ints[MAX_LIST];
  67. float floats[MAX_LIST];
  68. } buffer;
  69. char *definition;
  70. #ifdef MAXMSP
  71. t_dictionary *d;
  72. #endif
  73. } t_mapper;
  74. // *********************************************************
  75. // -(function prototypes)-----------------------------------
  76. static void *mapperobj_new(t_symbol *s, int argc, t_atom *argv);
  77. static void mapperobj_free(t_mapper *x);
  78. static void mapperobj_anything(t_mapper *x, t_symbol *s, int argc, t_atom *argv);
  79. static void mapperobj_add_signal(t_mapper *x, t_symbol *s, int argc, t_atom *argv);
  80. static void mapperobj_remove_signal(t_mapper *x, t_symbol *s, int argc, t_atom *argv);
  81. static void mapperobj_clear_signals(t_mapper *x, t_symbol *s, int argc, t_atom *argv);
  82. static void mapperobj_poll(t_mapper *x);
  83. static void mapperobj_sig_handler(mpr_sig sig, mpr_sig_evt evt, mpr_id inst,
  84. int len, mpr_type type, const void *val,
  85. mpr_time time);
  86. static void mapperobj_print_properties(t_mapper *x);
  87. static void mapperobj_learn(t_mapper *x, t_symbol *s, int argc, t_atom *argv);
  88. static void mapperobj_set(t_mapper *x, t_symbol *s, int argc, t_atom *argv);
  89. #ifdef MAXMSP
  90. void mapperobj_assist(t_mapper *x, void *b, long m, long a, char *s);
  91. static void mapperobj_register_signals(t_mapper *x);
  92. static void mapperobj_read_definition(t_mapper *x);
  93. #endif
  94. static int maxpd_atom_strcmp(t_atom *a, const char *string);
  95. static const char *maxpd_atom_get_string(t_atom *a);
  96. static void maxpd_atom_set_string(t_atom *a, const char *string);
  97. static void maxpd_atom_set_int(t_atom *a, int i);
  98. static double maxpd_atom_get_float(t_atom *a);
  99. static void maxpd_atom_set_float(t_atom *a, float d);
  100. // *********************************************************
  101. // -(global class pointer variable)-------------------------
  102. static void *mapperobj_class;
  103. // *********************************************************
  104. // -(main)--------------------------------------------------
  105. #ifdef WIN32
  106. void ext_main(void *r)
  107. {
  108. main();
  109. }
  110. #endif
  111. #ifdef MAXMSP
  112. int main(void)
  113. {
  114. t_class *c;
  115. c = class_new("mapper", (method)mapperobj_new, (method)mapperobj_free,
  116. (long)sizeof(t_mapper), 0L, A_GIMME, 0);
  117. class_addmethod(c, (method)mapperobj_assist, "assist", A_CANT, 0);
  118. class_addmethod(c, (method)mapperobj_add_signal, "add", A_GIMME, 0);
  119. class_addmethod(c, (method)mapperobj_remove_signal, "remove", A_GIMME, 0);
  120. class_addmethod(c, (method)mapperobj_anything, "anything", A_GIMME, 0);
  121. class_addmethod(c, (method)mapperobj_learn, "learn", A_GIMME, 0);
  122. class_addmethod(c, (method)mapperobj_set, "set", A_GIMME, 0);
  123. class_addmethod(c, (method)mapperobj_clear_signals, "clear", A_GIMME, 0);
  124. class_register(CLASS_BOX, c); /* CLASS_NOBOX */
  125. mapperobj_class = c;
  126. return 0;
  127. }
  128. #else
  129. int mapper_setup(void)
  130. {
  131. t_class *c;
  132. c = class_new(gensym("mapper"), (t_newmethod)mapperobj_new, (t_method)mapperobj_free,
  133. (long)sizeof(t_mapper), 0L, A_GIMME, 0);
  134. class_addmethod(c, (t_method)mapperobj_add_signal, gensym("add"), A_GIMME, 0);
  135. class_addmethod(c, (t_method)mapperobj_remove_signal, gensym("remove"), A_GIMME, 0);
  136. class_addanything(c, (t_method)mapperobj_anything);
  137. class_addmethod(c, (t_method)mapperobj_learn, gensym("learn"), A_GIMME, 0);
  138. class_addmethod(c, (t_method)mapperobj_set, gensym("set"), A_GIMME, 0);
  139. class_addmethod(c, (t_method)mapperobj_clear_signals, gensym("clear"), A_GIMME, 0);
  140. mapperobj_class = c;
  141. return 0;
  142. }
  143. #endif
  144. // *********************************************************
  145. // -(new)---------------------------------------------------
  146. static void *mapperobj_new(t_symbol *s, int argc, t_atom *argv)
  147. {
  148. t_mapper *x = NULL;
  149. long i;
  150. int learn = 0;
  151. const char *alias = NULL;
  152. const char *iface = NULL;
  153. #ifdef MAXMSP
  154. if ((x = object_alloc(mapperobj_class))) {
  155. x->outlet2 = listout((t_object *)x);
  156. x->outlet1 = listout((t_object *)x);
  157. x->name = 0;
  158. #else
  159. if ((x = (t_mapper *) pd_new(mapperobj_class)) ) {
  160. x->outlet1 = outlet_new(&x->ob, gensym("list"));
  161. x->outlet2 = outlet_new(&x->ob, gensym("list"));
  162. #endif
  163. for (i = 0; i < argc; i++) {
  164. if ((argv+i)->a_type == A_SYM) {
  165. if (maxpd_atom_strcmp(argv+i, "@alias") == 0) {
  166. if ((argv+i+1)->a_type == A_SYM) {
  167. alias = maxpd_atom_get_string(argv+i+1);
  168. i++;
  169. }
  170. }
  171. #ifdef MAXMSP
  172. else if ((maxpd_atom_strcmp(argv+i, "@def") == 0) ||
  173. (maxpd_atom_strcmp(argv+i, "@definition") == 0)) {
  174. if ((argv+i+1)->a_type == A_SYM) {
  175. x->definition = strdup(maxpd_atom_get_string(argv+i+1));
  176. mapperobj_read_definition(x);
  177. i++;
  178. }
  179. }
  180. #endif
  181. else if (maxpd_atom_strcmp(argv+i, "@learn") == 0) {
  182. if ((argv+i+1)->a_type == A_FLOAT) {
  183. learn = (maxpd_atom_get_float(argv+i+1) > 1) ? 0 : 1;
  184. i++;
  185. }
  186. #ifdef MAXMSP
  187. else if ((argv+i+1)->a_type == A_LONG) {
  188. learn = (atom_getlong(argv+i+1) > 1) ? 0 : 1;
  189. i++;
  190. }
  191. #endif
  192. }
  193. else if (maxpd_atom_strcmp(argv+i, "@interface") == 0) {
  194. if ((argv+i+1)->a_type == A_SYM) {
  195. iface = maxpd_atom_get_string(argv+i+1);
  196. i++;
  197. }
  198. }
  199. }
  200. }
  201. if (alias) {
  202. x->name = *alias == '/' ? strdup(alias+1) : strdup(alias);
  203. }
  204. else if (!x->name) {
  205. #ifdef MAXMSP
  206. x->name = strdup("maxmsp");
  207. #else
  208. x->name = strdup("puredata");
  209. #endif
  210. }
  211. POST(x, "libmapper version %s – visit libmapper.org for more information.",
  212. mpr_get_version());
  213. x->device = mpr_dev_new(x->name, 0);
  214. if (!x->device) {
  215. POST(x, "Error initializing libmapper device.");
  216. return 0;
  217. }
  218. x->graph = mpr_obj_get_graph(x->device);
  219. if (iface)
  220. mpr_graph_set_interface(x->graph, iface);
  221. POST(x, "Using network interface %s.", mpr_graph_get_interface(x->graph));
  222. // add other declared properties
  223. for (i = 0; i < argc; i++) {
  224. if (i > argc - 2) // need 2 arguments for key and value
  225. break;
  226. if ((maxpd_atom_strcmp(argv+i, "@alias") == 0) ||
  227. (maxpd_atom_strcmp(argv+i, "@def") == 0) ||
  228. (maxpd_atom_strcmp(argv+i, "@definition") == 0) ||
  229. (maxpd_atom_strcmp(argv+i, "@learn") == 0) ||
  230. (maxpd_atom_strcmp(argv+i, "@interface") == 0)){
  231. i++;
  232. continue;
  233. }
  234. else if (maxpd_atom_get_string(argv+i)[0] == '@') {
  235. switch ((argv+i+1)->a_type) {
  236. case A_SYM: {
  237. const char *value = maxpd_atom_get_string(argv+i+1);
  238. mpr_obj_set_prop(x->device, MPR_PROP_UNKNOWN,
  239. maxpd_atom_get_string(argv+i)+1, 1,
  240. MPR_STR, value, 1);
  241. i++;
  242. break;
  243. }
  244. case A_FLOAT:
  245. {
  246. float value = maxpd_atom_get_float(argv+i+1);
  247. mpr_obj_set_prop(x->device, MPR_PROP_UNKNOWN,
  248. maxpd_atom_get_string(argv+i)+1, 1,
  249. MPR_FLT, &value, 1);
  250. i++;
  251. break;
  252. }
  253. #ifdef MAXMSP
  254. case A_LONG:
  255. {
  256. int value = atom_getlong(argv+i+1);
  257. mpr_obj_set_prop(x->device, MPR_PROP_UNKNOWN,
  258. maxpd_atom_get_string(argv+i)+1, 1,
  259. MPR_INT32, &value, 1);
  260. i++;
  261. break;
  262. }
  263. #endif
  264. default:
  265. break;
  266. }
  267. }
  268. }
  269. x->ready = 0;
  270. x->updated = 0;
  271. x->learn_mode = learn;
  272. #ifdef MAXMSP
  273. mapperobj_register_signals(x);
  274. // Create the timing clock
  275. x->clock = clock_new(x, (method)mapperobj_poll);
  276. #else
  277. // Create the timing clock
  278. x->clock = clock_new(x, (t_method)mapperobj_poll);
  279. #endif
  280. clock_delay(x->clock, INTERVAL); // Set clock to go off after delay
  281. }
  282. return (x);
  283. }
  284. // *********************************************************
  285. // -(free)--------------------------------------------------
  286. static void mapperobj_free(t_mapper *x)
  287. {
  288. clock_unset(x->clock); // Remove clock routine from the scheduler
  289. clock_free(x->clock); // Frees memeory used by clock
  290. #ifdef MAXMSP
  291. object_free(x->d); // Frees memory used by dictionary
  292. #endif
  293. if (x->device) {
  294. mpr_dev_free(x->device);
  295. }
  296. if (x->name) {
  297. free(x->name);
  298. }
  299. }
  300. // *********************************************************
  301. // -(print properties)--------------------------------------
  302. static void mapperobj_print_properties(t_mapper *x)
  303. {
  304. if (x->ready) {
  305. //output name
  306. maxpd_atom_set_string(x->buffer.atoms, mpr_obj_get_prop_as_str(x->device, MPR_PROP_NAME, NULL));
  307. outlet_anything(x->outlet2, gensym("name"), 1, x->buffer.atoms);
  308. //output interface
  309. maxpd_atom_set_string(x->buffer.atoms, mpr_graph_get_interface(x->graph));
  310. outlet_anything(x->outlet2, gensym("interface"), 1, x->buffer.atoms);
  311. //output IP
  312. maxpd_atom_set_string(x->buffer.atoms, mpr_graph_get_address(x->graph));
  313. outlet_anything(x->outlet2, gensym("IP"), 1, x->buffer.atoms);
  314. //output port
  315. maxpd_atom_set_int(x->buffer.atoms,
  316. mpr_obj_get_prop_as_int32(x->device, MPR_PROP_PORT, NULL));
  317. outlet_anything(x->outlet2, gensym("port"), 1, x->buffer.atoms);
  318. //output ordinal
  319. maxpd_atom_set_int(x->buffer.atoms,
  320. mpr_obj_get_prop_as_int32(x->device, MPR_PROP_ORDINAL, NULL));
  321. outlet_anything(x->outlet2, gensym("ordinal"), 1, x->buffer.atoms);
  322. //output numInputs
  323. maxpd_atom_set_int(x->buffer.atoms,
  324. mpr_list_get_size(mpr_dev_get_sigs(x->device, MPR_DIR_IN)));
  325. outlet_anything(x->outlet2, gensym("numInputs"), 1, x->buffer.atoms);
  326. //output numOutputs
  327. maxpd_atom_set_int(x->buffer.atoms,
  328. mpr_list_get_size(mpr_dev_get_sigs(x->device, MPR_DIR_OUT)));
  329. outlet_anything(x->outlet2, gensym("numOutputs"), 1, x->buffer.atoms);
  330. }
  331. }
  332. // *********************************************************
  333. // -(inlet/outlet assist - maxmsp only)---------------------
  334. #ifdef MAXMSP
  335. void mapperobj_assist(t_mapper *x, void *b, long m, long a, char *s)
  336. {
  337. if (m == ASSIST_INLET) { // inlet
  338. sprintf(s, "OSC input");
  339. }
  340. else { // outlet
  341. if (a == 0) {
  342. sprintf(s, "Mapped OSC data");
  343. }
  344. else {
  345. sprintf(s, "Device information");
  346. }
  347. }
  348. }
  349. #endif // MAXMSP
  350. // *********************************************************
  351. // -(add signal)--------------------------------------------
  352. static void mapperobj_add_signal(t_mapper *x, t_symbol *s, int argc, t_atom *argv)
  353. {
  354. const char *sig_name = 0, *sig_units = 0;
  355. char sig_type = 0;
  356. int sig_length = 1, prop_int = 0;
  357. long i;
  358. mpr_sig sig = 0;
  359. mpr_dir dir;
  360. if (argc < 4) {
  361. POST(x, "Not enough arguments for 'add' message.");
  362. return;
  363. }
  364. if ((argv->a_type != A_SYM) || ((argv+1)->a_type != A_SYM))
  365. return;
  366. if (maxpd_atom_strcmp(argv, "input") == 0)
  367. dir = MPR_DIR_IN;
  368. else if (maxpd_atom_strcmp(argv, "output") == 0)
  369. dir = MPR_DIR_OUT;
  370. else
  371. return;
  372. // get signal name
  373. sig_name = maxpd_atom_get_string(argv+1);
  374. // get signal type, length, and units
  375. for (i = 2; i < argc; i++) {
  376. if (i > argc - 2) // need 2 arguments for key and value
  377. break;
  378. if ((argv+i)->a_type == A_SYM) {
  379. if (maxpd_atom_strcmp(argv+i, "@type") == 0) {
  380. if ((argv+i+1)->a_type == A_SYM) {
  381. sig_type = maxpd_atom_get_string(argv+i+1)[0];
  382. i++;
  383. }
  384. }
  385. else if (maxpd_atom_strcmp(argv+i, "@length") == 0) {
  386. if ((argv+i+1)->a_type == A_FLOAT) {
  387. sig_length = (int)maxpd_atom_get_float(argv+i+1);
  388. i++;
  389. }
  390. #ifdef MAXMSP
  391. else if ((argv+i+1)->a_type == A_LONG) {
  392. sig_length = atom_getlong(argv+i+1);
  393. i++;
  394. }
  395. #endif
  396. }
  397. else if(maxpd_atom_strcmp(argv+i, "@units") == 0) {
  398. if ((argv+i+1)->a_type == A_SYM) {
  399. sig_units = maxpd_atom_get_string(argv+i+1);
  400. i++;
  401. }
  402. }
  403. }
  404. }
  405. if (!sig_type) {
  406. POST(x, "Signal has no declared type!");
  407. return;
  408. }
  409. if (sig_length < 1) {
  410. POST(x, "Signals cannot have length < 1!");
  411. return;
  412. }
  413. else if (sig_length > MAX_LIST) {
  414. POST(x, "Limiting signal vector length %d.", MAX_LIST);
  415. sig_length = MAX_LIST;
  416. }
  417. sig = mpr_sig_new(x->device, dir, sig_name, sig_length, sig_type, sig_units,
  418. 0, 0, 0, mapperobj_sig_handler, MPR_SIG_ALL);
  419. mpr_obj_set_prop(sig, MPR_PROP_DATA, NULL, 1, MPR_PTR, x, 0);
  420. if (!sig) {
  421. POST(x, "Error adding signal!");
  422. return;
  423. }
  424. // add other declared properties
  425. for (i = 2; i < argc; i++) {
  426. if (i > argc - 2) // need 2 arguments for key and value
  427. break;
  428. if ((maxpd_atom_strcmp(argv+i, "@type") == 0) ||
  429. (maxpd_atom_strcmp(argv+i, "@length") == 0) ||
  430. (maxpd_atom_strcmp(argv+i, "@units") == 0)){
  431. i++;
  432. continue;
  433. }
  434. if (maxpd_atom_strcmp(argv+i, "@min") == 0) {
  435. if ((argv+i+1)->a_type == A_FLOAT) {
  436. float val = maxpd_atom_get_float(argv+i+1);
  437. mpr_obj_set_prop(sig, MPR_PROP_MIN, NULL, 1, MPR_FLT, &val, 1);
  438. i++;
  439. }
  440. #ifdef MAXMSP
  441. else if ((argv + i + 1)->a_type == A_LONG) {
  442. int val = (int)atom_getlong(argv+i+1);
  443. mpr_obj_set_prop(sig, MPR_PROP_MIN, NULL, 1, MPR_INT32, &val, 1);
  444. i++;
  445. }
  446. #endif
  447. }
  448. else if (maxpd_atom_strcmp(argv+i, "@max") == 0) {
  449. if ((argv+i+1)->a_type == A_FLOAT) {
  450. float val = maxpd_atom_get_float(argv+i+1);
  451. mpr_obj_set_prop(sig, MPR_PROP_MAX, NULL, 1, MPR_FLT, &val, 1);
  452. i++;
  453. }
  454. #ifdef MAXMSP
  455. else if ((argv + i + 1)->a_type == A_LONG) {
  456. int val = (int)atom_getlong(argv+i+1);
  457. mpr_obj_set_prop(sig, MPR_PROP_MAX, NULL, 1, MPR_INT32, &val, 1);
  458. i++;
  459. }
  460. #endif
  461. }
  462. else if (maxpd_atom_strcmp(argv+i, "@instances") == 0) {
  463. if ((argv+i+1)->a_type == A_FLOAT) {
  464. prop_int = (int)maxpd_atom_get_float(argv+i+1);
  465. i++;
  466. }
  467. #ifdef MAXMSP
  468. else if ((argv+i+1)->a_type == A_LONG) {
  469. prop_int = atom_getlong(argv+i+1);
  470. i++;
  471. }
  472. #endif
  473. if (prop_int > 1)
  474. mpr_sig_reserve_inst(sig, prop_int, 0, 0);
  475. }
  476. else if (maxpd_atom_strcmp(argv+i, "@stealing") == 0) {
  477. if ((argv+i+1)->a_type == A_SYM) {
  478. int stl = MPR_STEAL_NONE;
  479. if (maxpd_atom_strcmp(argv+i+1, "newest") == 0) {
  480. stl = MPR_STEAL_NEWEST;
  481. }
  482. if (maxpd_atom_strcmp(argv+i+1, "oldest") == 0) {
  483. stl = MPR_STEAL_OLDEST;
  484. }
  485. mpr_obj_set_prop(sig, MPR_PROP_STEAL_MODE, NULL, 1, MPR_INT32, &stl, 1);
  486. i++;
  487. }
  488. }
  489. else if (maxpd_atom_get_string(argv+i)[0] == '@') {
  490. switch ((argv+i+1)->a_type) {
  491. case A_SYM: {
  492. const char *value = maxpd_atom_get_string(argv+i+1);
  493. mpr_obj_set_prop(sig, MPR_PROP_UNKNOWN, maxpd_atom_get_string(argv+i)+1, 1,
  494. MPR_STR, value, 1);
  495. i++;
  496. break;
  497. }
  498. case A_FLOAT:
  499. {
  500. float value = maxpd_atom_get_float(argv+i+1);
  501. mpr_obj_set_prop(sig, MPR_PROP_UNKNOWN, maxpd_atom_get_string(argv+i)+1, 1,
  502. MPR_FLT, &value, 1);
  503. i++;
  504. break;
  505. }
  506. #ifdef MAXMSP
  507. case A_LONG:
  508. {
  509. int value = atom_getlong(argv+i+1);
  510. mpr_obj_set_prop(sig, MPR_PROP_UNKNOWN, maxpd_atom_get_string(argv+i)+1, 1,
  511. MPR_INT32, &value, 1);
  512. i++;
  513. break;
  514. }
  515. #endif
  516. default:
  517. break;
  518. }
  519. }
  520. }
  521. // Update status outlet
  522. maxpd_atom_set_int(x->buffer.atoms, mpr_list_get_size(mpr_dev_get_sigs(x->device, dir)));
  523. if (dir == MPR_DIR_OUT)
  524. outlet_anything(x->outlet2, gensym("numOutputs"), 1, x->buffer.atoms);
  525. else
  526. outlet_anything(x->outlet2, gensym("numInputs"), 1, x->buffer.atoms);
  527. }
  528. // *********************************************************
  529. // -(remove signal)-----------------------------------------
  530. static void mapperobj_remove_signal(t_mapper *x, t_symbol *s, int argc, t_atom *argv)
  531. {
  532. const char *sig_name = NULL, *direction = NULL;
  533. if (argc < 2) {
  534. return;
  535. }
  536. if (argv->a_type != A_SYM || (argv+1)->a_type != A_SYM) {
  537. POST(x, "Unable to parse remove message!");
  538. return;
  539. }
  540. direction = maxpd_atom_get_string(argv);
  541. sig_name = maxpd_atom_get_string(argv+1);
  542. mpr_list sigs = mpr_dev_get_sigs(x->device, MPR_DIR_ANY);
  543. sigs = mpr_list_filter(sigs, MPR_PROP_NAME, NULL, 1, MPR_STR, sig_name, MPR_OP_EQ);
  544. if (sigs && *sigs)
  545. mpr_sig_free(*sigs);
  546. if (strcmp(direction, "output") == 0) {
  547. maxpd_atom_set_int(x->buffer.atoms,
  548. mpr_list_get_size(mpr_dev_get_sigs(x->device, MPR_DIR_OUT)));
  549. outlet_anything(x->outlet2, gensym("numOutputs"), 1, x->buffer.atoms);
  550. }
  551. else if (strcmp(direction, "input") == 0) {
  552. maxpd_atom_set_int(x->buffer.atoms,
  553. mpr_list_get_size(mpr_dev_get_sigs(x->device, MPR_DIR_IN)));
  554. outlet_anything(x->outlet2, gensym("numInputs"), 1, x->buffer.atoms);
  555. }
  556. }
  557. // *********************************************************
  558. // -(clear all signals)-------------------------------------
  559. static void mapperobj_clear_signals(t_mapper *x, t_symbol *s,
  560. int argc, t_atom *argv)
  561. {
  562. mpr_dir dir = 0;
  563. if (!argc)
  564. dir = MPR_DIR_ANY;
  565. else if (maxpd_atom_strcmp(argv, "inputs") == 0)
  566. dir |= MPR_DIR_IN;
  567. else if (maxpd_atom_strcmp(argv, "outputs") == 0)
  568. dir |= MPR_DIR_OUT;
  569. else
  570. return;
  571. mpr_list sigs;
  572. POST(x, "Clearing signals");
  573. sigs = mpr_dev_get_sigs(x->device, dir);
  574. while (sigs) {
  575. mpr_sig sig = *sigs;
  576. sigs = mpr_list_get_next(sigs);
  577. mpr_sig_free(sig);
  578. }
  579. if (dir & MPR_DIR_IN) {
  580. maxpd_atom_set_int(x->buffer.atoms, mpr_list_get_size(mpr_dev_get_sigs(x->device, MPR_DIR_IN)));
  581. outlet_anything(x->outlet2, gensym("numInputs"), 1, x->buffer.atoms);
  582. }
  583. if (dir & MPR_DIR_OUT) {
  584. maxpd_atom_set_int(x->buffer.atoms, mpr_list_get_size(mpr_dev_get_sigs(x->device, MPR_DIR_OUT)));
  585. outlet_anything(x->outlet2, gensym("numOutputs"), 1, x->buffer.atoms);
  586. }
  587. }
  588. // *********************************************************
  589. // -(set signal value)--------------------------------------
  590. static void mapperobj_set(t_mapper *x, t_symbol *s, int argc, t_atom *argv)
  591. {
  592. /* This method sets the value of an input signal.
  593. * This allows storing of input signal state changes generated by
  594. * user actions rather than libmapper messaging. This state storage
  595. * is used by libmapper for (e.g.) retreiving information for training
  596. * implicit mapping algorithms. */
  597. // forward to 'anything' handler
  598. mapperobj_anything(x, s, argc, argv);
  599. }
  600. // *********************************************************
  601. // -(anything)----------------------------------------------
  602. static void mapperobj_anything(t_mapper *x, t_symbol *s, int argc, t_atom *argv)
  603. {
  604. if (!x->ready)
  605. return;
  606. int i = 0, j = 0, id = 0;
  607. if (!argc)
  608. return;
  609. //find signal
  610. mpr_sig sig = NULL;
  611. mpr_list sigs = mpr_dev_get_sigs(x->device, MPR_DIR_ANY);
  612. sigs = mpr_list_filter(sigs, MPR_PROP_NAME, NULL, 1, MPR_STR, s->s_name, MPR_OP_EQ);
  613. if (sigs && *sigs)
  614. sig = *sigs;
  615. if (!sig) {
  616. if (!x->learn_mode)
  617. return;
  618. int length = argc;
  619. if (length > MAX_LIST) {
  620. POST(x, "Limiting signal vector length %d.", MAX_LIST);
  621. length = MAX_LIST;
  622. }
  623. // register as new signal
  624. if (argv->a_type == A_FLOAT) {
  625. sig = mpr_sig_new(x->device, MPR_DIR_OUT, s->s_name, length, MPR_FLT, 0, 0, 0, 0, 0, 0);
  626. }
  627. #ifdef MAXMSP
  628. else if (argv->a_type == A_LONG) {
  629. sig = mpr_sig_new(x->device, MPR_DIR_OUT, s->s_name, length, MPR_INT32, 0, 0, 0, 0, 0, 0);
  630. }
  631. #endif
  632. else {
  633. return;
  634. }
  635. //output updated numOutputs
  636. maxpd_atom_set_float(x->buffer.atoms,
  637. mpr_list_get_size(mpr_dev_get_sigs(x->device, MPR_DIR_OUT)));
  638. outlet_anything(x->outlet2, gensym("numOutputs"), 1, x->buffer.atoms);
  639. }
  640. int len = mpr_obj_get_prop_as_int32(sig, MPR_PROP_LEN, NULL);
  641. mpr_type type = (mpr_type)mpr_obj_get_prop_as_int32(sig, MPR_PROP_TYPE, NULL);
  642. if (argc == 2 && (argv + 1)->a_type == A_SYM) {
  643. if ((argv)->a_type == A_FLOAT) {
  644. id = (int)atom_getfloat(argv);
  645. }
  646. #ifdef MAXMSP
  647. else if ((argv)->a_type == A_LONG) {
  648. id = (int)atom_getlong(argv);
  649. }
  650. else
  651. return;
  652. #endif
  653. if (maxpd_atom_strcmp(argv+1, "release") == 0)
  654. mpr_sig_release_inst(sig, id);
  655. return;
  656. }
  657. if (argc == len + 1) {
  658. // Special case: signal value may be preceded by instance number
  659. if ((argv)->a_type == A_FLOAT) {
  660. id = (int)maxpd_atom_get_float(argv);
  661. j = 1;
  662. }
  663. #ifdef MAXMSP
  664. else if ((argv)->a_type == A_LONG) {
  665. id = (int)atom_getlong(argv);
  666. j = 1;
  667. }
  668. #endif
  669. else {
  670. POST(x, "Instance ID is not int or float!");
  671. return;
  672. }
  673. }
  674. else if (argc != len)
  675. return;
  676. if (MPR_INT32 == type) {
  677. int *payload = x->buffer.ints;
  678. for (i = 0; i < len; i++) {
  679. if ((argv + i + j)->a_type == A_FLOAT)
  680. payload[i] = (int)atom_getfloat(argv + i + j);
  681. #ifdef MAXMSP
  682. else if ((argv + i + j)->a_type == A_LONG)
  683. payload[i] = (int)atom_getlong(argv + i + j);
  684. #endif
  685. }
  686. //update signal
  687. mpr_sig_set_value(sig, id, len, MPR_INT32, payload);
  688. }
  689. else if (MPR_FLT == type) {
  690. float *payload = x->buffer.floats;
  691. for (i = 0; i < len; i++) {
  692. if ((argv + i + j)->a_type == A_FLOAT)
  693. payload[i] = atom_getfloat(argv + i + j);
  694. #ifdef MAXMSP
  695. else if ((argv + i + j)->a_type == A_LONG)
  696. payload[i] = (float)atom_getlong(argv + i + j);
  697. #endif
  698. }
  699. //update signal
  700. mpr_sig_set_value(sig, id, len, MPR_FLT, payload);
  701. }
  702. else {
  703. return;
  704. }
  705. }
  706. // *********************************************************
  707. // -(sig handler)-------------------------------------------
  708. static void mapperobj_sig_handler(mpr_sig sig, mpr_sig_evt evt, mpr_id inst,
  709. int len, mpr_type type, const void *val,
  710. mpr_time time)
  711. {
  712. t_mapper *x = (void*)mpr_obj_get_prop_as_ptr(sig, MPR_PROP_DATA, NULL);
  713. t_symbol *name = gensym(mpr_obj_get_prop_as_str(sig, MPR_PROP_NAME, NULL));
  714. switch (evt) {
  715. case MPR_SIG_UPDATE: {
  716. int poly = 0;
  717. if (mpr_sig_get_num_inst(sig, MPR_STATUS_ALL) > 1) {
  718. maxpd_atom_set_int(x->buffer.atoms, inst);
  719. poly = 1;
  720. }
  721. if (val) {
  722. int i;
  723. if (len > (MAX_LIST-1)) {
  724. POST(x, "Maximum list length is %i!", MAX_LIST-1);
  725. len = MAX_LIST-1;
  726. }
  727. #ifdef MAXMSP
  728. if (MPR_INT32 == type) {
  729. int *v = (int*)val;
  730. for (i = 0; i < len; i++)
  731. maxpd_atom_set_int(x->buffer.atoms + i + poly, v[i]);
  732. }
  733. else if (MPR_FLT == type) {
  734. #endif
  735. float *v = (float*)val;
  736. for (i = 0; i < len; i++)
  737. maxpd_atom_set_float(x->buffer.atoms + i + poly, v[i]);
  738. #ifdef MAXMSP
  739. }
  740. #endif
  741. outlet_anything(x->outlet1, name, len + poly, x->buffer.atoms);
  742. }
  743. else if (poly) {
  744. maxpd_atom_set_string(x->buffer.atoms + 1, "release");
  745. maxpd_atom_set_string(x->buffer.atoms + 2, "local");
  746. outlet_anything(x->outlet1, name, 3, x->buffer.atoms);
  747. }
  748. break;
  749. }
  750. case MPR_SIG_REL_UPSTRM:
  751. maxpd_atom_set_int(x->buffer.atoms, inst);
  752. maxpd_atom_set_string(x->buffer.atoms + 1, "release");
  753. maxpd_atom_set_string(x->buffer.atoms + 2, "upstream");
  754. outlet_anything(x->outlet1, name, 3, x->buffer.atoms);
  755. break;
  756. case MPR_SIG_REL_DNSTRM:
  757. maxpd_atom_set_int(x->buffer.atoms, inst);
  758. maxpd_atom_set_string(x->buffer.atoms + 1, "release");
  759. maxpd_atom_set_string(x->buffer.atoms + 2, "downstream");
  760. outlet_anything(x->outlet1, name, 3, x->buffer.atoms);
  761. break;
  762. case MPR_SIG_INST_OFLW: {
  763. maxpd_atom_set_int(x->buffer.atoms, inst);
  764. int mode = mpr_obj_get_prop_as_int32(sig, MPR_PROP_STEAL_MODE, NULL);
  765. switch (mode) {
  766. case MPR_STEAL_OLDEST:
  767. inst = mpr_sig_get_oldest_inst_id(sig);
  768. if (inst)
  769. mpr_sig_release_inst(sig, inst);
  770. break;
  771. case MPR_STEAL_NEWEST:
  772. inst = mpr_sig_get_newest_inst_id(sig);
  773. if (inst)
  774. mpr_sig_release_inst(sig, inst);
  775. break;
  776. case 0:
  777. maxpd_atom_set_string(x->buffer.atoms + 1, "overflow");
  778. outlet_anything(x->outlet1, name, 2, x->buffer.atoms);
  779. break;
  780. default:
  781. break;
  782. }
  783. break;
  784. }
  785. default:
  786. break;
  787. }
  788. }
  789. // *********************************************************
  790. // -(read device definition - maxmsp only)------------------
  791. #ifdef MAXMSP
  792. static void mapperobj_read_definition(t_mapper *x)
  793. {
  794. if (x->d) {
  795. object_free(x->d);
  796. }
  797. t_object *info;
  798. t_symbol *sym_device = gensym("device");
  799. t_symbol *sym_name = gensym("name");
  800. const char *my_name = 0;
  801. short path;
  802. unsigned int filetype = 'JSON', outtype;
  803. // TODO: add ".json" to end of string if missing (or pick new filetype!)
  804. if (locatefile_extended(x->definition, &path, &outtype, &filetype, 1) == 0) {
  805. POST(x, "Located file %s", x->definition);
  806. if (dictionary_read(x->definition, path, &(x->d)) == 0) {
  807. //check that first key is "device"
  808. if (dictionary_entryisdictionary(x->d, sym_device)) {
  809. //recover name from dictionary
  810. dictionary_getdictionary(x->d, sym_device, &info);
  811. dictionary_getstring((t_dictionary *)info, sym_name, &my_name);
  812. if (my_name) {
  813. free(x->name);
  814. x->name = *my_name == '/' ? strdup(my_name+1) : strdup(my_name);
  815. }
  816. }
  817. }
  818. else {
  819. POST(x, "Could not parse file %s", x->definition);
  820. }
  821. }
  822. else {
  823. POST(x, "Could not locate file %s", x->definition);
  824. }
  825. }
  826. #endif // MAXMSP
  827. // *********************************************************
  828. // -(register signals from dictionary - maxmsp only)--------
  829. #ifdef MAXMSP
  830. static void mapperobj_register_signals(t_mapper *x) {
  831. t_atom *signals;
  832. long num_signals, i;
  833. t_object *device, *inputs, *outputs, *temp;
  834. t_symbol *sym_device = gensym("device");
  835. t_symbol *sym_inputs = gensym("inputs");
  836. t_symbol *sym_outputs = gensym("outputs");
  837. t_symbol *sym_name = gensym("name");
  838. t_symbol *sym_type = gensym("type");
  839. t_symbol *sym_units = gensym("units");
  840. t_symbol *sym_minimum = gensym("minimum");
  841. t_symbol *sym_maximum = gensym("maximum");
  842. t_symbol *sym_length = gensym("length");
  843. const char *sig_name, *sig_units, *sig_type_str;
  844. mpr_type sig_type = 0;
  845. double val_d;
  846. long long val_l, sig_length;
  847. mpr_sig temp_sig;
  848. short range_known[2];
  849. if (!x->d)
  850. return;
  851. // Get pointer to dictionary "device"
  852. if (dictionary_getdictionary(x->d, sym_device, &device) != MAX_ERR_NONE)
  853. return;
  854. // Get pointer to atom array "inputs"
  855. if (dictionary_getatomarray((t_dictionary *)device, sym_inputs, &inputs) == MAX_ERR_NONE) {
  856. atomarray_getatoms((t_atomarray *)inputs, &num_signals, &signals);
  857. // iterate through array of atoms
  858. for (i=0; i<num_signals; i++) {
  859. // initialize variables
  860. range_known[0] = 0;
  861. range_known[1] = 0;
  862. // each atom object points to a dictionary, need to recover atoms by key
  863. temp = atom_getobj(&(signals[i]));
  864. if (dictionary_getstring((t_dictionary *)temp, sym_name, &sig_name) != MAX_ERR_NONE)
  865. continue;
  866. if (dictionary_getstring((t_dictionary *)temp, sym_type, &sig_type_str) != MAX_ERR_NONE)
  867. continue;
  868. if (dictionary_getlong((t_dictionary *)temp, sym_length, &sig_length) != MAX_ERR_NONE)
  869. sig_length = 1;
  870. if (dictionary_getstring((t_dictionary *)temp, sym_units, &sig_units) != MAX_ERR_NONE)
  871. sig_units = 0;
  872. if ((strcmp(sig_type_str, "int") == 0) || (strcmp(sig_type_str, "i") == 0))
  873. sig_type = MPR_INT32;
  874. else if ((strcmp(sig_type_str, "float") == 0) || (strcmp(sig_type_str, "f") == 0))
  875. sig_type = MPR_FLT;
  876. else {
  877. POST(x, "Skipping registration of signal %s (unknown type).", sig_name);
  878. continue;
  879. }
  880. if (sig_length > MAX_LIST) {
  881. POST(x, "Limiting signal vector length %d.", MAX_LIST);
  882. sig_length = MAX_LIST;
  883. }
  884. temp_sig = mpr_sig_new(x->device, MPR_DIR_IN, sig_name, (int)sig_length, sig_type,
  885. sig_units, 0, 0, 0, mapperobj_sig_handler, MPR_SIG_ALL);
  886. mpr_obj_set_prop(temp_sig, MPR_PROP_DATA, NULL, 1, MPR_PTR, x, 0);
  887. if (!temp_sig)
  888. continue;
  889. if (dictionary_getfloat((t_dictionary *)temp, sym_minimum, &val_d) == MAX_ERR_NONE) {
  890. mpr_obj_set_prop(temp_sig, MPR_PROP_MIN, NULL, 1, MPR_DBL, &val_d, 1);
  891. }
  892. else if (dictionary_getlong((t_dictionary *)temp, sym_minimum, &val_l) == MAX_ERR_NONE) {
  893. int val_i = (int)val_l;
  894. mpr_obj_set_prop(temp_sig, MPR_PROP_MIN, NULL, 1, MPR_INT32, &val_i, 1);
  895. }
  896. if (dictionary_getfloat((t_dictionary *)temp, sym_maximum, &val_d) == MAX_ERR_NONE) {
  897. mpr_obj_set_prop(temp_sig, MPR_PROP_MAX, NULL, 1, MPR_DBL, &val_d, 1);
  898. }
  899. else if (dictionary_getlong((t_dictionary *)temp, sym_maximum, &val_l) == MAX_ERR_NONE) {
  900. int val_i = (int)val_l;
  901. mpr_obj_set_prop(temp_sig, MPR_PROP_MAX, NULL, 1, MPR_INT32, &val_i, 1);
  902. }
  903. }
  904. }
  905. // Get pointer to atom array "outputs"
  906. if (dictionary_getatomarray((t_dictionary *)device, sym_outputs, &outputs) == MAX_ERR_NONE) {
  907. atomarray_getatoms((t_atomarray *)outputs, &num_signals, &signals);
  908. // iterate through array of atoms
  909. for (i=0; i<num_signals; i++) {
  910. // initialize variables
  911. range_known[0] = 0;
  912. range_known[1] = 0;
  913. // each atom object points to a dictionary, need to recover atoms by key
  914. temp = atom_getobj(&(signals[i]));
  915. if (dictionary_getstring((t_dictionary *)temp, sym_name, &sig_name) != MAX_ERR_NONE)
  916. continue;
  917. if (dictionary_getstring((t_dictionary *)temp, sym_type, &sig_type_str) != MAX_ERR_NONE)
  918. continue;
  919. if (dictionary_getlong((t_dictionary *)temp, sym_length, &sig_length) != MAX_ERR_NONE)
  920. sig_length = 1;
  921. if (dictionary_getstring((t_dictionary *)temp, sym_units, &sig_units) != MAX_ERR_NONE)
  922. sig_units = 0;
  923. if ((strcmp(sig_type_str, "int") == 0) || (strcmp(sig_type_str, "i") == 0))
  924. sig_type = MPR_INT32;
  925. else if ((strcmp(sig_type_str, "float") == 0) || (strcmp(sig_type_str, "f") == 0))
  926. sig_type = MPR_FLT;
  927. else {
  928. POST("Skipping registration of signal %s (unknown type).",
  929. sig_name);
  930. continue;
  931. }
  932. if (sig_length > MAX_LIST) {
  933. POST(x, "Limiting signal vector length %d.", MAX_LIST);
  934. sig_length = MAX_LIST;
  935. }
  936. temp_sig = mpr_sig_new(x->device, MPR_DIR_OUT, sig_name, (int)sig_length, sig_type,
  937. sig_units, 0, 0, 0, 0, 0);
  938. if (!temp_sig)
  939. continue;
  940. if (dictionary_getfloat((t_dictionary *)temp, sym_minimum, &val_d) == MAX_ERR_NONE) {
  941. mpr_obj_set_prop(temp_sig, MPR_PROP_MIN, NULL, 1, MPR_DBL, &val_d, 1);
  942. }
  943. else if (dictionary_getlong((t_dictionary *)temp, sym_minimum, &val_l) == MAX_ERR_NONE) {
  944. int val_i = (int)val_l;
  945. mpr_obj_set_prop(temp_sig, MPR_PROP_MIN, NULL, 1, MPR_INT32, &val_i, 1);
  946. }
  947. if (dictionary_getfloat((t_dictionary *)temp, sym_maximum, &val_d) == MAX_ERR_NONE) {
  948. mpr_obj_set_prop(temp_sig, MPR_PROP_MAX, NULL, 1, MPR_DBL, &val_d, 1);
  949. }
  950. else if (dictionary_getlong((t_dictionary *)temp, sym_maximum, &val_l) == MAX_ERR_NONE) {
  951. int val_i = (int)val_l;
  952. mpr_obj_set_prop(temp_sig, MPR_PROP_MAX, NULL, 1, MPR_INT32, &val_i, 1);
  953. }
  954. }
  955. }
  956. }
  957. #endif // MAXMSP
  958. // *********************************************************
  959. // -(poll libmapper)----------------------------------------
  960. static void mapperobj_poll(t_mapper *x)
  961. {
  962. int count = 10;
  963. #ifdef MAXMSP
  964. critical_enter(0);
  965. #endif
  966. while(count-- && mpr_dev_poll(x->device, 0)) {};
  967. #ifdef MAXMSP
  968. critical_exit(0);
  969. #endif
  970. if (!x->ready) {
  971. if (mpr_dev_get_is_ready(x->device)) {
  972. POST(x, "Joining mapping network as '%s'",
  973. mpr_obj_get_prop_as_str(x->device, MPR_PROP_NAME, NULL));
  974. x->ready = 1;
  975. #ifdef MAXMSP
  976. defer_low((t_object *)x, (method)mapperobj_print_properties, NULL, 0, NULL);
  977. #else
  978. mapperobj_print_properties(x);
  979. #endif
  980. }
  981. }
  982. clock_delay(x->clock, INTERVAL); // Set clock to go off after delay
  983. }
  984. // *********************************************************
  985. // -(toggle learning mode)----------------------------------
  986. static void mapperobj_learn(t_mapper *x, t_symbol *s,
  987. int argc, t_atom *argv)
  988. {
  989. int mode = x->learn_mode;
  990. if (argc > 0) {
  991. if (argv->a_type == A_FLOAT) {
  992. mode = (int)atom_getfloat(argv);
  993. }
  994. #ifdef MAXMSP
  995. else if (argv->a_type == A_LONG) {
  996. mode = (int)atom_getlong(argv);
  997. }
  998. #endif
  999. if (mode != x->learn_mode) {
  1000. x->learn_mode = mode;
  1001. if (mode == 0) {
  1002. POST(x, "Learning mode off.");
  1003. }
  1004. else {
  1005. POST(x, "Learning mode on.");
  1006. }
  1007. }
  1008. }
  1009. }
  1010. // *********************************************************
  1011. // some helper functions for abtracting differences
  1012. // between maxmsp and puredata
  1013. static int maxpd_atom_strcmp(t_atom *a, const char *string)
  1014. {
  1015. if (a->a_type != A_SYM || !string)
  1016. return 1;
  1017. #ifdef MAXMSP
  1018. return strcmp(atom_getsym(a)->s_name, string);
  1019. #else
  1020. return strcmp((a)->a_w.w_symbol->s_name, string);
  1021. #endif
  1022. }
  1023. static const char *maxpd_atom_get_string(t_atom *a)
  1024. {
  1025. #ifdef MAXMSP
  1026. return atom_getsym(a)->s_name;
  1027. #else
  1028. return (a)->a_w.w_symbol->s_name;
  1029. #endif
  1030. }
  1031. static void maxpd_atom_set_string(t_atom *a, const char *string)
  1032. {
  1033. #ifdef MAXMSP
  1034. atom_setsym(a, gensym((char *)string));
  1035. #else
  1036. SETSYMBOL(a, gensym(string));
  1037. #endif
  1038. }
  1039. static void maxpd_atom_set_int(t_atom *a, int i)
  1040. {
  1041. #ifdef MAXMSP
  1042. atom_setlong(a, (long)i);
  1043. #else
  1044. SETFLOAT(a, (double)i);
  1045. #endif
  1046. }
  1047. static double maxpd_atom_get_float(t_atom *a)
  1048. {
  1049. return (double)atom_getfloat(a);
  1050. }
  1051. static void maxpd_atom_set_float(t_atom *a, float d)
  1052. {
  1053. #ifdef MAXMSP
  1054. atom_setfloat(a, d);
  1055. #else
  1056. SETFLOAT(a, d);
  1057. #endif
  1058. }