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

/mapper.c

https://github.com/radarsat1/mapper-max-pd
C | 1009 lines | 845 code | 72 blank | 92 comment | 290 complexity | b0861d9603bbc8239e56517b4ff00468 MD5 | raw file
  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 MAXMSP
  15. #include "ext.h" // standard Max include, always required
  16. #include "ext_obex.h" // required for new style Max object
  17. #include "ext_dictionary.h"
  18. #include "jpatcher_api.h"
  19. #else
  20. #include "m_pd.h"
  21. #define A_SYM A_SYMBOL
  22. #endif
  23. #include <mapper/mapper.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27. #include <math.h>
  28. #include <lo/lo.h>
  29. #ifndef WIN32
  30. #include <arpa/inet.h>
  31. #endif
  32. #include <unistd.h>
  33. #define INTERVAL 1
  34. #define MAX_LIST 256
  35. // *********************************************************
  36. // -(object struct)-----------------------------------------
  37. typedef struct _mapper
  38. {
  39. t_object ob;
  40. #ifdef WIN32
  41. #ifdef PD
  42. int pad; /* protect the object against observed writing beyond
  43. the bounds of t_object on Windows versions of PureData. */
  44. #endif
  45. #endif
  46. void *outlet1;
  47. void *outlet2;
  48. void *clock; // pointer to clock object
  49. char *name;
  50. mapper_admin admin;
  51. mapper_device device;
  52. int ready;
  53. int learn_mode;
  54. t_atom buffer[MAX_LIST];
  55. char *definition;
  56. #ifdef MAXMSP
  57. t_dictionary *d;
  58. #endif
  59. } t_mapper;
  60. static t_symbol *ps_list;
  61. static int port = 9000;
  62. // *********************************************************
  63. // -(function prototypes)-----------------------------------
  64. static void *mapper_new(t_symbol *s, int argc, t_atom *argv);
  65. static void mapper_free(t_mapper *x);
  66. static void mapper_anything(t_mapper *x, t_symbol *s, int argc, t_atom *argv);
  67. static void mapper_add_signal(t_mapper *x, t_symbol *s, int argc, t_atom *argv);
  68. static void mapper_remove_signal(t_mapper *x, t_symbol *s, int argc, t_atom *argv);
  69. static void mapper_poll(t_mapper *x);
  70. static void mapper_float_handler(mapper_signal msig, mapper_db_signal props,
  71. mapper_timetag_t *time, void *value);
  72. static void mapper_int_handler(mapper_signal msig, mapper_db_signal props,
  73. mapper_timetag_t *time, void *value);
  74. static void mapper_print_properties(t_mapper *x);
  75. static void mapper_register_signals(t_mapper *x);
  76. static void mapper_learn(t_mapper *x, t_symbol *s, int argc, t_atom *argv);
  77. static void mapper_set(t_mapper *x, t_symbol *s, int argc, t_atom *argv);
  78. static void mapper_read_definition(t_mapper *x);
  79. #ifdef MAXMSP
  80. void mapper_assist(t_mapper *x, void *b, long m, long a, char *s);
  81. #endif
  82. static const char *maxpd_atom_get_string(t_atom *a);
  83. static void maxpd_atom_set_string(t_atom *a, const char *string);
  84. static void maxpd_atom_set_int(t_atom *a, int i);
  85. static double maxpd_atom_get_float(t_atom *a);
  86. static void maxpd_atom_set_float(t_atom *a, float d);
  87. // *********************************************************
  88. // -(global class pointer variable)-------------------------
  89. static void *mapper_class;
  90. // *********************************************************
  91. // -(main)--------------------------------------------------
  92. #ifdef MAXMSP
  93. int main(void)
  94. {
  95. t_class *c;
  96. c = class_new("mapper", (method)mapper_new, (method)mapper_free,
  97. (long)sizeof(t_mapper), 0L, A_GIMME, 0);
  98. class_addmethod(c, (method)mapper_assist, "assist", A_CANT, 0);
  99. class_addmethod(c, (method)mapper_add_signal, "add", A_GIMME, 0);
  100. class_addmethod(c, (method)mapper_remove_signal, "remove", A_GIMME, 0);
  101. class_addmethod(c, (method)mapper_anything, "anything", A_GIMME, 0);
  102. class_addmethod(c, (method)mapper_learn, "learn", A_GIMME, 0);
  103. class_addmethod(c, (method)mapper_set, "set", A_GIMME, 0);
  104. class_register(CLASS_BOX, c); /* CLASS_NOBOX */
  105. mapper_class = c;
  106. ps_list = gensym("list");
  107. return 0;
  108. }
  109. #else
  110. int mapper_setup(void)
  111. {
  112. t_class *c;
  113. c = class_new(gensym("mapper"), (t_newmethod)mapper_new, (t_method)mapper_free,
  114. (long)sizeof(t_mapper), 0L, A_GIMME, 0);
  115. class_addmethod(c, (t_method)mapper_add_signal, gensym("add"), A_GIMME, 0);
  116. class_addmethod(c, (t_method)mapper_remove_signal, gensym("remove"), A_GIMME, 0);
  117. class_addanything(c, (t_method)mapper_anything);
  118. class_addmethod(c, (t_method)mapper_learn, gensym("learn"), A_GIMME, 0);
  119. class_addmethod(c, (t_method)mapper_set, gensym("set"), A_GIMME, 0);
  120. mapper_class = c;
  121. ps_list = gensym("list");
  122. return 0;
  123. }
  124. #endif
  125. // *********************************************************
  126. // -(new)---------------------------------------------------
  127. void *mapper_new(t_symbol *s, int argc, t_atom *argv)
  128. {
  129. t_mapper *x = NULL;
  130. long i;
  131. int learn = 0;
  132. const char *alias = NULL;
  133. const char *iface = NULL;
  134. #ifdef MAXMSP
  135. if (x = object_alloc(mapper_class)) {
  136. x->outlet2 = listout((t_object *)x);
  137. x->outlet1 = listout((t_object *)x);
  138. x->name = strdup("maxmsp");
  139. #else
  140. if (x = (t_mapper *) pd_new(mapper_class) ) {
  141. x->outlet1 = outlet_new(&x->ob, gensym("list"));
  142. x->outlet2 = outlet_new(&x->ob, gensym("list"));
  143. x->name = strdup("puredata");
  144. #endif
  145. for (i = 0; i < argc; i++) {
  146. if ((argv+i)->a_type == A_SYM) {
  147. if(strcmp(maxpd_atom_get_string(argv+i), "@alias") == 0) {
  148. if ((argv+i+1)->a_type == A_SYM) {
  149. alias = maxpd_atom_get_string(argv+i+1);
  150. i++;
  151. }
  152. }
  153. else if ((strcmp(maxpd_atom_get_string(argv+i), "@def") == 0) ||
  154. (strcmp(maxpd_atom_get_string(argv+i), "@definition") == 0)) {
  155. if ((argv+i+1)->a_type == A_SYM) {
  156. x->definition = strdup(maxpd_atom_get_string(argv+i+1));
  157. mapper_read_definition(x);
  158. i++;
  159. }
  160. }
  161. else if (strcmp(maxpd_atom_get_string(argv+i), "@learn") == 0) {
  162. if ((argv+i+1)->a_type == A_FLOAT) {
  163. learn = (maxpd_atom_get_float(argv+i+1) > 1) ? 0 : 1;
  164. i++;
  165. }
  166. #ifdef MAXMSP
  167. else if ((argv+i+1)->a_type == A_LONG) {
  168. learn = (atom_getlong(argv+i+1) > 1) ? 0 : 1;
  169. i++;
  170. }
  171. #endif
  172. }
  173. else if (strcmp(maxpd_atom_get_string(argv+i), "@interface") == 0) {
  174. if ((argv+i+1)->a_type == A_SYM) {
  175. iface = maxpd_atom_get_string(argv+i+1);
  176. i++;
  177. }
  178. }
  179. }
  180. }
  181. if (alias) {
  182. free(x->name);
  183. x->name = *alias == '/' ? strdup(alias+1) : strdup(alias);
  184. }
  185. post("mapper: using name %s", x->name);
  186. if (iface)
  187. post("mapper: trying interface %s", iface);
  188. else
  189. post("mapper: using default interface.");
  190. x->admin = mapper_admin_new(iface, 0, 0);
  191. if (!x->admin) {
  192. post("Error initializing admin.");
  193. return 0;
  194. }
  195. x->device = mdev_new(x->name, port, x->admin);
  196. if (!x->device) {
  197. post("Error initializing device.");
  198. return 0;
  199. }
  200. // add other declared properties
  201. for (i = 0; i < argc; i++) {
  202. if (i > argc - 2) // need 2 arguments for key and value
  203. break;
  204. if ((strcmp(maxpd_atom_get_string(argv+i), "@alias") == 0) ||
  205. (strcmp(maxpd_atom_get_string(argv+i), "@def") == 0) ||
  206. (strcmp(maxpd_atom_get_string(argv+i), "@definition") == 0) ||
  207. (strcmp(maxpd_atom_get_string(argv+i), "@learn") == 0) ||
  208. (strcmp(maxpd_atom_get_string(argv+i), "@interface") == 0)){
  209. i++;
  210. continue;
  211. }
  212. else if (maxpd_atom_get_string(argv+i)[0] == '@') {
  213. lo_arg *value;
  214. switch ((argv+i+1)->a_type) {
  215. case A_SYM: {
  216. value = (lo_arg *)(maxpd_atom_get_string(argv+i+1));
  217. mdev_set_property(x->device, maxpd_atom_get_string(argv+i)+1, LO_STRING, value);
  218. i++;
  219. break;
  220. }
  221. case A_FLOAT:
  222. value->f = maxpd_atom_get_float(argv+i+1);
  223. mdev_set_property(x->device, maxpd_atom_get_string(argv+i)+1, LO_FLOAT, value);
  224. i++;
  225. break;
  226. #ifdef MAXMSP
  227. case A_LONG:
  228. value->i32 = atom_getlong(argv+i+1);
  229. mdev_set_property(x->device, maxpd_atom_get_string(argv+i)+1, LO_INT32, value);
  230. i++;
  231. break;
  232. #endif
  233. default:
  234. break;
  235. }
  236. }
  237. }
  238. mapper_print_properties(x);
  239. x->ready = 0;
  240. x->learn_mode = learn;
  241. #ifdef MAXMSP
  242. mapper_register_signals(x);
  243. x->clock = clock_new(x, (method)mapper_poll); // Create the timing clock
  244. #else
  245. x->clock = clock_new(x, (t_method)mapper_poll);
  246. #endif
  247. clock_delay(x->clock, INTERVAL); // Set clock to go off after delay
  248. }
  249. return (x);
  250. }
  251. // *********************************************************
  252. // -(free)--------------------------------------------------
  253. void mapper_free(t_mapper *x)
  254. {
  255. clock_unset(x->clock); // Remove clock routine from the scheduler
  256. clock_free(x->clock); // Frees memeory used by clock
  257. #ifdef MAXMSP
  258. object_free(x->d); // Frees memory used by dictionary
  259. #endif
  260. if (x->device) {
  261. mdev_free(x->device);
  262. }
  263. if (x->admin) {
  264. mapper_admin_free(x->admin);
  265. }
  266. if (x->name) {
  267. free(x->name);
  268. }
  269. }
  270. // *********************************************************
  271. // -(print properties)--------------------------------------
  272. void mapper_print_properties(t_mapper *x)
  273. {
  274. if (x->ready) {
  275. //output name
  276. maxpd_atom_set_string(x->buffer, mdev_name(x->device));
  277. outlet_anything(x->outlet2, gensym("name"), 1, x->buffer);
  278. //output interface
  279. maxpd_atom_set_string(x->buffer, mdev_interface(x->device));
  280. outlet_anything(x->outlet2, gensym("interface"), 1, x->buffer);
  281. //output IP
  282. const struct in_addr *ip = mdev_ip4(x->device);
  283. maxpd_atom_set_string(x->buffer, inet_ntoa(*ip));
  284. outlet_anything(x->outlet2, gensym("IP"), 1, x->buffer);
  285. //output port
  286. maxpd_atom_set_int(x->buffer, mdev_port(x->device));
  287. outlet_anything(x->outlet2, gensym("port"), 1, x->buffer);
  288. //output numInputs
  289. maxpd_atom_set_int(x->buffer, mdev_num_inputs(x->device));
  290. outlet_anything(x->outlet2, gensym("numInputs"), 1, x->buffer);
  291. //output numOutputs
  292. maxpd_atom_set_int(x->buffer, mdev_num_outputs(x->device));
  293. outlet_anything(x->outlet2, gensym("numOutputs"), 1, x->buffer);
  294. }
  295. }
  296. // *********************************************************
  297. // -(inlet/outlet assist - maxmsp only)---------------------
  298. #ifdef MAXMSP
  299. void mapper_assist(t_mapper *x, void *b, long m, long a, char *s)
  300. {
  301. if (m == ASSIST_INLET) { // inlet
  302. sprintf(s, "OSC input");
  303. }
  304. else { // outlet
  305. if (a == 0) {
  306. sprintf(s, "Mapped OSC data");
  307. }
  308. else if (a == 1) {
  309. sprintf(s, "State queries");
  310. }
  311. else {
  312. sprintf(s, "Device information");
  313. }
  314. }
  315. }
  316. #endif
  317. // *********************************************************
  318. // -(add signal)--------------------------------------------
  319. void mapper_add_signal(t_mapper *x, t_symbol *s, int argc, t_atom *argv)
  320. {
  321. const char *sig_name = 0, *sig_units = 0;
  322. char sig_type = 0;
  323. int is_input, sig_min_int, sig_max_int, sig_length = 1;
  324. float sig_min_float, sig_max_float;
  325. long i;
  326. mapper_signal msig = 0;
  327. if (argc < 4) {
  328. post("mapper: not enough arguments for 'add' message.");
  329. return;
  330. }
  331. if ((argv->a_type != A_SYM) || ((argv+1)->a_type != A_SYM))
  332. return;
  333. if (strcmp(maxpd_atom_get_string(argv), "input") == 0)
  334. is_input = 1;
  335. else if (strcmp(maxpd_atom_get_string(argv), "output") == 0)
  336. is_input = 0;
  337. else
  338. return;
  339. // get signal name
  340. sig_name = maxpd_atom_get_string(argv+1);
  341. // get signal type, length, and units
  342. for (i = 2; i < argc; i++) {
  343. if (i > argc - 2) // need 2 arguments for key and value
  344. break;
  345. if ((argv+i)->a_type == A_SYM) {
  346. if (strcmp(maxpd_atom_get_string(argv+i), "@type") == 0) {
  347. if ((argv+i+1)->a_type == A_SYM) {
  348. sig_type = maxpd_atom_get_string(argv+i+1)[0];
  349. i++;
  350. }
  351. }
  352. else if (strcmp(maxpd_atom_get_string(argv+i), "@length") == 0) {
  353. if ((argv+i+1)->a_type == A_FLOAT) {
  354. sig_length = (int)maxpd_atom_get_float(argv+i+1);
  355. i++;
  356. }
  357. #ifdef MAXMSP
  358. else if ((argv+i+1)->a_type == A_LONG) {
  359. sig_length = atom_getlong(argv+i+1);
  360. i++;
  361. }
  362. #endif
  363. }
  364. else if(strcmp(maxpd_atom_get_string(argv+i), "@units") == 0) {
  365. if ((argv+i+1)->a_type == A_SYM) {
  366. sig_units = maxpd_atom_get_string(argv+i+1);
  367. i++;
  368. }
  369. }
  370. }
  371. }
  372. if (!sig_type) {
  373. post("mapper: signal has no declared type!");
  374. return;
  375. }
  376. if (sig_length < 1) {
  377. post("mapper: signals cannot have length < 1!");
  378. return;
  379. }
  380. if (is_input) {
  381. msig = mdev_add_input(x->device, sig_name, sig_length,
  382. sig_type, sig_units, 0, 0,
  383. sig_type == 'i' ? mapper_int_handler : mapper_float_handler, x);
  384. if (!msig) {
  385. post("mapper: error creating input!");
  386. return;
  387. }
  388. }
  389. else {
  390. msig = mdev_add_output(x->device, sig_name, sig_length,
  391. sig_type, sig_units, 0, 0);
  392. if (!msig) {
  393. post("mapper: error creating output!");
  394. return;
  395. }
  396. }
  397. // add other declared properties
  398. for (i = 2; i < argc; i++) {
  399. if (i > argc - 2) // need 2 arguments for key and value
  400. break;
  401. if ((strcmp(maxpd_atom_get_string(argv+i), "@type") == 0) ||
  402. (strcmp(maxpd_atom_get_string(argv+i), "@length") == 0) ||
  403. (strcmp(maxpd_atom_get_string(argv+i), "@units") == 0)){
  404. i++;
  405. continue;
  406. }
  407. if (strcmp(maxpd_atom_get_string(argv+i), "@min") == 0) {
  408. if ((argv+i+1)->a_type == A_FLOAT) {
  409. sig_min_float = maxpd_atom_get_float(argv+i+1);
  410. sig_min_int = (int)sig_min_float;
  411. msig_set_minimum(msig, sig_type == 'i' ? (void *)&sig_min_int : (void *)&sig_min_float);
  412. i++;
  413. }
  414. #ifdef MAXMSP
  415. else if ((argv + i + 1)->a_type == A_LONG) {
  416. sig_min_int = (int)atom_getlong(argv+i+1);
  417. sig_min_float = (float)sig_min_int;
  418. msig_set_minimum(msig, sig_type == 'i' ? (void *)&sig_min_int : (void *)&sig_min_float);
  419. i++;
  420. }
  421. #endif
  422. }
  423. else if (strcmp(maxpd_atom_get_string(argv+i), "@max") == 0) {
  424. if ((argv+i+1)->a_type == A_FLOAT) {
  425. sig_max_float = maxpd_atom_get_float(argv+i+1);
  426. sig_max_int = (int)sig_max_float;
  427. msig_set_maximum(msig, sig_type == 'i' ? (void *)&sig_max_int : (void *)&sig_max_float);
  428. i++;
  429. }
  430. #ifdef MAXMSP
  431. else if ((argv + i + 1)->a_type == A_LONG) {
  432. sig_max_int = (int)atom_getlong(argv+i+1);
  433. sig_max_float = (float)sig_max_int;
  434. msig_set_maximum(msig, sig_type == 'i' ? (void *)&sig_max_int : (void *)&sig_max_float);
  435. i++;
  436. }
  437. #endif
  438. }
  439. else if (maxpd_atom_get_string(argv+i)[0] == '@') {
  440. lo_arg *value;
  441. switch ((argv+i+1)->a_type) {
  442. case A_SYM: {
  443. value = (lo_arg *)maxpd_atom_get_string(argv+i+1);
  444. msig_set_property(msig, maxpd_atom_get_string(argv+i)+1, LO_STRING, value);
  445. i++;
  446. break;
  447. }
  448. case A_FLOAT:
  449. value->f = maxpd_atom_get_float(argv+i+1);
  450. msig_set_property(msig, maxpd_atom_get_string(argv+i)+1, LO_FLOAT, value);
  451. i++;
  452. break;
  453. #ifdef MAXMSP
  454. case A_LONG:
  455. value->i32 = atom_getlong(argv+i+1);
  456. msig_set_property(msig, maxpd_atom_get_string(argv+i)+1, LO_INT32, value);
  457. i++;
  458. break;
  459. #endif
  460. default:
  461. break;
  462. }
  463. }
  464. }
  465. // Update status outlet
  466. if (is_input) {
  467. //output numInputs
  468. maxpd_atom_set_int(x->buffer, mdev_num_inputs(x->device));
  469. outlet_anything(x->outlet2, gensym("numInputs"), 1, x->buffer);
  470. }
  471. else {
  472. //output numOutputs
  473. maxpd_atom_set_int(x->buffer, mdev_num_outputs(x->device));
  474. outlet_anything(x->outlet2, gensym("numOutputs"), 1, x->buffer);
  475. }
  476. }
  477. // *********************************************************
  478. // -(remove signal)-----------------------------------------
  479. void mapper_remove_signal(t_mapper *x, t_symbol *s, int argc, t_atom *argv)
  480. {
  481. mapper_signal msig;
  482. char *sig_name = NULL, *direction = NULL;
  483. if (argc < 2) {
  484. return;
  485. }
  486. if (argv->a_type != A_SYM || (argv+1)->a_type != A_SYM) {
  487. post("Unable to parse remove message!");
  488. return;
  489. }
  490. direction = strdup(maxpd_atom_get_string(argv));
  491. sig_name = strdup(maxpd_atom_get_string(argv+1));
  492. if (strcmp(direction, "output") == 0) {
  493. if (msig=mdev_get_output_by_name(x->device, sig_name, 0)) {
  494. mdev_remove_output(x->device, msig);
  495. maxpd_atom_set_int(x->buffer, mdev_num_outputs(x->device));
  496. outlet_anything(x->outlet2, gensym("numOutputs"), 1, x->buffer);
  497. }
  498. }
  499. else if (strcmp(direction, "input") == 0) {
  500. if (msig=mdev_get_input_by_name(x->device, sig_name, 0)) {
  501. mdev_remove_input(x->device, msig);
  502. maxpd_atom_set_int(x->buffer, mdev_num_inputs(x->device));
  503. outlet_anything(x->outlet2, gensym("numInputs"), 1, x->buffer);
  504. }
  505. }
  506. }
  507. // *********************************************************
  508. // -(set signal value)--------------------------------------
  509. void mapper_set(t_mapper *x, t_symbol *s, int argc, t_atom *argv)
  510. {
  511. // This method sets the value of an input signal.
  512. // This allows storing of input signal state changes generated by user actions rather than
  513. // libmapper messaging. This state storage is used by libmapper for (e.g.) retreiving information
  514. // for training implicit mapping algorithms.
  515. int i;
  516. if (!argc)
  517. return;
  518. if (!x->ready)
  519. return;
  520. if (argv->a_type != A_SYM)
  521. return;
  522. // find matching input signal
  523. mapper_signal msig = mdev_get_input_by_name(x->device, maxpd_atom_get_string(argv), 0);
  524. if (!msig) {
  525. post("Error setting value: signal named \"%s\" does not exist!", maxpd_atom_get_string(argv));
  526. return;
  527. }
  528. // get signal properties
  529. mapper_db_signal props = msig_properties(msig);
  530. if (props->length != argc - 1) {
  531. post("Error: vector length (%i) does not match signal definition (%i)!", argc - 1, props->length);
  532. return;
  533. }
  534. if (props->type == 'i') {
  535. int payload[props->length];
  536. for (i = 1; i < argc; i++) {
  537. if ((argv + i)->a_type == A_FLOAT)
  538. payload[i-1] = (int)atom_getfloat(argv + i);
  539. #ifdef MAXMSP
  540. else if ((argv + i)->a_type == A_LONG)
  541. payload[i-1] = (int)atom_getlong(argv + i);
  542. #endif
  543. }
  544. //update signal
  545. msig_update(msig, payload);
  546. }
  547. else if (props->type == 'f') {
  548. float payload[props->length];
  549. for (i = 1; i < argc; i++) {
  550. if ((argv + i)->a_type == A_FLOAT)
  551. payload[i-1] = atom_getfloat(argv + i);
  552. #ifdef MAXMSP
  553. else if ((argv + i)->a_type == A_LONG)
  554. payload[i-1] = (float)atom_getlong(argv + i);
  555. #endif
  556. }
  557. //update signal
  558. msig_update(msig, payload);
  559. }
  560. else {
  561. return;
  562. }
  563. }
  564. // *********************************************************
  565. // -(anything)----------------------------------------------
  566. void mapper_anything(t_mapper *x, t_symbol *s, int argc, t_atom *argv)
  567. {
  568. int i;
  569. if (argc) {
  570. //find signal
  571. mapper_signal msig;
  572. if (!(msig=mdev_get_output_by_name(x->device, s->s_name, 0))) {
  573. if (x->learn_mode) {
  574. // register as new signal
  575. if (argv->a_type == A_FLOAT) {
  576. msig = mdev_add_output(x->device, s->s_name, argc, 'f', 0, 0, 0);
  577. }
  578. #ifdef MAXMSP
  579. else if (argv->a_type == A_LONG) {
  580. msig = mdev_add_output(x->device, s->s_name, argc, 'i', 0, 0, 0);
  581. }
  582. #endif
  583. else {
  584. return;
  585. }
  586. //output updated numOutputs
  587. #ifdef MAXMSP
  588. atom_setsym(x->buffer, gensym("numOutputs"));
  589. atom_setlong(x->buffer + 1, mdev_num_outputs(x->device));
  590. outlet_anything(x->outlet2, ps_list, 2, x->buffer);
  591. #else
  592. SETFLOAT(x->buffer, mdev_num_outputs(x->device));
  593. outlet_anything(x->outlet2, gensym("numOutputs"), 1, x->buffer);
  594. #endif
  595. }
  596. else {
  597. return;
  598. }
  599. }
  600. mapper_db_signal props = msig_properties(msig);
  601. if (props->length != argc) {
  602. post("Error: vector length does not match signal definition!");
  603. return;
  604. }
  605. if (props->type == 'i') {
  606. int payload[props->length];
  607. for (i = 0; i < argc; i++) {
  608. if ((argv + i)->a_type == A_FLOAT)
  609. payload[i] = (int)atom_getfloat(argv + i);
  610. #ifdef MAXMSP
  611. else if ((argv + i)->a_type == A_LONG)
  612. payload[i] = (int)atom_getlong(argv + i);
  613. #endif
  614. }
  615. //update signal
  616. msig_update(msig, payload);
  617. }
  618. else if (props->type == 'f') {
  619. float payload[props->length];
  620. for (i = 0; i < argc; i++) {
  621. if ((argv + i)->a_type == A_FLOAT)
  622. payload[i] = atom_getfloat(argv + i);
  623. #ifdef MAXMSP
  624. else if ((argv + i)->a_type == A_LONG)
  625. payload[i] = (float)atom_getlong(argv + i);
  626. #endif
  627. }
  628. //update signal
  629. msig_update(msig, payload);
  630. }
  631. else {
  632. return;
  633. }
  634. }
  635. }
  636. // *********************************************************
  637. // -(int handler)-------------------------------------------
  638. void mapper_int_handler(mapper_signal msig, mapper_db_signal props, mapper_timetag_t *time, void *value)
  639. {
  640. if (value) {
  641. t_mapper *x = props->user_data;
  642. int i, length = props->length;
  643. int *v = value;
  644. if (length > (MAX_LIST-1)) {
  645. post("Maximum list length is %i!", MAX_LIST-1);
  646. length = MAX_LIST-1;
  647. }
  648. for (i = 0; i < length; i++)
  649. maxpd_atom_set_int(x->buffer + i, v[i]);
  650. outlet_anything(x->outlet1, gensym((char *)props->name), length, x->buffer);
  651. }
  652. }
  653. // *********************************************************
  654. // -(float handler)-----------------------------------------
  655. void mapper_float_handler(mapper_signal msig, mapper_db_signal props, mapper_timetag_t *time, void *value)
  656. {
  657. if (value) {
  658. t_mapper *x = props->user_data;
  659. int i, length = props->length;
  660. float *v = value;
  661. if (length > (MAX_LIST-1)) {
  662. post("Maximum list length is %i!", MAX_LIST-1);
  663. length = MAX_LIST-1;
  664. }
  665. for (i = 0; i < length; i++)
  666. maxpd_atom_set_float(x->buffer + i, v[i]);
  667. outlet_anything(x->outlet1, gensym((char *)props->name), length, x->buffer);
  668. }
  669. }
  670. // *********************************************************
  671. // -(read device definition - maxmsp only)------------------
  672. void mapper_read_definition (t_mapper *x)
  673. {
  674. #ifdef MAXMSP
  675. if (x->d) {
  676. object_free(x->d);
  677. }
  678. t_object *info;
  679. t_symbol *sym_device = gensym("device");
  680. t_symbol *sym_name = gensym("name");
  681. const char *my_name = 0;
  682. short path;
  683. long filetype = 'JSON', outtype;
  684. // TODO: add ".json" to end of string if missing (or pick new filetype!)
  685. if (locatefile_extended(x->definition, &path, &outtype, &filetype, 1) == 0) {
  686. post("located file %s", x->definition);
  687. if (dictionary_read(x->definition, path, &(x->d)) == 0) {
  688. //check that first key is "device"
  689. if (dictionary_entryisdictionary(x->d, sym_device)) {
  690. //recover name from dictionary
  691. dictionary_getdictionary(x->d, sym_device, &info);
  692. dictionary_getstring((t_dictionary *)info, sym_name, &my_name);
  693. if (my_name) {
  694. free(x->name);
  695. x->name = *my_name == '/' ? strdup(my_name+1) : strdup(my_name);
  696. }
  697. }
  698. }
  699. else {
  700. post("Could not parse file %s", x->definition);
  701. }
  702. }
  703. else {
  704. post("Could not locate file %s", x->definition);
  705. }
  706. #endif
  707. }
  708. // *********************************************************
  709. // -(register signals from dictionary - maxmsp only)--------
  710. #ifdef MAXMSP
  711. void mapper_register_signals(t_mapper *x) {
  712. t_atom *signals;
  713. long num_signals, i;
  714. t_object *device, *inputs, *outputs, *temp;
  715. t_symbol *sym_device = gensym("device");
  716. t_symbol *sym_inputs = gensym("inputs");
  717. t_symbol *sym_outputs = gensym("outputs");
  718. t_symbol *sym_name = gensym("name");
  719. t_symbol *sym_type = gensym("type");
  720. t_symbol *sym_units = gensym("units");
  721. t_symbol *sym_minimum = gensym("minimum");
  722. t_symbol *sym_maximum = gensym("maximum");
  723. t_symbol *sym_length = gensym("length");
  724. const char *sig_name, *sig_units, *sig_type;
  725. char sig_type_char = 0;
  726. double sig_min_double, sig_max_double;
  727. float sig_min_float, sig_max_float;
  728. long sig_min_long, sig_max_long, sig_length;
  729. int sig_min_int, sig_max_int;
  730. mapper_signal temp_sig;
  731. short range_known[2];
  732. if (x->d) {
  733. // Get pointer to dictionary "device"
  734. if (dictionary_getdictionary(x->d, sym_device, &device) == MAX_ERR_NONE) {
  735. // Get pointer to atom array "inputs"
  736. if (dictionary_getatomarray((t_dictionary *)device, sym_inputs, &inputs) == MAX_ERR_NONE) {
  737. atomarray_getatoms((t_atomarray *)inputs, &num_signals, &signals);
  738. // iterate through array of atoms
  739. for (i=0; i<num_signals; i++) {
  740. // initialize variables
  741. if (sig_units) {
  742. free(&sig_units);
  743. }
  744. if (sig_type) {
  745. free(&sig_type);
  746. }
  747. sig_length = 1;
  748. range_known[0] = 1;
  749. range_known[1] = 1;
  750. // each atom object points to a dictionary, need to recover atoms by key
  751. temp = atom_getobj(&(signals[i]));
  752. if (dictionary_getstring((t_dictionary *)temp, sym_name, &sig_name) == MAX_ERR_NONE) {
  753. dictionary_getstring((t_dictionary *)temp, sym_units, &sig_units);
  754. dictionary_getstring((t_dictionary *)temp, sym_type, &sig_type);
  755. dictionary_getlong((t_dictionary *)temp, sym_length, &sig_length);
  756. if (dictionary_getfloat((t_dictionary *)temp, sym_minimum, &sig_min_double) == MAX_ERR_NONE) {
  757. sig_min_float = (float)sig_min_double;
  758. sig_min_int = (int)sig_min_double;
  759. range_known[0] = 1;
  760. }
  761. else if (dictionary_getlong((t_dictionary *)temp, sym_minimum, &sig_min_long) == MAX_ERR_NONE) {
  762. sig_min_float = (float)sig_min_long;
  763. sig_min_int = (int)sig_min_long;
  764. range_known[0] = 1;
  765. }
  766. if (dictionary_getfloat((t_dictionary *)temp, sym_maximum, &sig_max_double) == MAX_ERR_NONE) {
  767. sig_max_float = (float)sig_max_double;
  768. sig_max_int = (int)sig_max_double;
  769. range_known[1] = 1;
  770. }
  771. else if (dictionary_getlong((t_dictionary *)temp, sym_maximum, &sig_max_long) == MAX_ERR_NONE) {
  772. sig_max_float = (float)sig_max_long;
  773. sig_max_int = (int)sig_max_long;
  774. range_known[1] = 1;
  775. }
  776. if ((strcmp(sig_type, "int") == 0) || (strcmp(sig_type, "i") == 0))
  777. sig_type_char = 'i';
  778. else if ((strcmp(sig_type, "float") == 0) || (strcmp(sig_type, "f") == 0))
  779. sig_type_char = 'f';
  780. else {
  781. post("Skipping registration of signal %s (unknown type).", sig_name);
  782. continue;
  783. }
  784. temp_sig = mdev_add_input(x->device, sig_name, (int)sig_length, sig_type_char, sig_units, 0, 0,
  785. sig_type_char == 'i' ? mapper_int_handler : mapper_float_handler, x);
  786. if (temp_sig) {
  787. if (range_known[0]) {
  788. msig_set_minimum(temp_sig, sig_type_char == 'i' ? (void *)&sig_min_int : (void *)&sig_min_float);
  789. }
  790. if (range_known[1]) {
  791. msig_set_maximum(temp_sig, sig_type_char == 'i' ? (void *)&sig_max_int : (void *)&sig_max_float);
  792. }
  793. }
  794. }
  795. }
  796. }
  797. // Get pointer to atom array "outputs"
  798. if (dictionary_getatomarray((t_dictionary *)device, sym_outputs, &outputs) == MAX_ERR_NONE) {
  799. atomarray_getatoms((t_atomarray *)outputs, &num_signals, &signals);
  800. // iterate through array of atoms
  801. for (i=0; i<num_signals; i++) {
  802. // initialize variables
  803. if (sig_units) {
  804. free(&sig_units);
  805. }
  806. if (sig_type) {
  807. free(&sig_type);
  808. }
  809. sig_length = 1;
  810. range_known[0] = 1;
  811. range_known[1] = 1;
  812. // each atom object points to a dictionary, need to recover atoms by key
  813. temp = atom_getobj(&(signals[i]));
  814. if (dictionary_getstring((t_dictionary *)temp, sym_name, &sig_name) == MAX_ERR_NONE) {
  815. dictionary_getstring((t_dictionary *)temp, sym_units, &sig_units);
  816. dictionary_getstring((t_dictionary *)temp, sym_type, &sig_type);
  817. dictionary_getlong((t_dictionary *)temp, sym_length, &sig_length);
  818. if (dictionary_getfloat((t_dictionary *)temp, sym_minimum, &sig_min_double) == MAX_ERR_NONE) {
  819. sig_min_float = (float)sig_min_double;
  820. sig_min_int = (int)sig_min_double;
  821. range_known[0] = 1;
  822. }
  823. else if (dictionary_getlong((t_dictionary *)temp, sym_minimum, &sig_min_long) == MAX_ERR_NONE) {
  824. sig_min_float = (float)sig_min_long;
  825. sig_min_int = (int)sig_min_long;
  826. range_known[0] = 1;
  827. }
  828. if (dictionary_getfloat((t_dictionary *)temp, sym_maximum, &sig_max_double) == MAX_ERR_NONE) {
  829. sig_max_float = (float)sig_max_double;
  830. sig_max_int = (int)sig_max_double;
  831. range_known[1] = 1;
  832. }
  833. else if (dictionary_getlong((t_dictionary *)temp, sym_maximum, &sig_max_long) == MAX_ERR_NONE) {
  834. sig_max_float = (float)sig_max_long;
  835. sig_max_int = (int)sig_max_long;
  836. range_known[1] = 1;
  837. }
  838. if ((strcmp(sig_type, "int") == 0) || (strcmp(sig_type, "i") == 0))
  839. sig_type_char = 'i';
  840. else if ((strcmp(sig_type, "float") == 0) || (strcmp(sig_type, "f") == 0))
  841. sig_type_char = 'f';
  842. else {
  843. post("Skipping registration of signal %s (unknown type).", sig_name);
  844. continue;
  845. }
  846. temp_sig = mdev_add_output(x->device, sig_name, (int)sig_length, sig_type_char, sig_units, 0, 0);
  847. if (temp_sig) {
  848. if (range_known[0]) {
  849. msig_set_minimum(temp_sig, sig_type_char == 'i' ? (void *)&sig_min_int : (void *)&sig_min_float);
  850. }
  851. if (range_known[1]) {
  852. msig_set_maximum(temp_sig, sig_type_char == 'i' ? (void *)&sig_max_int : (void *)&sig_max_float);
  853. }
  854. }
  855. }
  856. }
  857. }
  858. }
  859. }
  860. }
  861. #endif
  862. // *********************************************************
  863. // -(poll libmapper)----------------------------------------
  864. void mapper_poll(t_mapper *x)
  865. {
  866. mdev_poll(x->device, 0);
  867. if (!x->ready) {
  868. if (mdev_ready(x->device)) {
  869. //mapper_db_dump(db);
  870. x->ready = 1;
  871. mapper_print_properties(x);
  872. }
  873. }
  874. clock_delay(x->clock, INTERVAL); // Set clock to go off after delay
  875. }
  876. // *********************************************************
  877. // -(toggle learning mode)----------------------------------
  878. void mapper_learn(t_mapper *x, t_symbol *s, int argc, t_atom *argv)
  879. {
  880. int mode = x->learn_mode;
  881. if (argc > 0) {
  882. if (argv->a_type == A_FLOAT) {
  883. mode = (int)atom_getfloat(argv);
  884. }
  885. #ifdef MAXMSP
  886. else if (argv->a_type == A_LONG) {
  887. mode = (int)atom_getlong(argv);
  888. }
  889. #endif
  890. if (mode != x->learn_mode) {
  891. x->learn_mode = mode;
  892. if (mode == 0)
  893. post("Learning mode off.");
  894. else
  895. post("Learning mode on.");
  896. }
  897. }
  898. }
  899. // *********************************************************
  900. // some helper functions for abtracting differences
  901. // between maxmsp and puredata
  902. const char *maxpd_atom_get_string(t_atom *a)
  903. {
  904. #ifdef MAXMSP
  905. return atom_getsym(a)->s_name;
  906. #else
  907. return (a)->a_w.w_symbol->s_name;
  908. #endif
  909. }
  910. void maxpd_atom_set_string(t_atom *a, const char *string)
  911. {
  912. #ifdef MAXMSP
  913. atom_setsym(a, gensym((char *)string));
  914. #else
  915. SETSYMBOL(a, gensym(string));
  916. #endif
  917. }
  918. void maxpd_atom_set_int(t_atom *a, int i)
  919. {
  920. #ifdef MAXMSP
  921. atom_setlong(a, (long)i);
  922. #else
  923. SETFLOAT(a, (double)i);
  924. #endif
  925. }
  926. double maxpd_atom_get_float(t_atom *a)
  927. {
  928. return (double)atom_getfloat(a);
  929. }
  930. void maxpd_atom_set_float(t_atom *a, float d)
  931. {
  932. #ifdef MAXMSP
  933. atom_setfloat(a, d);
  934. #else
  935. SETFLOAT(a, d);
  936. #endif
  937. }