annotate Source/TouchKeys/Osc.cpp @ 56:b4a2d2ae43cf tip

merge
author Andrew McPherson <andrewm@eecs.qmul.ac.uk>
date Fri, 23 Nov 2018 15:48:14 +0000
parents 90ce403d0dc5
children
rev   line source
andrewm@0 1 /*
andrewm@0 2 TouchKeys: multi-touch musical keyboard control software
andrewm@0 3 Copyright (c) 2013 Andrew McPherson
andrewm@0 4
andrewm@0 5 This program is free software: you can redistribute it and/or modify
andrewm@0 6 it under the terms of the GNU General Public License as published by
andrewm@0 7 the Free Software Foundation, either version 3 of the License, or
andrewm@0 8 (at your option) any later version.
andrewm@0 9
andrewm@0 10 This program is distributed in the hope that it will be useful,
andrewm@0 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
andrewm@0 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
andrewm@0 13 GNU General Public License for more details.
andrewm@0 14
andrewm@0 15 You should have received a copy of the GNU General Public License
andrewm@0 16 along with this program. If not, see <http://www.gnu.org/licenses/>.
andrewm@0 17
andrewm@0 18 =====================================================================
andrewm@0 19
andrewm@0 20 Osc.cpp: classes for handling reception and transmission of OSC messages,
andrewm@0 21 using the liblo library.
andrewm@0 22 */
andrewm@0 23
andrewm@0 24 #include "Osc.h"
andrewm@0 25
andrewm@0 26 #undef DEBUG_OSC
andrewm@0 27
andrewm@0 28 #pragma mark OscHandler
andrewm@0 29
andrewm@0 30 OscHandler::~OscHandler()
andrewm@0 31 {
andrewm@0 32 if(oscController_ != NULL) // Remove (individually) each listener
andrewm@0 33 {
andrewm@0 34 set<string>::iterator it;
andrewm@0 35
andrewm@0 36 for(it = oscListenerPaths_.begin(); it != oscListenerPaths_.end(); ++it)
andrewm@0 37 {
andrewm@0 38 #ifdef DEBUG_OSC
andrewm@0 39 cout << "Deleting path " << *it << endl;
andrewm@0 40 #endif
andrewm@0 41
andrewm@0 42 string pathToRemove = *it;
andrewm@0 43 oscController_->removeListener(pathToRemove, this);
andrewm@0 44 }
andrewm@0 45 }
andrewm@0 46 }
andrewm@0 47
andrewm@0 48 #pragma mark -- Private Methods
andrewm@0 49
andrewm@0 50 // Call this internal method to add a listener to the OSC controller. Returns true on success.
andrewm@0 51
andrewm@0 52 bool OscHandler::addOscListener(const string& path)
andrewm@0 53 {
andrewm@0 54 if(oscController_ == NULL)
andrewm@0 55 return false;
andrewm@0 56 if(oscListenerPaths_.count(path) > 0)
andrewm@0 57 return false;
andrewm@0 58 oscListenerPaths_.insert(path);
andrewm@0 59 oscController_->addListener(path, this);
andrewm@0 60 return true;
andrewm@0 61 }
andrewm@0 62
andrewm@0 63 bool OscHandler::removeOscListener(const string& path)
andrewm@0 64 {
andrewm@0 65 if(oscController_ == NULL)
andrewm@0 66 return false;
andrewm@0 67 if(oscListenerPaths_.count(path) == 0)
andrewm@0 68 return false;
andrewm@0 69 oscController_->removeListener(path, this);
andrewm@0 70 oscListenerPaths_.erase(path);
andrewm@0 71 return true;
andrewm@0 72 }
andrewm@0 73
andrewm@0 74 bool OscHandler::removeAllOscListeners()
andrewm@0 75 {
andrewm@0 76 if(oscController_ == NULL)
andrewm@0 77 return false;
andrewm@0 78 set<string>::iterator it = oscListenerPaths_.begin();
andrewm@0 79
andrewm@0 80 while(it != oscListenerPaths_.end()) {
andrewm@0 81 removeOscListener(*it++);
andrewm@0 82 }
andrewm@0 83
andrewm@0 84 return true;
andrewm@0 85 }
andrewm@0 86
andrewm@0 87 #pragma mark OscMessageSource
andrewm@0 88
andrewm@0 89 // Adds a specific object listening for a specific OSC message. The object will be
andrewm@0 90 // added to the internal map from strings to objects. All messages are preceded by
andrewm@0 91 // a global prefix (typically "/mrp"). Returns true on success.
andrewm@0 92
andrewm@9 93 bool OscMessageSource::addListener(const string& path, OscHandler *object, bool matchSubpath)
andrewm@0 94 {
andrewm@0 95 if(object == NULL)
andrewm@0 96 return false;
andrewm@0 97
andrewm@0 98 #ifdef OLD_OSC_MESSAGE_SOURCE
andrewm@0 99 double before = Time::getMillisecondCounterHiRes();
andrewm@0 100 oscListenerMutex_.enterWrite();
andrewm@0 101 cout << "addListener(): took " << Time::getMillisecondCounterHiRes() - before << "ms to acquire mutex\n";
andrewm@0 102 noteListeners_.insert(pair<string, OscHandler*>(path, object));
andrewm@0 103 oscListenerMutex_.exitWrite();
andrewm@0 104 #else
andrewm@0 105 ScopedLock sl(oscUpdaterMutex_);
andrewm@0 106
andrewm@0 107 // Add this object to the insertion list
andrewm@0 108 noteListenersToAdd_.insert(std::pair<string, OscHandler*>(path, object));
andrewm@0 109 #endif
andrewm@0 110
andrewm@0 111 #ifdef DEBUG_OSC
andrewm@0 112 cout << "Added OSC listener to path '" << path << "'\n";
andrewm@0 113 #endif
andrewm@0 114
andrewm@0 115 return true;
andrewm@0 116 }
andrewm@0 117
andrewm@0 118 // Removes a specific object from listening to a specific OSC message.
andrewm@0 119 // Returns true if at least one path was removed.
andrewm@0 120
andrewm@0 121 bool OscMessageSource::removeListener(const string& path, OscHandler *object)
andrewm@0 122 {
andrewm@0 123 if(object == NULL)
andrewm@0 124 return false;
andrewm@0 125
andrewm@0 126 bool removedAny = false;
andrewm@0 127
andrewm@0 128 #ifdef OLD_OSC_MESSAGE_SOURCE
andrewm@0 129 oscListenerMutex_.enterWrite(); // Lock the mutex so no incoming messages happen in the middle
andrewm@0 130
andrewm@0 131 multimap<string, OscHandler*>::iterator it;
andrewm@0 132 pair<multimap<string, OscHandler*>::iterator,multimap<string, OscHandler*>::iterator> ret;
andrewm@0 133
andrewm@0 134 // Every time we remove an element from the multimap, the iterator is potentially corrupted. Realistically
andrewm@0 135 // there should never be more than one entry with the same object and same path (we check this on insertion).
andrewm@0 136
andrewm@0 137 ret = noteListeners_.equal_range(path);
andrewm@0 138
andrewm@0 139 it = ret.first;
andrewm@0 140 while(it != ret.second)
andrewm@0 141 {
andrewm@0 142 if(it->second == object)
andrewm@0 143 {
andrewm@0 144 noteListeners_.erase(it++);
andrewm@0 145 removedAny = true;
andrewm@0 146 break;
andrewm@0 147 }
andrewm@0 148 else
andrewm@0 149 ++it;
andrewm@0 150 }
andrewm@0 151
andrewm@0 152 oscListenerMutex_.exitWrite();
andrewm@0 153 #else
andrewm@0 154 ScopedLock sl(oscUpdaterMutex_);
andrewm@0 155
andrewm@0 156 // Add this object to the removal list
andrewm@0 157 noteListenersToRemove_.insert(std::pair<string, OscHandler*>(path, object));
andrewm@0 158
andrewm@0 159 // Also remove this object from anything on the add list, so it doesn't
andrewm@0 160 // get put back in by a previous add call.
andrewm@0 161 pair<multimap<string, OscHandler*>::iterator,multimap<string, OscHandler*>::iterator> ret;
andrewm@0 162 multimap<string, OscHandler*>::iterator it;
andrewm@0 163
andrewm@0 164 ret = noteListenersToAdd_.equal_range(path);
andrewm@0 165 it = ret.first;
andrewm@0 166 while(it != ret.second) {
andrewm@0 167 if(it->second == object) {
andrewm@0 168 noteListenersToAdd_.erase(it++);
andrewm@0 169 //break;
andrewm@0 170 }
andrewm@0 171 else
andrewm@0 172 ++it;
andrewm@0 173 }
andrewm@0 174
andrewm@0 175 removedAny = true; // FIXME: do we still need this?
andrewm@0 176 #endif
andrewm@0 177
andrewm@0 178 #ifdef DEBUG_OSC
andrewm@0 179 if(removedAny)
andrewm@0 180 cout << "Removed OSC listener from path '" << path << "'\n";
andrewm@0 181 else
andrewm@0 182 cout << "Removal failed to find OSC listener on path '" << path << "'\n";
andrewm@0 183 #endif
andrewm@0 184
andrewm@0 185 return removedAny;
andrewm@0 186 }
andrewm@0 187
andrewm@0 188 // Removes an object from all OSC messages it was listening to. Returns true if object
andrewm@0 189 // was found and removed.
andrewm@0 190
andrewm@0 191 bool OscMessageSource::removeListener(OscHandler *object)
andrewm@0 192 {
andrewm@0 193 if(object == NULL)
andrewm@0 194 return false;
andrewm@0 195
andrewm@0 196 bool removedAny = false;
andrewm@0 197
andrewm@0 198 #ifdef OLD_OSC_MESSAGE_SOURCE
andrewm@0 199 oscListenerMutex_.enterWrite(); // Lock the mutex so no incoming messages happen in the middle
andrewm@0 200
andrewm@0 201 multimap<string, OscHandler*>::iterator it;
andrewm@0 202
andrewm@0 203 // Every time we remove an element from the multimap, the iterator is potentially corrupted. Realistically
andrewm@0 204 // there should never be more than one entry with the same object and same path (we check this on insertion).
andrewm@0 205
andrewm@0 206 it = noteListeners_.begin();
andrewm@0 207 while(it != noteListeners_.end())
andrewm@0 208 {
andrewm@0 209 if(it->second == object)
andrewm@0 210 {
andrewm@0 211 noteListeners_.erase(it++);
andrewm@0 212 removedAny = true;
andrewm@0 213 //break;
andrewm@0 214 }
andrewm@0 215 else
andrewm@0 216 ++it;
andrewm@0 217 }
andrewm@0 218
andrewm@0 219 oscListenerMutex_.exitWrite();
andrewm@0 220 #else
andrewm@0 221 ScopedLock sl(oscUpdaterMutex_);
andrewm@0 222
andrewm@0 223 // Add this object to the removal list
andrewm@0 224 noteListenersForBlanketRemoval_.insert(object);
andrewm@0 225
andrewm@0 226 // Also remove this object from anything on the add list, so it doesn't
andrewm@0 227 // get put back in by a previous add call.
andrewm@0 228 multimap<string, OscHandler*>::iterator it;
andrewm@0 229 it = noteListenersToAdd_.begin();
andrewm@0 230 while(it != noteListenersToAdd_.end()) {
andrewm@0 231 if(it->second == object) {
andrewm@0 232 noteListenersToAdd_.erase(it++);
andrewm@0 233 }
andrewm@0 234 else
andrewm@0 235 ++it;
andrewm@0 236 }
andrewm@0 237
andrewm@0 238 removedAny = true; // FIXME: do we still need this?
andrewm@0 239 #endif
andrewm@0 240
andrewm@0 241 #ifdef DEBUG_OSC
andrewm@0 242 if(removedAny)
andrewm@0 243 cout << "Removed OSC listener from all paths\n";
andrewm@0 244 else
andrewm@0 245 cout << "Removal failed to find OSC listener on any path\n";
andrewm@0 246 #endif
andrewm@0 247
andrewm@0 248 return removedAny;
andrewm@0 249 }
andrewm@0 250
andrewm@0 251 // Propagate changes to the listeners to the main noteListeners_ object
andrewm@0 252
andrewm@0 253 void OscMessageSource::updateListeners()
andrewm@0 254 {
andrewm@0 255 ScopedLock sl2(oscListenerMutex_);
andrewm@0 256 ScopedLock sl(oscUpdaterMutex_);
andrewm@0 257 multimap<string, OscHandler*>::iterator it;
andrewm@0 258
andrewm@0 259 // Step 1: remove any objects that need complete removal from all paths
andrewm@0 260 set<OscHandler*>::iterator blanketRemovalIterator;
andrewm@0 261 for(blanketRemovalIterator = noteListenersForBlanketRemoval_.begin();
andrewm@0 262 blanketRemovalIterator != noteListenersForBlanketRemoval_.end();
andrewm@0 263 ++blanketRemovalIterator) {
andrewm@0 264 it = noteListeners_.begin();
andrewm@0 265 while(it != noteListeners_.end()) {
andrewm@0 266 if(it->second == *blanketRemovalIterator) {
andrewm@0 267 noteListeners_.erase(it++);
andrewm@0 268 }
andrewm@0 269 else
andrewm@0 270 ++it;
andrewm@0 271 }
andrewm@0 272 }
andrewm@0 273
andrewm@0 274 // Step 2: remove any specific path listeners
andrewm@0 275 for(it = noteListenersToRemove_.begin(); it != noteListenersToRemove_.end(); ++it) {
andrewm@0 276 pair<multimap<string, OscHandler*>::iterator,multimap<string, OscHandler*>::iterator> ret;
andrewm@0 277 multimap<string, OscHandler*>::iterator it2;
andrewm@0 278 string const& path = it->first;
andrewm@0 279 OscHandler *object = it->second;
andrewm@0 280
andrewm@0 281 // Find all the objects that match this string and remove ones that correspond to this particular OscHandler
andrewm@0 282 ret = noteListeners_.equal_range(path);
andrewm@0 283
andrewm@0 284 it2 = ret.first;
andrewm@0 285 while(it2 != ret.second)
andrewm@0 286 {
andrewm@0 287 if(it2->second == object) {
andrewm@0 288 noteListeners_.erase(it2++);
andrewm@0 289 //break;
andrewm@0 290 }
andrewm@0 291 else
andrewm@0 292 ++it2;
andrewm@0 293 }
andrewm@0 294 }
andrewm@0 295
andrewm@0 296 // Step 3: add any listeners
andrewm@0 297 for(it = noteListenersToAdd_.begin(); it != noteListenersToAdd_.end(); ++it) {
andrewm@0 298 noteListeners_.insert(pair<string, OscHandler*>(it->first, it->second));
andrewm@0 299 }
andrewm@0 300
andrewm@0 301 // Step 4: clear the buffers of pending listeners
andrewm@0 302 noteListenersForBlanketRemoval_.clear();
andrewm@0 303 noteListenersToRemove_.clear();
andrewm@0 304 noteListenersToAdd_.clear();
andrewm@0 305 }
andrewm@0 306
andrewm@0 307 #pragma mark OscReceiver
andrewm@0 308
andrewm@0 309 // OscReceiver::handler()
andrewm@0 310 // The main handler method for incoming OSC messages. From here, we farm out the processing depending
andrewm@9 311 // on the path. Return 0 if the message has been adequately handled, 1 otherwise (so the server can look
andrewm@9 312 // for other functions to pass it to).
andrewm@0 313
andrewm@0 314 int OscReceiver::handler(const char *path, const char *types, lo_arg **argv, int argc, lo_message msg, void *data)
andrewm@0 315 {
andrewm@0 316 bool matched = false;
andrewm@0 317
andrewm@0 318 string pathString(path);
andrewm@0 319
andrewm@0 320 if(useThru_)
andrewm@0 321 {
andrewm@0 322 // Rebroadcast any matching messages
andrewm@0 323
andrewm@0 324 if(!pathString.compare(0, thruPrefix_.length(), thruPrefix_))
andrewm@0 325 lo_send_message(thruAddress_, path, msg);
andrewm@0 326 }
andrewm@0 327
andrewm@0 328 // Check if the incoming message matches the global prefix for this program. If not, discard it.
andrewm@0 329 if(pathString.compare(0, globalPrefix_.length(), globalPrefix_))
andrewm@0 330 {
andrewm@0 331 #ifdef DEBUG_OSC
andrewm@0 332 cout << "OSC message '" << path << "' received\n";
andrewm@0 333 #endif
andrewm@0 334 return 1;
andrewm@0 335 }
andrewm@0 336
andrewm@0 337 // Update the list of OSC listeners to propagate any changes
andrewm@0 338 updateListeners();
andrewm@0 339
andrewm@0 340 // Lock the mutex so the list of listeners doesn't change midway through
andrewm@0 341 oscListenerMutex_.enter();
andrewm@0 342
andrewm@0 343 // Now remove the global prefix and compare the rest of the message to the registered handlers.
andrewm@0 344 multimap<string, OscHandler*>::iterator it;
andrewm@0 345 pair<multimap<string, OscHandler*>::iterator,multimap<string, OscHandler*>::iterator> ret;
andrewm@0 346 string truncatedPath = pathString.substr(globalPrefix_.length(),
andrewm@0 347 pathString.length() - globalPrefix_.length());
andrewm@9 348 string subpath = truncatedPath;
andrewm@0 349 ret = noteListeners_.equal_range(truncatedPath);
andrewm@9 350
andrewm@9 351 while(ret.first == ret.second) {
andrewm@9 352 // No handlers match this range. But maybe there are higher-level handlers
andrewm@9 353 // that match all subpaths.
andrewm@9 354
andrewm@9 355 // Strip off the last component of the path
andrewm@9 356 int pathSeparator = subpath.find_last_of('/');
andrewm@9 357
andrewm@9 358 if(pathSeparator == string::npos) // Not found --> no match
andrewm@9 359 break;
andrewm@9 360 else {
andrewm@9 361 // Reduce string by one path level and add *; compare again
andrewm@9 362 subpath = subpath.substr(0, pathSeparator);
andrewm@9 363 subpath.push_back('*');
andrewm@9 364 ret = noteListeners_.equal_range(subpath);
andrewm@9 365 }
andrewm@9 366 }
andrewm@9 367
andrewm@9 368 it = ret.first;
andrewm@9 369 while(it != ret.second) {
andrewm@9 370 OscHandler *object = (*it++).second;
andrewm@9 371
andrewm@9 372 #ifdef DEBUG_OSC
andrewm@9 373 cout << "Matched OSC path '" << path << "' to handler " << object << endl;
andrewm@9 374 #endif
andrewm@9 375 object->oscHandlerMethod(truncatedPath.c_str(), types, argc, argv, data);
andrewm@9 376 matched = true;
andrewm@9 377 }
andrewm@0 378
andrewm@0 379 oscListenerMutex_.exit();
andrewm@0 380
andrewm@0 381 if(matched) // This message has been handled
andrewm@0 382 return 0;
andrewm@0 383
andrewm@9 384 #ifdef DEBUG_OSC
andrewm@0 385 printf("Unhandled OSC path: <%s>\n", path);
andrewm@0 386
andrewm@0 387 for (int i=0; i<argc; i++) {
andrewm@0 388 printf("arg %d '%c' ", i, types[i]);
andrewm@0 389 lo_arg_pp((lo_type)types[i], argv[i]);
andrewm@0 390 printf("\n");
andrewm@0 391 }
andrewm@0 392 #endif
andrewm@0 393
andrewm@0 394 return 1;
andrewm@0 395 }
andrewm@0 396
andrewm@6 397 // Set the current port for the OSC receiver object. This implies stopping and
andrewm@6 398 // restarting the server. Returns true on success.
andrewm@6 399 bool OscReceiver::setPort(const int port)
andrewm@6 400 {
andrewm@6 401 // Stop existing server if running
andrewm@6 402 if(oscServerThread_ != 0) {
andrewm@6 403 lo_server_thread_del_method(oscServerThread_, NULL, NULL);
andrewm@6 404 lo_server_thread_stop(oscServerThread_);
andrewm@6 405 lo_server_thread_free(oscServerThread_);
andrewm@6 406 oscServerThread_ = 0;
andrewm@6 407 }
andrewm@6 408
andrewm@6 409 // Port value 0 indicates to turn off; this always succeeds.
andrewm@6 410 if(port == 0) {
andrewm@6 411 return true;
andrewm@6 412 }
andrewm@6 413
andrewm@6 414 // Now create a new one on the new port
andrewm@6 415 char portStr[16];
andrewm@20 416 #ifdef _MSC_VER
andrewm@20 417 _snprintf_s(portStr, 16, _TRUNCATE, "%d", port);
andrewm@20 418 #else
andrewm@6 419 snprintf(portStr, 16, "%d", port);
andrewm@20 420 #endif
andrewm@20 421
andrewm@6 422 oscServerThread_ = lo_server_thread_new(portStr, staticErrorHandler);
andrewm@6 423 if(oscServerThread_ != 0) {
andrewm@6 424 lo_server_thread_add_method(oscServerThread_, NULL, NULL, OscReceiver::staticHandler, (void *)this);
andrewm@6 425 lo_server_thread_start(oscServerThread_);
andrewm@6 426 return true;
andrewm@6 427 }
andrewm@6 428
andrewm@6 429 return false;
andrewm@6 430 }
andrewm@6 431
andrewm@0 432 #pragma mark OscTransmitter
andrewm@0 433
andrewm@0 434 // Add a new transmit address. Returns the index of the new address.
andrewm@0 435
andrewm@0 436 int OscTransmitter::addAddress(const char * host, const char * port, int proto)
andrewm@0 437 {
andrewm@0 438 lo_address addr = lo_address_new_with_proto(proto, host, port);
andrewm@0 439
andrewm@0 440 if(addr == 0)
andrewm@0 441 return -1;
andrewm@0 442 addresses_.push_back(addr);
andrewm@0 443
andrewm@0 444 return (int)addresses_.size() - 1;
andrewm@0 445 }
andrewm@0 446
andrewm@0 447 // Delete a current transmit address
andrewm@0 448
andrewm@0 449 void OscTransmitter::removeAddress(int index)
andrewm@0 450 {
andrewm@0 451 if(index >= addresses_.size() || index < 0)
andrewm@0 452 return;
andrewm@0 453 addresses_.erase(addresses_.begin() + index);
andrewm@0 454 }
andrewm@0 455
andrewm@0 456 // Delete all destination addresses
andrewm@0 457
andrewm@0 458 void OscTransmitter::clearAddresses()
andrewm@0 459 {
andrewm@0 460 vector<lo_address>::iterator it = addresses_.begin();
andrewm@0 461
andrewm@0 462 while(it != addresses_.end()) {
andrewm@0 463 lo_address_free(*it++);
andrewm@0 464 }
andrewm@0 465
andrewm@0 466 addresses_.clear();
andrewm@0 467 }
andrewm@0 468
andrewm@0 469 void OscTransmitter::sendMessage(const char * path, const char * type, ...)
andrewm@0 470 {
andrewm@0 471 if(!enabled_)
andrewm@0 472 return;
andrewm@0 473
andrewm@0 474 va_list v;
andrewm@0 475
andrewm@0 476 va_start(v, type);
andrewm@0 477 lo_message msg = lo_message_new();
andrewm@0 478 lo_message_add_varargs(msg, type, v);
andrewm@0 479
andrewm@0 480 /*if(debugMessages_) {
andrewm@0 481 cout << path << " " << type << ": ";
andrewm@0 482
andrewm@0 483 lo_arg **args = lo_message_get_argv(msg);
andrewm@0 484
andrewm@0 485 for(int i = 0; i < lo_message_get_argc(msg); i++) {
andrewm@0 486 switch(type[i]) {
andrewm@0 487 case 'i':
andrewm@0 488 cout << args[i]->i << " ";
andrewm@0 489 break;
andrewm@0 490 case 'f':
andrewm@0 491 cout << args[i]->f << " ";
andrewm@0 492 break;
andrewm@0 493 default:
andrewm@0 494 cout << "? ";
andrewm@0 495 }
andrewm@0 496 }
andrewm@0 497
andrewm@0 498 cout << endl;
andrewm@0 499 //lo_message_pp(msg);
andrewm@0 500 }*/
andrewm@0 501
andrewm@0 502 sendMessage(path, type, msg);
andrewm@0 503
andrewm@0 504 lo_message_free(msg);
andrewm@0 505 va_end(v);
andrewm@0 506 }
andrewm@0 507
andrewm@0 508 void OscTransmitter::sendMessage(const char * path, const char * type, const lo_message& message)
andrewm@0 509 {
andrewm@0 510 if(!enabled_)
andrewm@0 511 return;
andrewm@0 512
andrewm@0 513 if(debugMessages_) {
andrewm@0 514 cout << path << " " << type << " ";
andrewm@0 515
andrewm@0 516 int argc = lo_message_get_argc(message);
andrewm@0 517 lo_arg **argv = lo_message_get_argv(message);
andrewm@0 518 for (int i=0; i<argc; i++) {
andrewm@0 519 lo_arg_pp((lo_type)type[i], argv[i]);
andrewm@0 520 cout << " ";
andrewm@0 521 }
andrewm@0 522 cout << endl;
andrewm@0 523 }
andrewm@0 524
andrewm@0 525 // Send message to everyone who's currently listening
andrewm@0 526 for(vector<lo_address>::iterator it = addresses_.begin(); it != addresses_.end(); it++) {
andrewm@0 527 lo_send_message(*it, path, message);
andrewm@0 528 }
andrewm@0 529 }
andrewm@0 530
andrewm@0 531 // Send an array of bytes as an OSC message. Bytes will be sent as a blob.
andrewm@0 532
andrewm@0 533 void OscTransmitter::sendByteArray(const char * path, const unsigned char * data, int length)
andrewm@0 534 {
andrewm@0 535 if(!enabled_)
andrewm@0 536 return;
andrewm@0 537 if(length == 0)
andrewm@0 538 return;
andrewm@0 539
andrewm@0 540 lo_blob b = lo_blob_new(length, data);
andrewm@0 541
andrewm@0 542 lo_message msg = lo_message_new();
andrewm@0 543 lo_message_add_blob(msg, b);
andrewm@0 544
andrewm@0 545 if(debugMessages_) {
andrewm@0 546 cout << path << " ";
andrewm@0 547 lo_message_pp(msg);
andrewm@0 548 }
andrewm@0 549
andrewm@0 550 // Send message to everyone who's currently listening
andrewm@0 551 for(vector<lo_address>::iterator it = addresses_.begin(); it != addresses_.end(); it++) {
andrewm@0 552 lo_send_message(*it, path, msg);
andrewm@0 553 }
andrewm@0 554
andrewm@0 555 lo_blob_free(b);
andrewm@0 556 }
andrewm@0 557
andrewm@0 558 OscTransmitter::~OscTransmitter()
andrewm@0 559 {
andrewm@0 560 clearAddresses();
andrewm@49 561 }
andrewm@49 562
andrewm@49 563 OscMessage* OscTransmitter::createMessage(const char * path, const char * type, ...)
andrewm@49 564 {
andrewm@49 565 va_list v;
andrewm@49 566
andrewm@49 567 va_start(v, type);
andrewm@49 568 lo_message msg = lo_message_new();
andrewm@49 569 lo_message_add_varargs(msg, type, v);
andrewm@49 570 va_end(v);
andrewm@49 571
andrewm@49 572 return new OscMessage(path, type, msg);
andrewm@49 573 }