CSL  5.2
OSC_support.cpp
Go to the documentation of this file.
1 //
2 // OSC_support.cpp -- CSL support functions for use with OSC input.
3 // See the copyright notice and acknowledgment of authors in the file COPYRIGHT
4 //
5 // This file has a bunch of the "glue" code necessary to use OSC simply from within CSL.
6 // For an example, see OSC_main.cpp (which uses CSL instruymkents) GestureSensorTests.cpp,
7 // which interfaces to the CREATE gesture sensors using OSC, or Server_Tests.cpp, which
8 // adds a few simple OSC commands for controlling the random bell textures.
9 //
10 // To use this in your own main, add the following:
11 // // setup call for OSC addr space mgmnt
12 // initOSCAddrSpace();
13 // // add an OSC command callback
14 // addOSCMethod(mCmd, callback);
15 //
16 // // or use an instrument library
17 // setupOSCInstrLibrary(vector<Instrument *> library);
18 //
19 // // Run the main loop function (doesn't return)
20 // mainOSCLoop(udp_port);
21 //
22 // Functions
23 
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 
28 #include "lo/lo.h"
29 
30 #include "BasicFMInstrument.h"
31 //#include "SndFileInstrument.h"
32 //#include "OSC_cpp.h"
33 
34 int done = 0;
35 
36 void error(int num, const char *m, const char *path);
37 int generic_handler(const char *path, const char *types, lo_arg **argv,
38  int argc, void *data, void *user_data);
39 int foo_handler(const char *path, const char *types, lo_arg **argv, int argc,
40  void *data, void *user_data);
41 int quit_handler(const char *path, const char *types, lo_arg **argv, int argc,
42  void *data, void *user_data);
43 
44 #define MAX_ACCESSORS 64 // max number of instrument accessors
45 
46 using namespace csl;
47 
48 // Prototypes for "glue" code
49 
50 extern "C" void initOSCReceive();
51 extern "C" void initOSCAddrSpace();
52 extern "C" void setupOSCInstrLibrary(std::vector<Instrument *> library);
53 #define addOSCMethod(name, nfunction) \
54  lo_server_thread_add_method(sSrvThrd, nname, NULL, nfunction, NULL)
55 
56 extern "C" void addOSCMethod2(name, nfunction, void * user_data);
57 
58  /* add method that will match the path /foo/bar, with two numbers, coerced
59  * to float and int */
60  lo_server_thread_add_method(sSrvThrd, "/foo/bar", "fi", foo_handler, NULL);
61 
62 
63 extern "C" void mainOSCLoop(int port);
64 extern "C" void quitCSL();
65 
66 // OSC globals
67 
69 
70 void error(int num, const char *msg, const char *path)
71 {
72  printf("liblo server error %d in path %s: %s\n", num, path, msg);
73  fflush(stdout);
74 }
75 
76 /* catch any incoming messages and display them. returning 1 means that the
77  * message has not been fully handled and the server should try other methods */
78 int generic_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) {
79  int i;
80  printf("path: <%s>\n", path);
81  for (i=0; i<argc; i++) {
82  printf("arg %d '%c' ", i, types[i]);
83  lo_arg_pp(types[i], argv[i]);
84  printf("\n");
85  }
86  printf("\n");
87  fflush(stdout);
88 
89  return 1;
90 }
91 
92 int foo_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) {
93  /* example showing pulling the argument values out of the argv array */
94  printf("%s <- f:%f, i:%d\n\n", path, argv[0]->f, argv[1]->i);
95  fflush(stdout);
96 
97  return 0;
98 }
99 
100 int quit_handler(const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) {
101  done = 1;
102  printf("quiting\n\n");
103  fflush(stdout);
104  // Shut down and quit
105  logMsg("OSC server exiting.");
107  IO * io = IO :: theInstance();
108  io->stop(); // stop it
109  io->close();
110  exit(0);
111 }
112 
113 // OSC support functions
114 
115 // Set up the receive Q
116 
117 extern "C" void initOSCReceive() {
118 
119  /* start a new server on port 7770 */
121 }
122 
123 // Main OSC loop -- select - read - dispatch
124 
125 extern "C" void mainOSCLoop(int port) {
126  /* add method that will match any path and args */
128  /* add method that will match the path /quit with no args */
130  // start lo!
132 
133  while (!done) {
134 #ifdef WIN32
135  Sleep(1);
136 #else
137  usleep(1000);
138 #endif
139  }
140 quit:
141  quitCSL();
142  return 0;
143 }
144 
145 /////////////////////////// OSC Helper Functions /////////////////////////////
146 
147 // Structure passed to OSC to hold a UGEN reference and a parameter selector
148 
149 typedef struct {
151  unsigned num;
152  unsigned selector;
153 } Inst_Context;
154 
155 // General-purpose type-checking parameter-setter methods for Instruments
156 
157 void floatParamSetter(void * con, int arglen, const void * vargs, OSCTimeTag when, NetworkReturnAddressPtr ra) {
158  char * error;
159  Inst_Context * context = (Inst_Context *) con;
160  char * typeString = (char *) vargs;
161  void * otherArgs = (void *) OSCDataAfterAlignedString(typeString, typeString+arglen, &error);
162  if (strcmp(typeString, ",f")) {
163  logMsg(kLogError, "ERROR: Invalid type string in OSC message, expected \",f\" got \"%s\"", typeString);
164  fflush(stdout);
165  return;
166  }
167  logMsg("OSC set float param %d/%d to %g", (context->num + 1), context->selector, ((float *) otherArgs)[0]);
168  fflush(stdout);
169  context->instr->setParameter(context->selector, otherArgs);
170 }
171 
172 void intParamSetter(void * con, int arglen, const void * vargs, OSCTimeTag when, NetworkReturnAddressPtr ra) {
173  char * error;
174  Inst_Context * context = (Inst_Context *) con;
175  char * typeString = (char *) vargs;
176  void * otherArgs = (void *) OSCDataAfterAlignedString(typeString, typeString+arglen, &error);
177  if (strcmp(typeString, ",i")) {
178  logMsg(kLogError, "ERROR: Invalid type string in OSC message, expected \",i\" got \"%s\"", typeString);
179  return;
180  }
181  logMsg("OSC set int param %d/%d to %d", (context->num + 1), context->selector, ((int *) otherArgs)[0]);
182  fflush(stdout);
183  context->instr->setParameter(context->selector, otherArgs);
184 }
185 
186 void stringParamSetter(void * con, int arglen, const void * vargs, OSCTimeTag when, NetworkReturnAddressPtr ra) {
187  char * error;
188  Inst_Context * context = (Inst_Context *) con;
189  char * typeString = (char *) vargs;
190  void * otherArgs = (void *) OSCDataAfterAlignedString(typeString, typeString+arglen, &error);
191  if (strcmp(typeString, ",s")) {
192  logMsg(kLogError, "ERROR: Invalid type string in OSC message, expected \",s\" got \"%s\"", typeString);
193  return;
194  }
195  logMsg("OSC set string param %d/%d to %s", (context->num + 1), context->selector, (char *) otherArgs);
196  context->instr->setParameter(context->selector, otherArgs);
197 }
198 
199 // Play a note by re-triggering the main envelope
200 
201 void playNote(void * con, int arglen, const void * vargs, OSCTimeTag when, NetworkReturnAddressPtr ra) {
202  Inst_Context * context = (Inst_Context *) con;
203  logMsg("OSC play_note on instr %d", (context->num + 1));
204  context->instr->play();
205 }
206 
207 // Play a note with arguments (passed to the instrument as a void *)
208 
209 void playWithArgs(void * con, int arglen, const void * vargs, OSCTimeTag when, NetworkReturnAddressPtr ra) {
210  Inst_Context * context = (Inst_Context *) con;
211  char * error;
212  char * typeString = (char *) vargs;
213  char * endOfArgs = (char *) vargs + arglen;
214  void * otherArgs = OSCDataAfterAlignedString(typeString, typeString+arglen, &error);
215  logMsg("OSC play_with_args on instr %d %s", (context->num + 1), typeString);
216  context->instr->playOSC(typeString, otherArgs, endOfArgs);
217 }
218 
219 
220 // IOSC setup methods
221 
222 extern "C" void initOSCAddrSpace() {
223 }
224 
225 extern "C" void addOSCMethod(char * name, OSC_CALL_BACK function ) {
226 }
227 
228 extern "C" void addOSCMethod2(char * name, OSC_CALL_BACK function, void * user_data) {
229 }
230 
231 // Set up the OSC address space for an instrument library
232 
233 extern "C" void setupOSCInstrLibrary(std::vector<Instrument *> library) {
234  char * iname = NULL;
235  Inst_Context * the_context = NULL;
236  unsigned num_instruments = library.size();
237  logMsg("Setting up OSC address space for %d instruments\n", num_instruments);
238 
239  // Instrument reader loop
240  for (unsigned i = 0; i < num_instruments; i++) {
241  iname = (char *) malloc(8);
242  sprintf(iname, "i%d", i+1); // create container for instrument
243  temp_cont = OSCNewContainer(iname, OSCTopLevelContainer, &cqinfo);
244  Instrument * instr = library[i]; // get the instrument and its accessors
245  unsigned num_accessors = instr->numAccessors();
246  AccessorVector accs = instr->getAccessors();
247  logMsg("Adding instrument \"%s\" (%s); %d accessors", iname, instr->name().c_str(), num_accessors);
248 
249  // Accessor method creation loop
250  for (unsigned j = 0; j < num_accessors; j++) {
251  the_context = (Inst_Context *) malloc(sizeof(Inst_Context));
252  the_context->instr = instr;
253  the_context->num = i;
254  the_context->selector = accs[j]->mSelector;
255  // if (i == 0)
256  // printf("\tAdding OSC method for %s (%d)\n", accessors[j]->name, accessors[j]->selector);
257  switch(accs[j]->mType) {
258  case CSL_INT_TYPE:
259  OSCNewMethod(accs[j]->mName.c_str(), temp_cont, intParamSetter, the_context, &QueryResponseInfo);
260  break;
261  case CSL_FLOAT_TYPE:
262  OSCNewMethod(accs[j]->mName.c_str(), temp_cont, floatParamSetter, the_context, &QueryResponseInfo);
263  break;
264  case CSL_STRING_TYPE:
265  OSCNewMethod(accs[j]->mName.c_str(), temp_cont, stringParamSetter, the_context, &QueryResponseInfo);
266  }
267  }
268  OSCNewMethod("p", temp_cont, playNote, the_context, &QueryResponseInfo);
269  OSCNewMethod("pn", temp_cont, playWithArgs, the_context, &QueryResponseInfo);
270  }
271  fflush(stdout);
272 //Debugging
273 // printf("\nPrinting whole address space as published\n");
274 // OSCPrintWholeAddressSpace();
275 }