comparison osc/OSCQueue.cpp @ 69:76cc2c424268

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