OSCQueue.cpp

Go to the documentation of this file.
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 <iostream>
00024 
00025 #define OSC_MESSAGE_QUEUE_SIZE 1023
00026 
00027 #ifdef HAVE_LIBLO
00028 
00029 void
00030 OSCQueue::oscError(int num, const char *msg, const char *path)
00031 {
00032     std::cerr << "ERROR: OSCQueue::oscError: liblo server error " << num
00033               << " in path " << path << ": " << msg << std::endl;
00034 }
00035 
00036 int
00037 OSCQueue::oscMessageHandler(const char *path, const char *types, lo_arg **argv,
00038                             int argc, lo_message, void *user_data)
00039 {
00040     OSCQueue *queue = static_cast<OSCQueue *>(user_data);
00041 
00042     int target;
00043     int targetData;
00044     QString method;
00045 
00046     if (!queue->parseOSCPath(path, target, targetData, method)) {
00047         return 1;
00048     }
00049 
00050     OSCMessage message;
00051     message.setTarget(target);
00052     message.setTargetData(targetData);
00053     message.setMethod(method);
00054 
00055     int i = 0;
00056 
00057     while (types && i < argc && types[i]) {
00058 
00059         char type = types[i];
00060         lo_arg *arg = argv[i];
00061 
00062         switch (type) {
00063         case 'i': message.addArg(arg->i); break;
00064             // This conversion fails to compile in 64-bit environments
00065             // at present, and we don't use the h type anyway so we
00066             // can safely omit it
00067 //        case 'h': message.addArg(arg->h); break;
00068         case 'f': message.addArg(arg->f); break;
00069         case 'd': message.addArg(arg->d); break;
00070         case 'c': message.addArg(arg->c); break;
00071         case 't': message.addArg(arg->i); break;
00072         case 's': message.addArg(&arg->s); break;
00073         default:  std::cerr << "WARNING: OSCQueue::oscMessageHandler: "
00074                             << "Unsupported OSC type '" << type << "'" 
00075                             << std::endl;
00076             break;
00077         }
00078 
00079         ++i;
00080     }
00081 
00082     queue->postMessage(message);
00083     return 0;
00084 }
00085 
00086 #endif
00087    
00088 OSCQueue::OSCQueue() :
00089 #ifdef HAVE_LIBLO
00090     m_thread(0),
00091 #endif
00092     m_buffer(OSC_MESSAGE_QUEUE_SIZE)
00093 {
00094 #ifdef HAVE_LIBLO
00095     m_thread = lo_server_thread_new(NULL, oscError);
00096 
00097     lo_server_thread_add_method(m_thread, NULL, NULL,
00098                                 oscMessageHandler, this);
00099 
00100     lo_server_thread_start(m_thread);
00101 
00102     std::cout << "OSCQueue::OSCQueue: Base OSC URL is "
00103               << lo_server_thread_get_url(m_thread) << std::endl;
00104 #endif
00105 }
00106 
00107 OSCQueue::~OSCQueue()
00108 {
00109 #ifdef HAVE_LIBLO
00110     if (m_thread) {
00111         lo_server_thread_stop(m_thread);
00112     }
00113 #endif
00114 
00115     while (m_buffer.getReadSpace() > 0) {
00116         delete m_buffer.readOne();
00117     }
00118 }
00119 
00120 bool
00121 OSCQueue::isOK() const
00122 {
00123 #ifdef HAVE_LIBLO
00124     return (m_thread != 0);
00125 #else
00126     return false;
00127 #endif
00128 }
00129 
00130 QString
00131 OSCQueue::getOSCURL() const
00132 {
00133     QString url = "";
00134 #ifdef HAVE_LIBLO
00135     url = lo_server_thread_get_url(m_thread);
00136 #endif
00137     return url;
00138 }
00139 
00140 size_t
00141 OSCQueue::getMessagesAvailable() const
00142 {
00143     return m_buffer.getReadSpace();
00144 }
00145 
00146 OSCMessage
00147 OSCQueue::readMessage()
00148 {
00149     OSCMessage *message = m_buffer.readOne();
00150     OSCMessage rmessage = *message;
00151     delete message;
00152     return rmessage;
00153 }
00154 
00155 void
00156 OSCQueue::postMessage(OSCMessage message)
00157 {
00158     int count = 0, max = 5;
00159     while (m_buffer.getWriteSpace() == 0) {
00160         if (count == max) {
00161             std::cerr << "ERROR: OSCQueue::postMessage: OSC message queue is full and not clearing -- abandoning incoming message" << std::endl;
00162             return;
00163         }
00164         std::cerr << "WARNING: OSCQueue::postMessage: OSC message queue (capacity " << m_buffer.getSize() << " is full!" << std::endl;
00165         std::cerr << "Waiting for something to be processed" << std::endl;
00166 #ifdef _WIN32
00167         Sleep(1);
00168 #else
00169         sleep(1);
00170 #endif
00171         count++;
00172     }
00173 
00174     OSCMessage *mp = new OSCMessage(message);
00175     m_buffer.write(&mp, 1);
00176     std::cerr << "OSCQueue::postMessage: Posted OSC message: target "
00177               << message.getTarget() << ", target data " << message.getTargetData()
00178               << ", method " << message.getMethod().toStdString() << std::endl;
00179     emit messagesAvailable();
00180 }
00181 
00182 bool
00183 OSCQueue::parseOSCPath(QString path, int &target, int &targetData,
00184                        QString &method)
00185 {
00186     while (path.startsWith("/")) {
00187         path = path.right(path.length()-1);
00188     }
00189 
00190     int i = 0;
00191 
00192     bool ok = false;
00193     target = path.section('/', i, i).toInt(&ok);
00194 
00195     if (!ok) {
00196         target = 0;
00197     } else {
00198         ++i;
00199         targetData = path.section('/', i, i).toInt(&ok);
00200         if (!ok) {
00201             targetData = 0;
00202         } else {
00203             ++i;
00204         }
00205     }
00206 
00207     method = path.section('/', i, -1);
00208 
00209     if (method.contains('/')) {
00210         std::cerr << "ERROR: OSCQueue::parseOSCPath: malformed path \""
00211                   << path.toStdString() << "\" (should be target/data/method or "
00212                   << "target/method or method, where target and data "
00213                   << "are numeric)" << std::endl;
00214         return false;
00215     }
00216 
00217     std::cerr << "OSCQueue::parseOSCPath: good path \"" << path.toStdString()
00218               << "\"" << std::endl;
00219 
00220     return true;
00221 }
00222 

Generated on Wed Feb 20 15:45:27 2008 for SonicVisualiser by  doxygen 1.5.1