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 }
|