svcore
1.9
|
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ 00002 00003 /* 00004 Sonic Visualiser 00005 An audio file viewer and annotation editor. 00006 Centre for Digital Music, Queen Mary, University of London. 00007 00008 This program is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU General Public License as 00010 published by the Free Software Foundation; either version 2 of the 00011 License, or (at your option) any later version. See the file 00012 COPYING included with this distribution for more information. 00013 */ 00014 00015 /* 00016 This is a modified version of a source file from the 00017 Rosegarden MIDI and audio sequencer and notation editor. 00018 This file copyright 2000-2006 Chris Cannam and QMUL. 00019 */ 00020 00021 #include "OSCQueue.h" 00022 00023 #include "base/Profiler.h" 00024 00025 #include <iostream> 00026 #include <unistd.h> 00027 00028 #define OSC_MESSAGE_QUEUE_SIZE 1023 00029 00030 #ifdef HAVE_LIBLO 00031 00032 void 00033 OSCQueue::oscError(int num, const char *msg, const char *path) 00034 { 00035 cerr << "ERROR: OSCQueue::oscError: liblo server error " << num 00036 << " in path " << path << ": " << msg << endl; 00037 } 00038 00039 int 00040 OSCQueue::oscMessageHandler(const char *path, const char *types, lo_arg **argv, 00041 int argc, lo_message, void *user_data) 00042 { 00043 OSCQueue *queue = static_cast<OSCQueue *>(user_data); 00044 00045 int target; 00046 int targetData; 00047 QString method; 00048 00049 if (!queue->parseOSCPath(path, target, targetData, method)) { 00050 return 1; 00051 } 00052 00053 OSCMessage message; 00054 message.setTarget(target); 00055 message.setTargetData(targetData); 00056 message.setMethod(method); 00057 00058 int i = 0; 00059 00060 while (types && i < argc && types[i]) { 00061 00062 char type = types[i]; 00063 lo_arg *arg = argv[i]; 00064 00065 switch (type) { 00066 case 'i': message.addArg(arg->i); break; 00067 // This conversion fails to compile in 64-bit environments 00068 // at present, and we don't use the h type anyway so we 00069 // can safely omit it 00070 // case 'h': message.addArg(arg->h); break; 00071 case 'f': message.addArg(arg->f); break; 00072 case 'd': message.addArg(arg->d); break; 00073 case 'c': message.addArg(arg->c); break; 00074 case 't': message.addArg(arg->i); break; 00075 case 's': message.addArg(&arg->s); break; 00076 default: cerr << "WARNING: OSCQueue::oscMessageHandler: " 00077 << "Unsupported OSC type '" << type << "'" 00078 << endl; 00079 break; 00080 } 00081 00082 ++i; 00083 } 00084 00085 queue->postMessage(message); 00086 return 0; 00087 } 00088 00089 #endif 00090 00091 OSCQueue::OSCQueue() : 00092 #ifdef HAVE_LIBLO 00093 m_thread(0), 00094 #endif 00095 m_buffer(OSC_MESSAGE_QUEUE_SIZE) 00096 { 00097 Profiler profiler("OSCQueue::OSCQueue"); 00098 00099 #ifdef HAVE_LIBLO 00100 m_thread = lo_server_thread_new(NULL, oscError); 00101 00102 lo_server_thread_add_method(m_thread, NULL, NULL, 00103 oscMessageHandler, this); 00104 00105 lo_server_thread_start(m_thread); 00106 00107 cout << "OSCQueue::OSCQueue: Base OSC URL is " 00108 << lo_server_thread_get_url(m_thread) << endl; 00109 #endif 00110 } 00111 00112 OSCQueue::~OSCQueue() 00113 { 00114 #ifdef HAVE_LIBLO 00115 if (m_thread) { 00116 lo_server_thread_stop(m_thread); 00117 } 00118 #endif 00119 00120 while (m_buffer.getReadSpace() > 0) { 00121 delete m_buffer.readOne(); 00122 } 00123 } 00124 00125 bool 00126 OSCQueue::isOK() const 00127 { 00128 #ifdef HAVE_LIBLO 00129 return (m_thread != 0); 00130 #else 00131 return false; 00132 #endif 00133 } 00134 00135 QString 00136 OSCQueue::getOSCURL() const 00137 { 00138 QString url = ""; 00139 #ifdef HAVE_LIBLO 00140 url = lo_server_thread_get_url(m_thread); 00141 #endif 00142 return url; 00143 } 00144 00145 int 00146 OSCQueue::getMessagesAvailable() const 00147 { 00148 return m_buffer.getReadSpace(); 00149 } 00150 00151 OSCMessage 00152 OSCQueue::readMessage() 00153 { 00154 OSCMessage *message = m_buffer.readOne(); 00155 OSCMessage rmessage = *message; 00156 delete message; 00157 return rmessage; 00158 } 00159 00160 void 00161 OSCQueue::postMessage(OSCMessage message) 00162 { 00163 int count = 0, max = 5; 00164 while (m_buffer.getWriteSpace() == 0) { 00165 if (count == max) { 00166 cerr << "ERROR: OSCQueue::postMessage: OSC message queue is full and not clearing -- abandoning incoming message" << endl; 00167 return; 00168 } 00169 cerr << "WARNING: OSCQueue::postMessage: OSC message queue (capacity " << m_buffer.getSize() << " is full!" << endl; 00170 SVDEBUG << "Waiting for something to be processed" << endl; 00171 #ifdef _WIN32 00172 Sleep(1); 00173 #else 00174 sleep(1); 00175 #endif 00176 count++; 00177 } 00178 00179 OSCMessage *mp = new OSCMessage(message); 00180 m_buffer.write(&mp, 1); 00181 SVDEBUG << "OSCQueue::postMessage: Posted OSC message: target " 00182 << message.getTarget() << ", target data " << message.getTargetData() 00183 << ", method " << message.getMethod() << endl; 00184 emit messagesAvailable(); 00185 } 00186 00187 bool 00188 OSCQueue::parseOSCPath(QString path, int &target, int &targetData, 00189 QString &method) 00190 { 00191 while (path.startsWith("/")) { 00192 path = path.right(path.length()-1); 00193 } 00194 00195 int i = 0; 00196 00197 bool ok = false; 00198 target = path.section('/', i, i).toInt(&ok); 00199 00200 if (!ok) { 00201 target = 0; 00202 } else { 00203 ++i; 00204 targetData = path.section('/', i, i).toInt(&ok); 00205 if (!ok) { 00206 targetData = 0; 00207 } else { 00208 ++i; 00209 } 00210 } 00211 00212 method = path.section('/', i, -1); 00213 00214 if (method.contains('/')) { 00215 cerr << "ERROR: OSCQueue::parseOSCPath: malformed path \"" 00216 << path << "\" (should be target/data/method or " 00217 << "target/method or method, where target and data " 00218 << "are numeric)" << endl; 00219 return false; 00220 } 00221 00222 SVDEBUG << "OSCQueue::parseOSCPath: good path \"" << path << "\"" << endl; 00223 00224 return true; 00225 } 00226