comparison data/osc/OSCQueue.cpp @ 320:32e50b620a6c

* Move some things around to facilitate plundering libraries for other applications without needing to duplicate so much code. sv/osc -> data/osc sv/audioio -> audioio sv/transform -> plugin/transform sv/document -> document (will rename to framework in next commit)
author Chris Cannam
date Wed, 24 Oct 2007 16:34:31 +0000
parents
children 115f60df1e4d
comparison
equal deleted inserted replaced
319:3ff8f571da09 320:32e50b620a6c
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 and QMUL.
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 // This conversion fails to compile in 64-bit environments
65 // at present, and we don't use the h type anyway so we
66 // can safely omit it
67 // case 'h': message.addArg(arg->h); break;
68 case 'f': message.addArg(arg->f); break;
69 case 'd': message.addArg(arg->d); break;
70 case 'c': message.addArg(arg->c); break;
71 case 't': message.addArg(arg->i); break;
72 case 's': message.addArg(&arg->s); break;
73 default: std::cerr << "WARNING: OSCQueue::oscMessageHandler: "
74 << "Unsupported OSC type '" << type << "'"
75 << std::endl;
76 break;
77 }
78
79 ++i;
80 }
81
82 queue->postMessage(message);
83 return 0;
84 }
85
86 #endif
87
88 OSCQueue::OSCQueue() :
89 #ifdef HAVE_LIBLO
90 m_thread(0),
91 #endif
92 m_buffer(OSC_MESSAGE_QUEUE_SIZE)
93 {
94 #ifdef HAVE_LIBLO
95 m_thread = lo_server_thread_new(NULL, oscError);
96
97 lo_server_thread_add_method(m_thread, NULL, NULL,
98 oscMessageHandler, this);
99
100 lo_server_thread_start(m_thread);
101
102 std::cout << "OSCQueue::OSCQueue: Base OSC URL is "
103 << lo_server_thread_get_url(m_thread) << std::endl;
104 #endif
105 }
106
107 OSCQueue::~OSCQueue()
108 {
109 #ifdef HAVE_LIBLO
110 if (m_thread) {
111 lo_server_thread_stop(m_thread);
112 }
113 #endif
114
115 while (m_buffer.getReadSpace() > 0) {
116 delete m_buffer.readOne();
117 }
118 }
119
120 bool
121 OSCQueue::isOK() const
122 {
123 #ifdef HAVE_LIBLO
124 return (m_thread != 0);
125 #else
126 return false;
127 #endif
128 }
129
130 QString
131 OSCQueue::getOSCURL() const
132 {
133 QString url = "";
134 #ifdef HAVE_LIBLO
135 url = lo_server_thread_get_url(m_thread);
136 #endif
137 return url;
138 }
139
140 size_t
141 OSCQueue::getMessagesAvailable() const
142 {
143 return m_buffer.getReadSpace();
144 }
145
146 OSCMessage
147 OSCQueue::readMessage()
148 {
149 OSCMessage *message = m_buffer.readOne();
150 OSCMessage rmessage = *message;
151 delete message;
152 return rmessage;
153 }
154
155 void
156 OSCQueue::postMessage(OSCMessage message)
157 {
158 int count = 0, max = 5;
159 while (m_buffer.getWriteSpace() == 0) {
160 if (count == max) {
161 std::cerr << "ERROR: OSCQueue::postMessage: OSC message queue is full and not clearing -- abandoning incoming message" << std::endl;
162 return;
163 }
164 std::cerr << "WARNING: OSCQueue::postMessage: OSC message queue (capacity " << m_buffer.getSize() << " is full!" << std::endl;
165 std::cerr << "Waiting for something to be processed" << std::endl;
166 #ifdef _WIN32
167 Sleep(1);
168 #else
169 sleep(1);
170 #endif
171 count++;
172 }
173
174 OSCMessage *mp = new OSCMessage(message);
175 m_buffer.write(&mp, 1);
176 std::cerr << "OSCQueue::postMessage: Posted OSC message: target "
177 << message.getTarget() << ", target data " << message.getTargetData()
178 << ", method " << message.getMethod().toStdString() << std::endl;
179 emit messagesAvailable();
180 }
181
182 bool
183 OSCQueue::parseOSCPath(QString path, int &target, int &targetData,
184 QString &method)
185 {
186 while (path.startsWith("/")) {
187 path = path.right(path.length()-1);
188 }
189
190 int i = 0;
191
192 bool ok = false;
193 target = path.section('/', i, i).toInt(&ok);
194
195 if (!ok) {
196 target = 0;
197 } else {
198 ++i;
199 targetData = path.section('/', i, i).toInt(&ok);
200 if (!ok) {
201 targetData = 0;
202 } else {
203 ++i;
204 }
205 }
206
207 method = path.section('/', i, -1);
208
209 if (method.contains('/')) {
210 std::cerr << "ERROR: OSCQueue::parseOSCPath: malformed path \""
211 << path.toStdString() << "\" (should be target/data/method or "
212 << "target/method or method, where target and data "
213 << "are numeric)" << std::endl;
214 return false;
215 }
216
217 std::cerr << "OSCQueue::parseOSCPath: good path \"" << path.toStdString()
218 << "\"" << std::endl;
219
220 return true;
221 }
222