Jamoma API  0.6.0.a19
j.oscroute.cpp
Go to the documentation of this file.
1 /** @file
2  *
3  * @ingroup implementationMaxExternals
4  *
5  * @brief j.oscroute - parse and pass OSC messages
6  *
7  * @details
8  *
9  * @authors Tim Place, Trond Lossius
10  *
11  * @copyright Copyright © 2006 Tim Place @n
12  * This code is licensed under the terms of the "New BSD License" @n
13  * http://creativecommons.org/licenses/BSD/
14  */
15 
16 
17 #include "j.oscroute.h"
18 
19 /************************************************************************************/
20 // Main() Function
21 
22 int JAMOMA_EXPORT_MAXOBJ main(void)
23 {
24  t_class *c;
25 
26  // Initialize Globals
27  jamoma_init();
28  common_symbols_init();
29 
30  // Define our class
31  c = class_new("j.oscroute",(method)oscroute_new, (method)oscroute_free, sizeof(t_oscroute), (method)0L, A_GIMME, 0);
32 
33  // Make methods accessible for our class:
34  class_addmethod(c, (method)oscroute_bang, "bang", 0L, 0L);
35  class_addmethod(c, (method)oscroute_int, "int", A_DEFLONG, 0L);
36  class_addmethod(c, (method)oscroute_float, "float", A_DEFFLOAT, 0L);
37  class_addmethod(c, (method)oscroute_list, "list", A_GIMME, 0L);
38  class_addmethod(c, (method)oscroute_symbol, "anything", A_GIMME, 0L);
39  class_addmethod(c, (method)oscroute_assist, "assist", A_CANT, 0L);
40  class_addmethod(c, (method)object_obex_dumpout, "dumpout", A_CANT, 0);
41 
42  // Finalize our class
43  class_register(CLASS_BOX, c);
44  oscroute_class = c;
45  return 0;
46 }
47 
48 
49 /************************************************************************************/
50 // Object Life
51 
52 void *oscroute_new(t_symbol *s, long argc, t_atom *argv)
53 {
54  short i;
55  t_oscroute *x = (t_oscroute *)object_alloc(oscroute_class);
56 
57  if (x) {
58  x->outlet_overflow = outlet_new(x, 0); // overflow outlet
59  //object_obex_store((void *)x, _sym_dumpout, (object *)x->outlet_overflow); // dumpout
60  x->num_args = argc;
61 
62  // If no argumentss are provided, we create one proxy inlet so that the arg can be set using an inlet
63  if (argc < 1) {
64  x->num_args = 1;
65  x->arguments[0] = gensym("/nil");
66  x->arglen[0] = 4;
67  x->proxy_inlet[0] = proxy_new(x, 1, 0L);
68  x->outlets[0] = outlet_new(x, 0);
69  }
70  else {
71  // If we have arguments, we create one proxy inlet (right to left) for each of them, so that they can be dynamically changed.
72  for (i=argc; i>0; i--)
73  x->proxy_inlet[i-1] = proxy_new(x, i, 0L);
74  for (i=x->num_args-1; i >= 0; i--) {
75  x->outlets[i] = outlet_new(x, 0); // Create Outlet
76  switch(argv[i].a_type) {
77  case A_SYM:
78  //atom_setsym(&(x->arguments[i]), atom_getsym(argv+i));
79  x->arguments[i] = atom_getsym(argv+i);
80  x->arglen[i] = strlen(atom_getsym(argv+i)->s_name);
81  break;
82  case A_LONG:
83  {
84  char tempstr[256];
85 
86  snprintf(tempstr, 256, "%ld", atom_getlong(argv+i));
87  x->arguments[i] = gensym(tempstr);
88  x->arglen[i] = strlen(tempstr);
89  }
90  break;
91  case A_FLOAT:
92  {
93  char tempstr[256];
94 
95  snprintf(tempstr, 256, "%f", atom_getfloat(argv+i));
96  x->arguments[i] = gensym(tempstr);
97  x->arglen[i] = strlen(tempstr);
98  }
99  break;
100  default:
101  error("j.oscroute - invalid arguments - all args must be symbols");
102  }
103  }
104  }
105  }
106  return (x); // return the pointer to our new instantiation
107 }
108 
109 void oscroute_free(t_oscroute *x)
110 {
111  short i;
112 
113  // All proxy objects must be freed
114  for (i=0; i<x->num_args; i++)
115  freeobject((t_object *)(x->proxy_inlet[i]));
116 }
117 
118 
119 
120 /************************************************************************************/
121 // Methods bound to input/inlets
122 
123 // Method for Assistance Messages
124 void oscroute_assist(t_oscroute *x, void *b, long msg, long arg, char *dst)
125 {
126  if (msg==1) // Inlet
127  strcpy(dst, "Input");
128  else if (msg==2) { // Outlets
129  if (arg < x->num_args)
130  strcpy(dst, x->arguments[arg]->s_name);
131  else
132  strcpy(dst, "dumpout / overflow from non-matching input");
133  }
134 }
135 
136 
137 // BANG INPUT: STRAIGHT TO OVERFLOW
138 void oscroute_bang(t_oscroute *x)
139 {
140  outlet_bang(x->outlet_overflow);
141 }
142 
143 // INT INPUT: STRAIGHT TO OVERFLOW
144 void oscroute_int(t_oscroute *x, long n)
145 {
146  outlet_int(x->outlet_overflow, n);
147 }
148 
149 // FLOAT INPUT: STRAIGHT TO OVERFLOW
150 void oscroute_float(t_oscroute *x, double f)
151 {
152  outlet_float(x->outlet_overflow, f);
153 }
154 
155 // LIST INPUT: STRAIGHT TO OVERFLOW
156 void oscroute_list(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv)
157 {
158  outlet_list(x->outlet_overflow, _sym_list, argc , argv);
159 }
160 
161 void output_msg(t_oscroute *x, char *msg, int outlet, long argc, t_atom *argv)
162 {
163  t_symbol *output;
164  if (msg == 0) {
165 
166  if (argc == 0) {
167  outlet_bang(x->outlets[outlet]);
168  } else if (argc==1) {
169 
170  if (argv->a_type==A_LONG)
171  outlet_int(x->outlets[outlet],argv->a_w.w_long);
172  else if (argv->a_type==A_FLOAT)
173  outlet_float(x->outlets[outlet],argv->a_w.w_float);
174  else if (argv->a_type==A_SYM)
175  outlet_anything(x->outlets[outlet],argv->a_w.w_sym,0,0);
176 
177  } else {
178  if (argv->a_type==A_SYM) {
179  output = argv->a_w.w_sym;
180  argc--;
181  argv++;
182  } else {
183  output = _sym_list;
184  }
185 
186  outlet_anything(x->outlets[outlet], output, argc, argv);
187  }
188  } else
189  outlet_anything(x->outlets[outlet], gensym(msg), argc, argv);
190 
191 }
192 
193 // SYMBOL INPUT
194 void oscroute_symbol(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv)
195 {
196  t_symbol *output;
197  char input[MAX_MESS_SIZE]; // our input string
198  long inlet = proxy_getinlet((t_object *)x);
199 
200  // If the message comes in the second (or third, ...) inlet, then set the string to match...
201  if (inlet > 0) {
202  x->arguments[inlet-1] = msg;
203  x->arglen[inlet-1] = strlen(msg->s_name);
204  return;
205  }
206 
207  // Otherwise match the stored string(s) and output...
208  strcpy(input, msg->s_name);
209 
210  /* to -- the introduction of relative address feature
211  in modular0.6 make this test useless
212 
213  // Make sure we are dealing with valid OSC input by looking for a leading slash
214  if (input[0] != '/') {
215  outlet_anything(x->outlet_overflow, msg, argc , argv);
216  return;
217  }
218  */
219 
220  char *wc, *c;
221  bool overFlow = true;
222  for (int pos=0; pos < x->num_args; pos++) {
223  // Look for exact matches first.
224  if (strncmp(msg->s_name, x->arguments[pos]->s_name, x->arglen[pos])==0) {
225  // If incoming message is longer than argument...
226  if (strlen(msg->s_name) > x->arglen[pos]) {
227  // ...it is only a match if it continues with a slash
228  if (input[x->arglen[pos]] == '/') {
229  output = gensym(msg->s_name + x->arglen[pos] +1); // 0.6 changes : +1 to remove don't have a leading slash and output a relative adddress
230  outlet_anything(x->outlets[pos], output, argc , argv);
231  overFlow = false;
232  break;
233  }
234  }
235  // If the incoming message is no longer we know that we have a match
236  else {
237 
238  // We then have to check what message to return.
239  // The message received has no arguments:
240  if (argc == 0) {
241  outlet_bang(x->outlets[pos]);
242  overFlow = false;
243  break;
244  }
245  // The message received has one argument only:
246  else if (argc==1) {
247  overFlow = false;
248  // int argument
249  if (argv->a_type==A_LONG) {
250  outlet_int(x->outlets[pos],argv->a_w.w_long);
251  break;
252  }
253  // float argument
254  else if (argv->a_type==A_FLOAT) {
255  outlet_float(x->outlets[pos],argv->a_w.w_float);
256  break;
257  }
258  // something else
259  else if (argv->a_type==A_SYM) {
260  outlet_anything(x->outlets[pos],argv->a_w.w_sym,0,0);
261  break;
262  }
263  else { // something completely different: copy to output as list
264  outlet_anything(x->outlets[pos], _sym_list, 1, argv);
265  break;
266  }
267  }
268  // There are two or more arguments: check if first is A_SYM
269  else {
270  if (argv->a_type==A_SYM) {
271  output = argv->a_w.w_sym;
272  argc--;
273  argv++;
274  }
275  else
276  output = _sym_list;
277  outlet_anything(x->outlets[pos], output, argc , argv);
278  overFlow = false;
279  break;
280  }
281  }
282  }
283  }
284  // XXX Putting this here makes crashes go away. It would be really good to know why.
285  //cpost("temp hack to prevent optimizations that cause this object to crash in Deployment");
286  // If no exact matches, look for wildcards.
287  for (int index=0; index < x->num_args; index++) {
288 
289  if (wc = strstr(x->arguments[index]->s_name, "*")) {
290  // Does the argument have anything following the wildcard?
291  if (*(wc+1) == '\0') {
292  // Now compare the argument up to the asterisk to the message
293  if (strncmp(msg->s_name, x->arguments[index]->s_name, x->arglen[index] - 1) == 0) {
294 
295  // Increment string past everything that matches including the asterisk
296  char *temp = msg->s_name + (x->arglen[index] - 1);
297  // Check for a slash, an asterisk causes us to strip off everything up to the next slash
298  char *outMsg = strstr(temp, "/");
299  if (outMsg)
300  output_msg(x, outMsg, index, argc, argv);
301  else {
302  // no slash, output everything following the message
303  output_msg(x, NULL, index, argc, argv);
304  }
305  return;
306  } else {
307  // We break here because if the strncmp() fails it means we have a wildcard following an
308  // OSC message i.e. /robot/* but the incoming message doesn't begin with /robot
309  //break;
310  }
311  } else {
312  // There is no NULL char after asterisk
313  c = msg->s_name;
314  while (wc && *(wc) == '*') {
315  wc++;
316  c++;
317  }
318 
319  c += strlen(c) - strlen(wc);
320  if (strncmp(c, wc, strlen(c)) == 0) {
321  output_msg(x, c, index, argc, argv);
322  return;
323  }
324  }
325  }
326  }
327 
328  // the message was never reckognised
329  if (overFlow)
330  outlet_anything(x->outlet_overflow, msg, argc , argv);
331 }
void oscroute_assist(t_oscroute *x, void *b, long msg, long arg, char *dst)
Provide assistance on input and output while patching.
Definition: j.oscroute.cpp:124
void oscroute_free(t_oscroute *x)
Object instance destructor, ensures that all memory assigned is properly freed.
Definition: j.oscroute.cpp:109
void oscroute_float(t_oscroute *x, double f)
Method called when a "float" is passed to the object.
Definition: j.oscroute.cpp:150
void oscroute_bang(t_oscroute *x)
Method called when a "bang" is passed to the object.
Definition: j.oscroute.cpp:138
void oscroute_int(t_oscroute *x, long n)
Method called when an "int" is passed to the object.
Definition: j.oscroute.cpp:144
int JAMOMA_EXPORT_MAXOBJ main(void)
Set up this class as a Max external the first time an object of this kind is instantiated.
Definition: j.oscroute.cpp:22
j.oscroute - parse and pass OSC messages
t_class * oscroute_class
Required: Global pointer for our class.
Definition: j.oscroute.h:104
void oscroute_list(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv)
Method called when a list is passed to the object.
Definition: j.oscroute.cpp:156
void oscroute_symbol(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv)
Method called when a symbol is passed to the object.
Definition: j.oscroute.cpp:194
void * oscroute_new(t_symbol *s, long argc, t_atom *argv)
Object instance constructor.
Definition: j.oscroute.cpp:52