lbajardsilogic@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
lbajardsilogic@0
|
2
|
lbajardsilogic@0
|
3 /*
|
lbajardsilogic@0
|
4 Sonic Visualiser
|
lbajardsilogic@0
|
5 An audio file viewer and annotation editor.
|
lbajardsilogic@0
|
6 Centre for Digital Music, Queen Mary, University of London.
|
lbajardsilogic@0
|
7
|
lbajardsilogic@0
|
8 This program is free software; you can redistribute it and/or
|
lbajardsilogic@0
|
9 modify it under the terms of the GNU General Public License as
|
lbajardsilogic@0
|
10 published by the Free Software Foundation; either version 2 of the
|
lbajardsilogic@0
|
11 License, or (at your option) any later version. See the file
|
lbajardsilogic@0
|
12 COPYING included with this distribution for more information.
|
lbajardsilogic@0
|
13 */
|
lbajardsilogic@0
|
14
|
lbajardsilogic@0
|
15 /*
|
lbajardsilogic@0
|
16 This is a modified version of a source file from the
|
lbajardsilogic@0
|
17 Rosegarden MIDI and audio sequencer and notation editor.
|
lbajardsilogic@0
|
18 This file copyright 2000-2006 Chris Cannam and QMUL.
|
lbajardsilogic@0
|
19 */
|
lbajardsilogic@0
|
20
|
lbajardsilogic@0
|
21 #include "OSCQueue.h"
|
lbajardsilogic@0
|
22
|
lbajardsilogic@0
|
23 #include <iostream>
|
lbajardsilogic@0
|
24
|
lbajardsilogic@0
|
25 #define OSC_MESSAGE_QUEUE_SIZE 1023
|
lbajardsilogic@0
|
26
|
lbajardsilogic@0
|
27 #ifdef HAVE_LIBLO
|
lbajardsilogic@0
|
28
|
lbajardsilogic@0
|
29 void
|
lbajardsilogic@0
|
30 OSCQueue::oscError(int num, const char *msg, const char *path)
|
lbajardsilogic@0
|
31 {
|
lbajardsilogic@0
|
32 std::cerr << "ERROR: OSCQueue::oscError: liblo server error " << num
|
lbajardsilogic@0
|
33 << " in path " << path << ": " << msg << std::endl;
|
lbajardsilogic@0
|
34 }
|
lbajardsilogic@0
|
35
|
lbajardsilogic@0
|
36 int
|
lbajardsilogic@0
|
37 OSCQueue::oscMessageHandler(const char *path, const char *types, lo_arg **argv,
|
lbajardsilogic@0
|
38 int argc, lo_message, void *user_data)
|
lbajardsilogic@0
|
39 {
|
lbajardsilogic@0
|
40 OSCQueue *queue = static_cast<OSCQueue *>(user_data);
|
lbajardsilogic@0
|
41
|
lbajardsilogic@0
|
42 int target;
|
lbajardsilogic@0
|
43 int targetData;
|
lbajardsilogic@0
|
44 QString method;
|
lbajardsilogic@0
|
45
|
lbajardsilogic@0
|
46 if (!queue->parseOSCPath(path, target, targetData, method)) {
|
lbajardsilogic@0
|
47 return 1;
|
lbajardsilogic@0
|
48 }
|
lbajardsilogic@0
|
49
|
lbajardsilogic@0
|
50 OSCMessage message;
|
lbajardsilogic@0
|
51 message.setTarget(target);
|
lbajardsilogic@0
|
52 message.setTargetData(targetData);
|
lbajardsilogic@0
|
53 message.setMethod(method);
|
lbajardsilogic@0
|
54
|
lbajardsilogic@0
|
55 int i = 0;
|
lbajardsilogic@0
|
56
|
lbajardsilogic@0
|
57 while (types && i < argc && types[i]) {
|
lbajardsilogic@0
|
58
|
lbajardsilogic@0
|
59 char type = types[i];
|
lbajardsilogic@0
|
60 lo_arg *arg = argv[i];
|
lbajardsilogic@0
|
61
|
lbajardsilogic@0
|
62 switch (type) {
|
lbajardsilogic@0
|
63 case 'i': message.addArg(arg->i); break;
|
lbajardsilogic@0
|
64 case 'h': message.addArg(arg->h); break;
|
lbajardsilogic@0
|
65 case 'f': message.addArg(arg->f); break;
|
lbajardsilogic@0
|
66 case 'd': message.addArg(arg->d); break;
|
lbajardsilogic@0
|
67 case 'c': message.addArg(arg->c); break;
|
lbajardsilogic@0
|
68 case 't': message.addArg(arg->i); break;
|
lbajardsilogic@0
|
69 case 's': message.addArg(&arg->s); break;
|
lbajardsilogic@0
|
70 default: std::cerr << "WARNING: OSCQueue::oscMessageHandler: "
|
lbajardsilogic@0
|
71 << "Unsupported OSC type '" << type << "'"
|
lbajardsilogic@0
|
72 << std::endl;
|
lbajardsilogic@0
|
73 break;
|
lbajardsilogic@0
|
74 }
|
lbajardsilogic@0
|
75
|
lbajardsilogic@0
|
76 ++i;
|
lbajardsilogic@0
|
77 }
|
lbajardsilogic@0
|
78
|
lbajardsilogic@0
|
79 queue->postMessage(message);
|
lbajardsilogic@0
|
80 return 0;
|
lbajardsilogic@0
|
81 }
|
lbajardsilogic@0
|
82
|
lbajardsilogic@0
|
83 #endif
|
lbajardsilogic@0
|
84
|
lbajardsilogic@0
|
85 OSCQueue::OSCQueue() :
|
lbajardsilogic@0
|
86 #ifdef HAVE_LIBLO
|
lbajardsilogic@0
|
87 m_thread(0),
|
lbajardsilogic@0
|
88 #endif
|
lbajardsilogic@0
|
89 m_buffer(OSC_MESSAGE_QUEUE_SIZE)
|
lbajardsilogic@0
|
90 {
|
lbajardsilogic@0
|
91 #ifdef HAVE_LIBLO
|
lbajardsilogic@0
|
92 m_thread = lo_server_thread_new(NULL, oscError);
|
lbajardsilogic@0
|
93
|
lbajardsilogic@0
|
94 lo_server_thread_add_method(m_thread, NULL, NULL,
|
lbajardsilogic@0
|
95 oscMessageHandler, this);
|
lbajardsilogic@0
|
96
|
lbajardsilogic@0
|
97 lo_server_thread_start(m_thread);
|
lbajardsilogic@0
|
98
|
lbajardsilogic@0
|
99 std::cout << "OSCQueue::OSCQueue: Base OSC URL is "
|
lbajardsilogic@0
|
100 << lo_server_thread_get_url(m_thread) << std::endl;
|
lbajardsilogic@0
|
101 #endif
|
lbajardsilogic@0
|
102 }
|
lbajardsilogic@0
|
103
|
lbajardsilogic@0
|
104 OSCQueue::~OSCQueue()
|
lbajardsilogic@0
|
105 {
|
lbajardsilogic@0
|
106 #ifdef HAVE_LIBLO
|
lbajardsilogic@0
|
107 if (m_thread) {
|
lbajardsilogic@0
|
108 lo_server_thread_stop(m_thread);
|
lbajardsilogic@0
|
109 }
|
lbajardsilogic@0
|
110 #endif
|
lbajardsilogic@0
|
111
|
lbajardsilogic@0
|
112 while (m_buffer.getReadSpace() > 0) {
|
lbajardsilogic@0
|
113 delete m_buffer.readOne();
|
lbajardsilogic@0
|
114 }
|
lbajardsilogic@0
|
115 }
|
lbajardsilogic@0
|
116
|
lbajardsilogic@0
|
117 bool
|
lbajardsilogic@0
|
118 OSCQueue::isOK() const
|
lbajardsilogic@0
|
119 {
|
lbajardsilogic@0
|
120 #ifdef HAVE_LIBLO
|
lbajardsilogic@0
|
121 return (m_thread != 0);
|
lbajardsilogic@0
|
122 #else
|
lbajardsilogic@0
|
123 return false;
|
lbajardsilogic@0
|
124 #endif
|
lbajardsilogic@0
|
125 }
|
lbajardsilogic@0
|
126
|
lbajardsilogic@0
|
127 QString
|
lbajardsilogic@0
|
128 OSCQueue::getOSCURL() const
|
lbajardsilogic@0
|
129 {
|
lbajardsilogic@0
|
130 QString url = "";
|
lbajardsilogic@0
|
131 #ifdef HAVE_LIBLO
|
lbajardsilogic@0
|
132 url = lo_server_thread_get_url(m_thread);
|
lbajardsilogic@0
|
133 #endif
|
lbajardsilogic@0
|
134 return url;
|
lbajardsilogic@0
|
135 }
|
lbajardsilogic@0
|
136
|
lbajardsilogic@0
|
137 size_t
|
lbajardsilogic@0
|
138 OSCQueue::getMessagesAvailable() const
|
lbajardsilogic@0
|
139 {
|
lbajardsilogic@0
|
140 return m_buffer.getReadSpace();
|
lbajardsilogic@0
|
141 }
|
lbajardsilogic@0
|
142
|
lbajardsilogic@0
|
143 OSCMessage
|
lbajardsilogic@0
|
144 OSCQueue::readMessage()
|
lbajardsilogic@0
|
145 {
|
lbajardsilogic@0
|
146 OSCMessage *message = m_buffer.readOne();
|
lbajardsilogic@0
|
147 OSCMessage rmessage = *message;
|
lbajardsilogic@0
|
148 delete message;
|
lbajardsilogic@0
|
149 return rmessage;
|
lbajardsilogic@0
|
150 }
|
lbajardsilogic@0
|
151
|
lbajardsilogic@0
|
152 void
|
lbajardsilogic@0
|
153 OSCQueue::postMessage(OSCMessage message)
|
lbajardsilogic@0
|
154 {
|
lbajardsilogic@0
|
155 int count = 0, max = 5;
|
lbajardsilogic@0
|
156 while (m_buffer.getWriteSpace() == 0) {
|
lbajardsilogic@0
|
157 if (count == max) {
|
lbajardsilogic@0
|
158 std::cerr << "ERROR: OSCQueue::postMessage: OSC message queue is full and not clearing -- abandoning incoming message" << std::endl;
|
lbajardsilogic@0
|
159 return;
|
lbajardsilogic@0
|
160 }
|
lbajardsilogic@0
|
161 std::cerr << "WARNING: OSCQueue::postMessage: OSC message queue (capacity " << m_buffer.getSize() << " is full!" << std::endl;
|
lbajardsilogic@0
|
162 std::cerr << "Waiting for something to be processed" << std::endl;
|
lbajardsilogic@0
|
163 #ifdef _WIN32
|
lbajardsilogic@0
|
164 Sleep(1);
|
lbajardsilogic@0
|
165 #else
|
lbajardsilogic@0
|
166 sleep(1);
|
lbajardsilogic@0
|
167 #endif
|
lbajardsilogic@0
|
168 count++;
|
lbajardsilogic@0
|
169 }
|
lbajardsilogic@0
|
170
|
lbajardsilogic@0
|
171 OSCMessage *mp = new OSCMessage(message);
|
lbajardsilogic@0
|
172 m_buffer.write(&mp, 1);
|
lbajardsilogic@0
|
173 std::cerr << "OSCQueue::postMessage: Posted OSC message: target "
|
lbajardsilogic@0
|
174 << message.getTarget() << ", target data " << message.getTargetData()
|
lbajardsilogic@0
|
175 << ", method " << message.getMethod().toStdString() << std::endl;
|
lbajardsilogic@0
|
176 emit messagesAvailable();
|
lbajardsilogic@0
|
177 }
|
lbajardsilogic@0
|
178
|
lbajardsilogic@0
|
179 bool
|
lbajardsilogic@0
|
180 OSCQueue::parseOSCPath(QString path, int &target, int &targetData,
|
lbajardsilogic@0
|
181 QString &method)
|
lbajardsilogic@0
|
182 {
|
lbajardsilogic@0
|
183 while (path.startsWith("/")) {
|
lbajardsilogic@0
|
184 path = path.right(path.length()-1);
|
lbajardsilogic@0
|
185 }
|
lbajardsilogic@0
|
186
|
lbajardsilogic@0
|
187 int i = 0;
|
lbajardsilogic@0
|
188
|
lbajardsilogic@0
|
189 bool ok = false;
|
lbajardsilogic@0
|
190 target = path.section('/', i, i).toInt(&ok);
|
lbajardsilogic@0
|
191
|
lbajardsilogic@0
|
192 if (!ok) {
|
lbajardsilogic@0
|
193 target = 0;
|
lbajardsilogic@0
|
194 } else {
|
lbajardsilogic@0
|
195 ++i;
|
lbajardsilogic@0
|
196 targetData = path.section('/', i, i).toInt(&ok);
|
lbajardsilogic@0
|
197 if (!ok) {
|
lbajardsilogic@0
|
198 targetData = 0;
|
lbajardsilogic@0
|
199 } else {
|
lbajardsilogic@0
|
200 ++i;
|
lbajardsilogic@0
|
201 }
|
lbajardsilogic@0
|
202 }
|
lbajardsilogic@0
|
203
|
lbajardsilogic@0
|
204 method = path.section('/', i, -1);
|
lbajardsilogic@0
|
205
|
lbajardsilogic@0
|
206 if (method.contains('/')) {
|
lbajardsilogic@0
|
207 std::cerr << "ERROR: OSCQueue::parseOSCPath: malformed path \""
|
lbajardsilogic@0
|
208 << path.toStdString() << "\" (should be target/data/method or "
|
lbajardsilogic@0
|
209 << "target/method or method, where target and data "
|
lbajardsilogic@0
|
210 << "are numeric)" << std::endl;
|
lbajardsilogic@0
|
211 return false;
|
lbajardsilogic@0
|
212 }
|
lbajardsilogic@0
|
213
|
lbajardsilogic@0
|
214 std::cerr << "OSCQueue::parseOSCPath: good path \"" << path.toStdString()
|
lbajardsilogic@0
|
215 << "\"" << std::endl;
|
lbajardsilogic@0
|
216
|
lbajardsilogic@0
|
217 return true;
|
lbajardsilogic@0
|
218 }
|
lbajardsilogic@0
|
219
|