Mercurial > hg > svcore
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 |