annotate osc/OSCQueue.cpp @ 73:e200055fe80b

* Add vertical zooming and snap-to-selection for OSC control; add a demo script
author Chris Cannam
date Wed, 15 Nov 2006 18:22:26 +0000
parents 76cc2c424268
children bedc7517b6e8
rev   line source
Chris@69 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@69 2
Chris@69 3 /*
Chris@69 4 Sonic Visualiser
Chris@69 5 An audio file viewer and annotation editor.
Chris@69 6 Centre for Digital Music, Queen Mary, University of London.
Chris@69 7
Chris@69 8 This program is free software; you can redistribute it and/or
Chris@69 9 modify it under the terms of the GNU General Public License as
Chris@69 10 published by the Free Software Foundation; either version 2 of the
Chris@69 11 License, or (at your option) any later version. See the file
Chris@69 12 COPYING included with this distribution for more information.
Chris@69 13 */
Chris@69 14
Chris@69 15 /*
Chris@69 16 This is a modified version of a source file from the
Chris@69 17 Rosegarden MIDI and audio sequencer and notation editor.
Chris@69 18 This file copyright 2000-2006 Chris Cannam.
Chris@69 19 */
Chris@69 20
Chris@69 21 #include "OSCQueue.h"
Chris@69 22
Chris@69 23 #include <iostream>
Chris@69 24
Chris@69 25 #define OSC_MESSAGE_QUEUE_SIZE 1023
Chris@69 26
Chris@69 27 #ifdef HAVE_LIBLO
Chris@69 28
Chris@69 29 void
Chris@69 30 OSCQueue::oscError(int num, const char *msg, const char *path)
Chris@69 31 {
Chris@69 32 std::cerr << "ERROR: OSCQueue::oscError: liblo server error " << num
Chris@69 33 << " in path " << path << ": " << msg << std::endl;
Chris@69 34 }
Chris@69 35
Chris@69 36 int
Chris@69 37 OSCQueue::oscMessageHandler(const char *path, const char *types, lo_arg **argv,
Chris@69 38 int argc, lo_message, void *user_data)
Chris@69 39 {
Chris@69 40 OSCQueue *queue = static_cast<OSCQueue *>(user_data);
Chris@69 41
Chris@69 42 int target;
Chris@69 43 int targetData;
Chris@69 44 QString method;
Chris@69 45
Chris@69 46 if (!queue->parseOSCPath(path, target, targetData, method)) {
Chris@69 47 return 1;
Chris@69 48 }
Chris@69 49
Chris@69 50 OSCMessage message;
Chris@69 51 message.setTarget(target);
Chris@69 52 message.setTargetData(targetData);
Chris@69 53 message.setMethod(method);
Chris@69 54
Chris@69 55 int i = 0;
Chris@69 56
Chris@69 57 while (types && i < argc && types[i]) {
Chris@69 58
Chris@69 59 char type = types[i];
Chris@69 60 lo_arg *arg = argv[i];
Chris@69 61
Chris@69 62 switch (type) {
Chris@69 63 case 'i': message.addArg(arg->i); break;
Chris@69 64 case 'h': message.addArg(arg->h); break;
Chris@69 65 case 'f': message.addArg(arg->f); break;
Chris@69 66 case 'd': message.addArg(arg->d); break;
Chris@69 67 case 'c': message.addArg(arg->c); break;
Chris@69 68 case 't': message.addArg(arg->i); break;
Chris@69 69 case 's': message.addArg(&arg->s); break;
Chris@69 70 default: std::cerr << "WARNING: OSCQueue::oscMessageHandler: "
Chris@69 71 << "Unsupported OSC type '" << type << "'"
Chris@69 72 << std::endl;
Chris@69 73 break;
Chris@69 74 }
Chris@69 75
Chris@69 76 ++i;
Chris@69 77 }
Chris@69 78
Chris@69 79 queue->postMessage(message);
Chris@69 80 return 0;
Chris@69 81 }
Chris@69 82
Chris@69 83 #endif
Chris@69 84
Chris@69 85 OSCQueue::OSCQueue() :
Chris@69 86 #ifdef HAVE_LIBLO
Chris@69 87 m_thread(0),
Chris@69 88 #endif
Chris@69 89 m_buffer(OSC_MESSAGE_QUEUE_SIZE)
Chris@69 90 {
Chris@69 91 #ifdef HAVE_LIBLO
Chris@69 92 m_thread = lo_server_thread_new(NULL, oscError);
Chris@69 93
Chris@69 94 lo_server_thread_add_method(m_thread, NULL, NULL,
Chris@69 95 oscMessageHandler, this);
Chris@69 96
Chris@69 97 lo_server_thread_start(m_thread);
Chris@69 98
Chris@69 99 std::cout << "OSCQueue::OSCQueue: Base OSC URL is "
Chris@69 100 << lo_server_thread_get_url(m_thread) << std::endl;
Chris@69 101 #endif
Chris@69 102 }
Chris@69 103
Chris@69 104 OSCQueue::~OSCQueue()
Chris@69 105 {
Chris@69 106 #ifdef HAVE_LIBLO
Chris@69 107 if (m_thread) {
Chris@69 108 lo_server_thread_stop(m_thread);
Chris@69 109 }
Chris@69 110 #endif
Chris@69 111
Chris@69 112 while (m_buffer.getReadSpace() > 0) {
Chris@69 113 delete m_buffer.readOne();
Chris@69 114 }
Chris@69 115 }
Chris@69 116
Chris@69 117 bool
Chris@69 118 OSCQueue::isOK() const
Chris@69 119 {
Chris@69 120 #ifdef HAVE_LIBLO
Chris@69 121 return (m_thread != 0);
Chris@69 122 #else
Chris@69 123 return false;
Chris@69 124 #endif
Chris@69 125 }
Chris@69 126
Chris@69 127 QString
Chris@69 128 OSCQueue::getOSCURL() const
Chris@69 129 {
Chris@69 130 QString url = "";
Chris@69 131 #ifdef HAVE_LIBLO
Chris@69 132 url = lo_server_thread_get_url(m_thread);
Chris@69 133 #endif
Chris@69 134 return url;
Chris@69 135 }
Chris@69 136
Chris@69 137 size_t
Chris@69 138 OSCQueue::getMessagesAvailable() const
Chris@69 139 {
Chris@69 140 return m_buffer.getReadSpace();
Chris@69 141 }
Chris@69 142
Chris@69 143 OSCMessage
Chris@69 144 OSCQueue::readMessage()
Chris@69 145 {
Chris@69 146 OSCMessage *message = m_buffer.readOne();
Chris@69 147 OSCMessage rmessage = *message;
Chris@69 148 delete message;
Chris@69 149 return rmessage;
Chris@69 150 }
Chris@69 151
Chris@69 152 void
Chris@69 153 OSCQueue::postMessage(OSCMessage message)
Chris@69 154 {
Chris@69 155 int count = 0, max = 5;
Chris@69 156 while (m_buffer.getWriteSpace() == 0) {
Chris@69 157 if (count == max) {
Chris@69 158 std::cerr << "ERROR: OSCQueue::postMessage: OSC message queue is full and not clearing -- abandoning incoming message" << std::endl;
Chris@69 159 return;
Chris@69 160 }
Chris@69 161 std::cerr << "WARNING: OSCQueue::postMessage: OSC message queue (capacity " << m_buffer.getSize() << " is full!" << std::endl;
Chris@69 162 std::cerr << "Waiting for something to be processed" << std::endl;
Chris@69 163 sleep(1);
Chris@69 164 count++;
Chris@69 165 }
Chris@69 166
Chris@69 167 OSCMessage *mp = new OSCMessage(message);
Chris@69 168 m_buffer.write(&mp, 1);
Chris@69 169 std::cerr << "OSCQueue::postMessage: Posted OSC message: target "
Chris@69 170 << message.getTarget() << ", target data " << message.getTargetData()
Chris@69 171 << ", method " << message.getMethod().toStdString() << std::endl;
Chris@69 172 emit messagesAvailable();
Chris@69 173 }
Chris@69 174
Chris@69 175 bool
Chris@69 176 OSCQueue::parseOSCPath(QString path, int &target, int &targetData,
Chris@69 177 QString &method)
Chris@69 178 {
Chris@69 179 while (path.startsWith("/")) {
Chris@69 180 path = path.right(path.length()-1);
Chris@69 181 }
Chris@69 182
Chris@69 183 int i = 0;
Chris@69 184
Chris@69 185 bool ok = false;
Chris@69 186 target = path.section('/', i, i).toInt(&ok);
Chris@69 187
Chris@69 188 if (!ok) {
Chris@69 189 target = 0;
Chris@69 190 } else {
Chris@69 191 ++i;
Chris@69 192 targetData = path.section('/', i, i).toInt(&ok);
Chris@69 193 if (!ok) {
Chris@69 194 targetData = 0;
Chris@69 195 } else {
Chris@69 196 ++i;
Chris@69 197 }
Chris@69 198 }
Chris@69 199
Chris@69 200 method = path.section('/', i, -1);
Chris@69 201
Chris@69 202 if (method.contains('/')) {
Chris@69 203 std::cerr << "ERROR: OSCQueue::parseOSCPath: malformed path \""
Chris@69 204 << path.toStdString() << "\" (should be target/data/method or "
Chris@69 205 << "target/method or method, where target and data "
Chris@69 206 << "are numeric)" << std::endl;
Chris@69 207 return false;
Chris@69 208 }
Chris@69 209
Chris@69 210 std::cerr << "OSCQueue::parseOSCPath: good path \"" << path.toStdString()
Chris@69 211 << "\"" << std::endl;
Chris@69 212
Chris@69 213 return true;
Chris@69 214 }
Chris@69 215