Mercurial > hg > svcore
view data/osc/OSCQueue.cpp @ 1682:4ca784e5033e single-point
Restore always-on export of label even if empty - backward compatibility makes testing easier
author | Chris Cannam |
---|---|
date | Wed, 03 Apr 2019 16:03:18 +0100 |
parents | 1078f0ef3012 |
children | c077a97d055f |
line wrap: on
line source
/* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ /* Sonic Visualiser An audio file viewer and annotation editor. Centre for Digital Music, Queen Mary, University of London. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. See the file COPYING included with this distribution for more information. */ /* This is a modified version of a source file from the Rosegarden MIDI and audio sequencer and notation editor. This file copyright 2000-2006 Chris Cannam and QMUL. */ #include "OSCQueue.h" #include "base/Profiler.h" #include <iostream> #define OSC_MESSAGE_QUEUE_SIZE 1023 #ifdef HAVE_LIBLO #include <unistd.h> #include <QThread> void OSCQueue::oscError(int num, const char *msg, const char *path) { cerr << "ERROR: OSCQueue::oscError: liblo server error " << num << " in path " << path << ": " << msg << endl; } int OSCQueue::oscMessageHandler(const char *path, const char *types, lo_arg **argv, int argc, lo_message, void *user_data) { OSCQueue *queue = static_cast<OSCQueue *>(user_data); int target; int targetData; QString method; if (!queue->parseOSCPath(path, target, targetData, method)) { return 1; } OSCMessage message; message.setTarget(target); message.setTargetData(targetData); message.setMethod(method); int i = 0; while (types && i < argc && types[i]) { char type = types[i]; lo_arg *arg = argv[i]; switch (type) { case 'i': message.addArg(arg->i); break; // This conversion fails to compile in 64-bit environments // at present, and we don't use the h type anyway so we // can safely omit it // case 'h': message.addArg(arg->h); break; case 'f': message.addArg(arg->f); break; case 'd': message.addArg(arg->d); break; case 'c': message.addArg(arg->c); break; case 't': message.addArg(arg->i); break; case 's': message.addArg(&arg->s); break; default: cerr << "WARNING: OSCQueue::oscMessageHandler: " << "Unsupported OSC type '" << type << "'" << endl; break; } ++i; } queue->postMessage(message); return 0; } #endif OSCQueue::OSCQueue(bool withNetworkPort) : #ifdef HAVE_LIBLO m_thread(nullptr), #endif m_withPort(withNetworkPort), m_buffer(OSC_MESSAGE_QUEUE_SIZE) { Profiler profiler("OSCQueue::OSCQueue"); #ifdef HAVE_LIBLO if (m_withPort) { m_thread = lo_server_thread_new(nullptr, oscError); lo_server_thread_add_method(m_thread, nullptr, nullptr, oscMessageHandler, this); lo_server_thread_start(m_thread); SVDEBUG << "OSCQueue::OSCQueue: Started OSC thread, URL is " << lo_server_thread_get_url(m_thread) << endl; cout << "OSCQueue::OSCQueue: Base OSC URL is " << lo_server_thread_get_url(m_thread) << endl; } #else if (m_withPort) { SVDEBUG << "OSCQueue::OSCQueue: Note: OSC port support not " << "compiled in; not opening port, falling back to " << "internal-only queue" << endl; m_withPort = false; } #endif } OSCQueue::~OSCQueue() { #ifdef HAVE_LIBLO if (m_thread) { lo_server_thread_stop(m_thread); } #endif while (m_buffer.getReadSpace() > 0) { delete m_buffer.readOne(); } } bool OSCQueue::isOK() const { if (!m_withPort) { return true; } else { #ifdef HAVE_LIBLO return (m_thread != nullptr); #else return false; #endif } } QString OSCQueue::getOSCURL() const { QString url = ""; #ifdef HAVE_LIBLO if (m_thread) { url = lo_server_thread_get_url(m_thread); } #endif return url; } int OSCQueue::getMessagesAvailable() const { return m_buffer.getReadSpace(); } OSCMessage OSCQueue::readMessage() { OSCMessage *message = m_buffer.readOne(); OSCMessage rmessage = *message; delete message; SVDEBUG << "OSCQueue::readMessage: In thread " << QThread::currentThreadId() << ": message follows:\n" << rmessage.toString() << endl; return rmessage; } void OSCQueue::postMessage(OSCMessage message) { int count = 0, max = 5; while (m_buffer.getWriteSpace() == 0) { if (count == max) { cerr << "ERROR: OSCQueue::postMessage: OSC message queue is full and not clearing -- abandoning incoming message" << endl; return; } cerr << "WARNING: OSCQueue::postMessage: OSC message queue (capacity " << m_buffer.getSize() << " is full!" << endl; SVDEBUG << "Waiting for something to be processed" << endl; #ifdef _WIN32 Sleep(1); #else sleep(1); #endif count++; } OSCMessage *mp = new OSCMessage(message); m_buffer.write(&mp, 1); SVDEBUG << "OSCQueue::postMessage: Posted OSC message: target " << message.getTarget() << ", target data " << message.getTargetData() << ", method " << message.getMethod() << endl; emit messagesAvailable(); } bool OSCQueue::parseOSCPath(QString path, int &target, int &targetData, QString &method) { while (path.startsWith("/")) { path = path.right(path.length()-1); } int i = 0; bool ok = false; target = path.section('/', i, i).toInt(&ok); if (!ok) { target = 0; } else { ++i; targetData = path.section('/', i, i).toInt(&ok); if (!ok) { targetData = 0; } else { ++i; } } method = path.section('/', i, -1); if (method.contains('/')) { cerr << "ERROR: OSCQueue::parseOSCPath: malformed path \"" << path << "\" (should be target/data/method or " << "target/method or method, where target and data " << "are numeric)" << endl; return false; } SVDEBUG << "OSCQueue::parseOSCPath: good path \"" << path << "\"" << endl; return true; }