annotate data/osc/OSCQueue.cpp @ 1196:c7b9c902642f spectrogram-minor-refactor

Fix threshold in spectrogram -- it wasn't working in the last release. There is a new protocol for this. Formerly the threshold parameter had a range from -50dB to 0 with the default at -50, and -50 treated internally as "no threshold". However, there was a hardcoded, hidden internal threshold for spectrogram colour mapping at -80dB with anything below this being rounded to zero. Now the threshold parameter has range -81 to -1 with the default at -80, -81 is treated internally as "no threshold", and there is no hidden internal threshold. So the default behaviour is the same as before, an effective -80dB threshold, but it is now possible to change this in both directions. Sessions reloaded from prior versions may look slightly different because, if the session says there should be no threshold, there will now actually be no threshold instead of having the hidden internal one. Still need to do something in the UI to make it apparent that the -81dB setting removes the threshold entirely. This is at least no worse than the previous, also obscured, magic -50dB setting.
author Chris Cannam
date Mon, 01 Aug 2016 16:21:01 +0100
parents 59e7fe1b1003
children 6b847a59d908
rev   line source
Chris@320 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@320 2
Chris@320 3 /*
Chris@320 4 Sonic Visualiser
Chris@320 5 An audio file viewer and annotation editor.
Chris@320 6 Centre for Digital Music, Queen Mary, University of London.
Chris@320 7
Chris@320 8 This program is free software; you can redistribute it and/or
Chris@320 9 modify it under the terms of the GNU General Public License as
Chris@320 10 published by the Free Software Foundation; either version 2 of the
Chris@320 11 License, or (at your option) any later version. See the file
Chris@320 12 COPYING included with this distribution for more information.
Chris@320 13 */
Chris@320 14
Chris@320 15 /*
Chris@320 16 This is a modified version of a source file from the
Chris@320 17 Rosegarden MIDI and audio sequencer and notation editor.
Chris@320 18 This file copyright 2000-2006 Chris Cannam and QMUL.
Chris@320 19 */
Chris@320 20
Chris@320 21 #include "OSCQueue.h"
Chris@320 22
Chris@408 23 #include "base/Profiler.h"
Chris@408 24
Chris@320 25 #include <iostream>
Chris@608 26 #include <unistd.h>
Chris@320 27
Chris@320 28 #define OSC_MESSAGE_QUEUE_SIZE 1023
Chris@320 29
Chris@320 30 #ifdef HAVE_LIBLO
Chris@320 31
Chris@320 32 void
Chris@320 33 OSCQueue::oscError(int num, const char *msg, const char *path)
Chris@320 34 {
Chris@843 35 cerr << "ERROR: OSCQueue::oscError: liblo server error " << num
Chris@843 36 << " in path " << path << ": " << msg << endl;
Chris@320 37 }
Chris@320 38
Chris@320 39 int
Chris@320 40 OSCQueue::oscMessageHandler(const char *path, const char *types, lo_arg **argv,
Chris@320 41 int argc, lo_message, void *user_data)
Chris@320 42 {
Chris@320 43 OSCQueue *queue = static_cast<OSCQueue *>(user_data);
Chris@320 44
Chris@320 45 int target;
Chris@320 46 int targetData;
Chris@320 47 QString method;
Chris@320 48
Chris@320 49 if (!queue->parseOSCPath(path, target, targetData, method)) {
Chris@320 50 return 1;
Chris@320 51 }
Chris@320 52
Chris@320 53 OSCMessage message;
Chris@320 54 message.setTarget(target);
Chris@320 55 message.setTargetData(targetData);
Chris@320 56 message.setMethod(method);
Chris@320 57
Chris@320 58 int i = 0;
Chris@320 59
Chris@320 60 while (types && i < argc && types[i]) {
Chris@320 61
Chris@320 62 char type = types[i];
Chris@320 63 lo_arg *arg = argv[i];
Chris@320 64
Chris@320 65 switch (type) {
Chris@320 66 case 'i': message.addArg(arg->i); break;
Chris@320 67 // This conversion fails to compile in 64-bit environments
Chris@320 68 // at present, and we don't use the h type anyway so we
Chris@320 69 // can safely omit it
Chris@320 70 // case 'h': message.addArg(arg->h); break;
Chris@320 71 case 'f': message.addArg(arg->f); break;
Chris@320 72 case 'd': message.addArg(arg->d); break;
Chris@320 73 case 'c': message.addArg(arg->c); break;
Chris@320 74 case 't': message.addArg(arg->i); break;
Chris@320 75 case 's': message.addArg(&arg->s); break;
Chris@843 76 default: cerr << "WARNING: OSCQueue::oscMessageHandler: "
Chris@320 77 << "Unsupported OSC type '" << type << "'"
Chris@843 78 << endl;
Chris@320 79 break;
Chris@320 80 }
Chris@320 81
Chris@320 82 ++i;
Chris@320 83 }
Chris@320 84
Chris@320 85 queue->postMessage(message);
Chris@320 86 return 0;
Chris@320 87 }
Chris@320 88
Chris@320 89 #endif
Chris@320 90
Chris@320 91 OSCQueue::OSCQueue() :
Chris@320 92 #ifdef HAVE_LIBLO
Chris@320 93 m_thread(0),
Chris@320 94 #endif
Chris@320 95 m_buffer(OSC_MESSAGE_QUEUE_SIZE)
Chris@320 96 {
Chris@408 97 Profiler profiler("OSCQueue::OSCQueue");
Chris@408 98
Chris@320 99 #ifdef HAVE_LIBLO
Chris@320 100 m_thread = lo_server_thread_new(NULL, oscError);
Chris@320 101
Chris@320 102 lo_server_thread_add_method(m_thread, NULL, NULL,
Chris@320 103 oscMessageHandler, this);
Chris@320 104
Chris@320 105 lo_server_thread_start(m_thread);
Chris@320 106
Chris@843 107 cout << "OSCQueue::OSCQueue: Base OSC URL is "
Chris@843 108 << lo_server_thread_get_url(m_thread) << endl;
Chris@320 109 #endif
Chris@320 110 }
Chris@320 111
Chris@320 112 OSCQueue::~OSCQueue()
Chris@320 113 {
Chris@320 114 #ifdef HAVE_LIBLO
Chris@320 115 if (m_thread) {
Chris@320 116 lo_server_thread_stop(m_thread);
Chris@320 117 }
Chris@320 118 #endif
Chris@320 119
Chris@320 120 while (m_buffer.getReadSpace() > 0) {
Chris@320 121 delete m_buffer.readOne();
Chris@320 122 }
Chris@320 123 }
Chris@320 124
Chris@320 125 bool
Chris@320 126 OSCQueue::isOK() const
Chris@320 127 {
Chris@320 128 #ifdef HAVE_LIBLO
Chris@320 129 return (m_thread != 0);
Chris@320 130 #else
Chris@320 131 return false;
Chris@320 132 #endif
Chris@320 133 }
Chris@320 134
Chris@320 135 QString
Chris@320 136 OSCQueue::getOSCURL() const
Chris@320 137 {
Chris@320 138 QString url = "";
Chris@320 139 #ifdef HAVE_LIBLO
Chris@320 140 url = lo_server_thread_get_url(m_thread);
Chris@320 141 #endif
Chris@320 142 return url;
Chris@320 143 }
Chris@320 144
Chris@929 145 int
Chris@320 146 OSCQueue::getMessagesAvailable() const
Chris@320 147 {
Chris@320 148 return m_buffer.getReadSpace();
Chris@320 149 }
Chris@320 150
Chris@320 151 OSCMessage
Chris@320 152 OSCQueue::readMessage()
Chris@320 153 {
Chris@320 154 OSCMessage *message = m_buffer.readOne();
Chris@320 155 OSCMessage rmessage = *message;
Chris@320 156 delete message;
Chris@320 157 return rmessage;
Chris@320 158 }
Chris@320 159
Chris@320 160 void
Chris@320 161 OSCQueue::postMessage(OSCMessage message)
Chris@320 162 {
Chris@320 163 int count = 0, max = 5;
Chris@320 164 while (m_buffer.getWriteSpace() == 0) {
Chris@320 165 if (count == max) {
Chris@843 166 cerr << "ERROR: OSCQueue::postMessage: OSC message queue is full and not clearing -- abandoning incoming message" << endl;
Chris@320 167 return;
Chris@320 168 }
Chris@843 169 cerr << "WARNING: OSCQueue::postMessage: OSC message queue (capacity " << m_buffer.getSize() << " is full!" << endl;
Chris@690 170 SVDEBUG << "Waiting for something to be processed" << endl;
Chris@320 171 #ifdef _WIN32
Chris@320 172 Sleep(1);
Chris@320 173 #else
Chris@320 174 sleep(1);
Chris@320 175 #endif
Chris@320 176 count++;
Chris@320 177 }
Chris@320 178
Chris@320 179 OSCMessage *mp = new OSCMessage(message);
Chris@320 180 m_buffer.write(&mp, 1);
Chris@690 181 SVDEBUG << "OSCQueue::postMessage: Posted OSC message: target "
Chris@320 182 << message.getTarget() << ", target data " << message.getTargetData()
Chris@687 183 << ", method " << message.getMethod() << endl;
Chris@320 184 emit messagesAvailable();
Chris@320 185 }
Chris@320 186
Chris@320 187 bool
Chris@320 188 OSCQueue::parseOSCPath(QString path, int &target, int &targetData,
Chris@320 189 QString &method)
Chris@320 190 {
Chris@320 191 while (path.startsWith("/")) {
Chris@320 192 path = path.right(path.length()-1);
Chris@320 193 }
Chris@320 194
Chris@320 195 int i = 0;
Chris@320 196
Chris@320 197 bool ok = false;
Chris@320 198 target = path.section('/', i, i).toInt(&ok);
Chris@320 199
Chris@320 200 if (!ok) {
Chris@320 201 target = 0;
Chris@320 202 } else {
Chris@320 203 ++i;
Chris@320 204 targetData = path.section('/', i, i).toInt(&ok);
Chris@320 205 if (!ok) {
Chris@320 206 targetData = 0;
Chris@320 207 } else {
Chris@320 208 ++i;
Chris@320 209 }
Chris@320 210 }
Chris@320 211
Chris@320 212 method = path.section('/', i, -1);
Chris@320 213
Chris@320 214 if (method.contains('/')) {
Chris@843 215 cerr << "ERROR: OSCQueue::parseOSCPath: malformed path \""
Chris@686 216 << path << "\" (should be target/data/method or "
Chris@320 217 << "target/method or method, where target and data "
Chris@843 218 << "are numeric)" << endl;
Chris@320 219 return false;
Chris@320 220 }
Chris@320 221
Chris@690 222 SVDEBUG << "OSCQueue::parseOSCPath: good path \"" << path << "\"" << endl;
Chris@320 223
Chris@320 224 return true;
Chris@320 225 }
Chris@320 226