annotate widgets/PluginParameterBox.cpp @ 1534:bfd8b22fd67c

Fix #1904 Scrolling colour 3d plot does not always work when in View normalisation mode. We shouldn't imagine we've just invalidated the cache if the truth is that we've only just created the renderer
author Chris Cannam
date Wed, 09 Oct 2019 13:45:17 +0100
parents c8a6fd3f9dff
children 11660e0c896f
rev   line source
Chris@60 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@60 2
Chris@60 3 /*
Chris@60 4 Sonic Visualiser
Chris@60 5 An audio file viewer and annotation editor.
Chris@60 6 Centre for Digital Music, Queen Mary, University of London.
Chris@182 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@60 8
Chris@60 9 This program is free software; you can redistribute it and/or
Chris@60 10 modify it under the terms of the GNU General Public License as
Chris@60 11 published by the Free Software Foundation; either version 2 of the
Chris@60 12 License, or (at your option) any later version. See the file
Chris@60 13 COPYING included with this distribution for more information.
Chris@60 14 */
Chris@60 15
Chris@60 16 #include "PluginParameterBox.h"
Chris@60 17
Chris@60 18 #include "AudioDial.h"
Chris@60 19
Chris@71 20 #include "plugin/PluginXml.h"
Chris@342 21 #include "plugin/RealTimePluginInstance.h" // for PortHint stuff
Chris@71 22
Chris@167 23 #include "base/RangeMapper.h"
Chris@167 24
Chris@60 25 #include <QDoubleSpinBox>
Chris@60 26 #include <QGridLayout>
Chris@63 27 #include <QComboBox>
Chris@63 28 #include <QCheckBox>
Chris@60 29 #include <QLayout>
Chris@60 30 #include <QLabel>
Chris@60 31
Chris@60 32 #include <iostream>
Chris@60 33 #include <string>
Chris@60 34
Chris@78 35 #include <cmath>
Chris@78 36
Chris@71 37 PluginParameterBox::PluginParameterBox(Vamp::PluginBase *plugin, QWidget *parent) :
Chris@62 38 QFrame(parent),
Chris@293 39 m_plugin(plugin),
Chris@1408 40 m_programCombo(nullptr)
Chris@60 41 {
Chris@60 42 m_layout = new QGridLayout;
Chris@60 43 setLayout(m_layout);
Chris@60 44 populate();
Chris@60 45 }
Chris@60 46
Chris@60 47 PluginParameterBox::~PluginParameterBox()
Chris@60 48 {
Chris@60 49 }
Chris@60 50
Chris@60 51 void
Chris@60 52 PluginParameterBox::populate()
Chris@60 53 {
Chris@71 54 Vamp::PluginBase::ParameterList params = m_plugin->getParameterDescriptors();
Chris@293 55 m_programs = m_plugin->getPrograms();
Chris@60 56
Chris@60 57 m_params.clear();
Chris@60 58
Chris@293 59 if (params.empty() && m_programs.empty()) {
Chris@62 60 m_layout->addWidget
Chris@62 61 (new QLabel(tr("This plugin has no adjustable parameters.")),
Chris@62 62 0, 0);
Chris@62 63 }
Chris@62 64
Chris@63 65 int offset = 0;
Chris@63 66
Chris@293 67 if (!m_programs.empty()) {
Chris@63 68
Chris@63 69 std::string currentProgram = m_plugin->getCurrentProgram();
Chris@63 70
Chris@293 71 m_programCombo = new QComboBox;
Chris@293 72 m_programCombo->setMaxVisibleItems
Chris@908 73 (int(m_programs.size() < 25 ? m_programs.size() : 20));
Chris@63 74
Chris@908 75 for (int i = 0; in_range_for(m_programs, i); ++i) {
Chris@293 76 m_programCombo->addItem(m_programs[i].c_str());
Chris@293 77 if (m_programs[i] == currentProgram) {
Chris@908 78 m_programCombo->setCurrentIndex(int(i));
Chris@63 79 }
Chris@63 80 }
Chris@63 81
Chris@63 82 m_layout->addWidget(new QLabel(tr("Program")), 0, 0);
Chris@293 83 m_layout->addWidget(m_programCombo, 0, 1, 1, 2);
Chris@63 84
Chris@293 85 connect(m_programCombo, SIGNAL(currentIndexChanged(const QString &)),
Chris@63 86 this, SLOT(programComboChanged(const QString &)));
Chris@63 87
Chris@63 88 offset = 1;
Chris@63 89 }
Chris@63 90
Chris@908 91 for (int i = 0; in_range_for(params, i); ++i) {
Chris@60 92
Chris@207 93 QString identifier = params[i].identifier.c_str();
Chris@60 94 QString name = params[i].name.c_str();
Chris@60 95 QString unit = params[i].unit.c_str();
Chris@60 96
Chris@60 97 float min = params[i].minValue;
Chris@60 98 float max = params[i].maxValue;
Chris@60 99 float deft = params[i].defaultValue;
Chris@207 100 float value = m_plugin->getParameter(params[i].identifier);
Chris@60 101
Chris@342 102 int hint = PortHint::NoHint;
Chris@342 103 RealTimePluginInstance *rtpi = dynamic_cast<RealTimePluginInstance *>
Chris@342 104 (m_plugin);
Chris@342 105 if (rtpi) {
Chris@342 106 hint = rtpi->getParameterDisplayHint(i);
Chris@342 107 }
Chris@342 108
Chris@60 109 float qtz = 0.0;
Chris@60 110 if (params[i].isQuantized) qtz = params[i].quantizeStep;
Chris@60 111
Chris@682 112 // cerr << "PluginParameterBox: hint = " << hint << ", min = " << min << ", max = "
Chris@682 113 // << max << ", qtz = " << qtz << endl;
Chris@342 114
Chris@74 115 std::vector<std::string> valueNames = params[i].valueNames;
Chris@74 116
Chris@60 117 // construct an integer range
Chris@60 118
Chris@60 119 int imin = 0, imax = 100;
Chris@60 120
Chris@342 121 if (!(hint & PortHint::Logarithmic)) {
Chris@342 122 if (qtz > 0.0) {
Chris@908 123 imax = int(lrintf((max - min) / qtz));
Chris@1348 124 if (imax <= imin) {
Chris@1348 125 imax = 100;
Chris@1348 126 qtz = (max - min) / 100.f;
Chris@1348 127 }
Chris@342 128 } else {
Chris@908 129 qtz = (max - min) / 100.f;
Chris@342 130 }
Chris@60 131 }
Chris@60 132
Chris@60 133 //!!! would be nice to ensure the default value corresponds to
Chris@60 134 // an integer!
Chris@60 135
Chris@207 136 QLabel *label = new QLabel(name);
Chris@208 137 if (params[i].description != "") {
Chris@828 138 label->setToolTip(QString("<qt>%1</qt>")
Chris@828 139 .arg(params[i].description.c_str())
Chris@828 140 .replace("\n", "<br>"));
Chris@208 141 }
Chris@63 142 m_layout->addWidget(label, i + offset, 0);
Chris@60 143
Chris@60 144 ParamRec rec;
Chris@60 145 rec.param = params[i];
Chris@1408 146 rec.dial = nullptr;
Chris@1408 147 rec.spin = nullptr;
Chris@1408 148 rec.check = nullptr;
Chris@1408 149 rec.combo = nullptr;
Chris@63 150
Chris@74 151 if (params[i].isQuantized && !valueNames.empty()) {
Chris@74 152
Chris@74 153 QComboBox *combobox = new QComboBox;
Chris@207 154 combobox->setObjectName(identifier);
Chris@74 155 for (unsigned int j = 0; j < valueNames.size(); ++j) {
Chris@74 156 combobox->addItem(valueNames[j].c_str());
Chris@249 157 if ((unsigned int)(lrintf(fabsf((value - min) / qtz))) == j) {
Chris@74 158 combobox->setCurrentIndex(j);
Chris@74 159 }
Chris@74 160 }
Chris@74 161 connect(combobox, SIGNAL(activated(int)),
Chris@74 162 this, SLOT(dialChanged(int)));
Chris@74 163 m_layout->addWidget(combobox, i + offset, 1, 1, 2);
Chris@74 164 rec.combo = combobox;
Chris@74 165
Chris@74 166 } else if (min == 0.0 && max == 1.0 && qtz == 1.0) {
Chris@63 167
Chris@63 168 QCheckBox *checkbox = new QCheckBox;
Chris@207 169 checkbox->setObjectName(identifier);
Chris@293 170 checkbox->setCheckState(value < 0.5 ? Qt::Unchecked : Qt::Checked);
Chris@63 171 connect(checkbox, SIGNAL(stateChanged(int)),
Chris@63 172 this, SLOT(checkBoxChanged(int)));
Chris@63 173 m_layout->addWidget(checkbox, i + offset, 2);
Chris@63 174 rec.check = checkbox;
Chris@63 175
Chris@63 176 } else {
Chris@63 177
Chris@63 178 AudioDial *dial = new AudioDial;
Chris@207 179 dial->setObjectName(name);
Chris@63 180 dial->setMinimum(imin);
Chris@63 181 dial->setMaximum(imax);
Chris@63 182 dial->setPageStep(1);
Chris@63 183 dial->setNotchesVisible((imax - imin) <= 12);
Chris@342 184 //!!! dial->setDefaultValue(lrintf((deft - min) / qtz));
Chris@342 185 // dial->setValue(lrintf((value - min) / qtz));
Chris@63 186 dial->setFixedWidth(32);
Chris@63 187 dial->setFixedHeight(32);
Chris@1348 188 if (max == min || imax == imin) {
Chris@1348 189 SVCERR << "WARNING: for parameter \"" << name
Chris@1348 190 << "\" of plugin \"" << m_plugin->getName()
Chris@1348 191 << "\": invalid range " << min << " -> " << max
Chris@1348 192 << " with quantize step " << qtz << endl;
Chris@342 193 } else {
Chris@1408 194 RangeMapper *rm = nullptr;
Chris@1348 195 if (hint & PortHint::Logarithmic) {
Chris@1348 196 rm = new LogRangeMapper(imin, imax, min, max, unit);
Chris@1348 197 } else {
Chris@1348 198 rm = new LinearRangeMapper(imin, imax, min, max, unit);
Chris@1348 199 }
Chris@1348 200 dial->setRangeMapper(rm);
Chris@1348 201 dial->setDefaultValue(rm->getPositionForValue(deft));
Chris@1348 202 dial->setValue(rm->getPositionForValue(value));
Chris@342 203 }
Chris@168 204 dial->setShowToolTip(true);
Chris@63 205 connect(dial, SIGNAL(valueChanged(int)),
Chris@63 206 this, SLOT(dialChanged(int)));
Chris@63 207 m_layout->addWidget(dial, i + offset, 1);
Chris@63 208
Chris@63 209 QDoubleSpinBox *spinbox = new QDoubleSpinBox;
Chris@207 210 spinbox->setObjectName(identifier);
Chris@63 211 spinbox->setMinimum(min);
Chris@63 212 spinbox->setMaximum(max);
Chris@63 213 spinbox->setSuffix(QString(" %1").arg(unit));
Chris@342 214 if (qtz != 0) spinbox->setSingleStep(qtz);
Chris@63 215 spinbox->setValue(value);
Chris@103 216 spinbox->setDecimals(4);
Chris@63 217 connect(spinbox, SIGNAL(valueChanged(double)),
Chris@63 218 this, SLOT(spinBoxChanged(double)));
Chris@63 219 m_layout->addWidget(spinbox, i + offset, 2);
Chris@63 220 rec.dial = dial;
Chris@63 221 rec.spin = spinbox;
Chris@63 222 }
Chris@63 223
Chris@207 224 m_params[identifier] = rec;
Chris@207 225 m_nameMap[name] = identifier;
Chris@60 226 }
Chris@60 227 }
Chris@60 228
Chris@60 229 void
Chris@60 230 PluginParameterBox::dialChanged(int ival)
Chris@60 231 {
Chris@60 232 QObject *obj = sender();
Chris@207 233 QString identifier = obj->objectName();
Chris@60 234
Chris@207 235 if (m_params.find(identifier) == m_params.end() &&
Chris@207 236 m_nameMap.find(identifier) != m_nameMap.end()) {
Chris@207 237 identifier = m_nameMap[identifier];
Chris@167 238 }
Chris@167 239
Chris@207 240 if (m_params.find(identifier) == m_params.end()) {
Chris@682 241 cerr << "WARNING: PluginParameterBox::dialChanged: Unknown parameter \"" << identifier << "\"" << endl;
Chris@60 242 return;
Chris@60 243 }
Chris@60 244
Chris@207 245 Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
Chris@60 246
Chris@60 247 float min = params.minValue;
Chris@60 248 float max = params.maxValue;
Chris@60 249
Chris@168 250 float newValue;
Chris@168 251
Chris@60 252 float qtz = 0.0;
Chris@60 253 if (params.isQuantized) qtz = params.quantizeStep;
Chris@168 254
Chris@168 255 AudioDial *ad = dynamic_cast<AudioDial *>(obj);
Chris@60 256
Chris@168 257 if (ad && ad->rangeMapper()) {
Chris@168 258
Chris@908 259 newValue = float(ad->mappedValue());
Chris@168 260 if (newValue < min) newValue = min;
Chris@168 261 if (newValue > max) newValue = max;
Chris@168 262 if (qtz != 0.0) {
Chris@908 263 ival = int(lrintf((newValue - min) / qtz));
Chris@908 264 newValue = min + float(ival) * qtz;
Chris@168 265 }
Chris@168 266
Chris@168 267 } else {
Chris@908 268 if (qtz == 0.f) {
Chris@908 269 qtz = (max - min) / 100.f;
Chris@168 270 }
Chris@908 271 newValue = min + float(ival) * qtz;
Chris@60 272 }
Chris@60 273
Chris@587 274 // SVDEBUG << "PluginParameterBox::dialChanged: newValue = " << newValue << endl;
Chris@342 275
Chris@207 276 QDoubleSpinBox *spin = m_params[identifier].spin;
Chris@63 277 if (spin) {
Chris@63 278 spin->blockSignals(true);
Chris@63 279 spin->setValue(newValue);
Chris@63 280 spin->blockSignals(false);
Chris@63 281 }
Chris@60 282
Chris@587 283 // SVDEBUG << "setting plugin parameter \"" << identifier << "\" to value " << newValue << endl;
Chris@530 284
Chris@207 285 m_plugin->setParameter(identifier.toStdString(), newValue);
Chris@64 286
Chris@293 287 updateProgramCombo();
Chris@293 288
Chris@71 289 emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
Chris@60 290 }
Chris@60 291
Chris@60 292 void
Chris@63 293 PluginParameterBox::checkBoxChanged(int state)
Chris@63 294 {
Chris@63 295 QObject *obj = sender();
Chris@207 296 QString identifier = obj->objectName();
Chris@63 297
Chris@207 298 if (m_params.find(identifier) == m_params.end() &&
Chris@207 299 m_nameMap.find(identifier) != m_nameMap.end()) {
Chris@207 300 identifier = m_nameMap[identifier];
Chris@167 301 }
Chris@167 302
Chris@207 303 if (m_params.find(identifier) == m_params.end()) {
Chris@682 304 cerr << "WARNING: PluginParameterBox::checkBoxChanged: Unknown parameter \"" << identifier << "\"" << endl;
Chris@63 305 return;
Chris@63 306 }
Chris@63 307
Chris@207 308 Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
Chris@63 309
Chris@207 310 if (state) m_plugin->setParameter(identifier.toStdString(), 1.0);
Chris@207 311 else m_plugin->setParameter(identifier.toStdString(), 0.0);
Chris@64 312
Chris@293 313 updateProgramCombo();
Chris@293 314
Chris@71 315 emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
Chris@63 316 }
Chris@63 317
Chris@63 318 void
Chris@60 319 PluginParameterBox::spinBoxChanged(double value)
Chris@60 320 {
Chris@60 321 QObject *obj = sender();
Chris@207 322 QString identifier = obj->objectName();
Chris@60 323
Chris@207 324 if (m_params.find(identifier) == m_params.end() &&
Chris@207 325 m_nameMap.find(identifier) != m_nameMap.end()) {
Chris@207 326 identifier = m_nameMap[identifier];
Chris@167 327 }
Chris@167 328
Chris@207 329 if (m_params.find(identifier) == m_params.end()) {
Chris@682 330 cerr << "WARNING: PluginParameterBox::spinBoxChanged: Unknown parameter \"" << identifier << "\"" << endl;
Chris@60 331 return;
Chris@60 332 }
Chris@60 333
Chris@207 334 Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
Chris@60 335
Chris@60 336 float min = params.minValue;
Chris@60 337 float max = params.maxValue;
Chris@60 338
Chris@60 339 float qtz = 0.0;
Chris@60 340 if (params.isQuantized) qtz = params.quantizeStep;
Chris@60 341
Chris@60 342 if (qtz > 0.0) {
Chris@908 343 int step = int(lrintf(float(value - min) / qtz));
Chris@908 344 value = min + float(step) * qtz;
Chris@60 345 }
Chris@60 346
Chris@807 347 // int imax = 100;
Chris@60 348
Chris@60 349 if (qtz > 0.0) {
Chris@807 350 // imax = lrintf((max - min) / qtz);
Chris@60 351 } else {
Chris@908 352 qtz = (max - min) / 100.f;
Chris@60 353 }
Chris@60 354
Chris@908 355 int ival = int(lrintf(float(value - min) / qtz));
Chris@60 356
Chris@207 357 AudioDial *dial = m_params[identifier].dial;
Chris@63 358 if (dial) {
Chris@63 359 dial->blockSignals(true);
Chris@342 360 if (dial->rangeMapper()) {
Chris@342 361 dial->setMappedValue(value);
Chris@342 362 } else {
Chris@342 363 dial->setValue(ival);
Chris@342 364 }
Chris@63 365 dial->blockSignals(false);
Chris@63 366 }
Chris@60 367
Chris@587 368 SVDEBUG << "setting plugin parameter \"" << identifier << "\" to value " << value << endl;
Chris@530 369
Chris@908 370 m_plugin->setParameter(identifier.toStdString(), float(value));
Chris@64 371
Chris@293 372 updateProgramCombo();
Chris@293 373
Chris@71 374 emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
Chris@60 375 }
Chris@60 376
Chris@63 377 void
Chris@63 378 PluginParameterBox::programComboChanged(const QString &newProgram)
Chris@63 379 {
Chris@63 380 m_plugin->selectProgram(newProgram.toStdString());
Chris@60 381
Chris@63 382 for (std::map<QString, ParamRec>::iterator i = m_params.begin();
Chris@63 383 i != m_params.end(); ++i) {
Chris@63 384
Chris@71 385 Vamp::PluginBase::ParameterDescriptor &param = i->second.param;
Chris@207 386 float value = m_plugin->getParameter(param.identifier);
Chris@63 387
Chris@63 388 if (i->second.spin) {
Chris@63 389 i->second.spin->blockSignals(true);
Chris@63 390 i->second.spin->setValue(value);
Chris@63 391 i->second.spin->blockSignals(false);
Chris@63 392 }
Chris@63 393
Chris@63 394 if (i->second.dial) {
Chris@63 395
Chris@63 396 float min = param.minValue;
Chris@63 397 float max = param.maxValue;
Chris@63 398
Chris@63 399 float qtz = 0.0;
Chris@63 400 if (param.isQuantized) qtz = param.quantizeStep;
Chris@63 401
Chris@63 402 if (qtz == 0.0) {
Chris@908 403 qtz = (max - min) / 100.f;
Chris@63 404 }
Chris@63 405
Chris@63 406 i->second.dial->blockSignals(true);
Chris@908 407 i->second.dial->setValue(int(lrintf(float(value - min) / qtz)));
Chris@63 408 i->second.dial->blockSignals(false);
Chris@63 409 }
Chris@74 410
Chris@74 411 if (i->second.combo) {
Chris@74 412 i->second.combo->blockSignals(true);
Chris@908 413 i->second.combo->setCurrentIndex(int(lrintf(value)));
Chris@74 414 i->second.combo->blockSignals(false);
Chris@74 415 }
Chris@293 416
Chris@293 417 if (i->second.check) {
Chris@293 418 i->second.check->blockSignals(true);
Chris@293 419 i->second.check->setCheckState(value < 0.5 ? Qt::Unchecked : Qt::Checked);
Chris@293 420 i->second.check->blockSignals(false);
Chris@293 421 }
Chris@63 422 }
Chris@64 423
Chris@71 424 emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
Chris@63 425 }
Chris@63 426
Chris@293 427 void
Chris@293 428 PluginParameterBox::updateProgramCombo()
Chris@293 429 {
Chris@293 430 if (!m_programCombo || m_programs.empty()) return;
Chris@293 431
Chris@293 432 std::string currentProgram = m_plugin->getCurrentProgram();
Chris@293 433
Chris@908 434 for (int i = 0; in_range_for(m_programs, i); ++i) {
Chris@293 435 if (m_programs[i] == currentProgram) {
Chris@293 436 m_programCombo->setCurrentIndex(i);
Chris@293 437 }
Chris@293 438 }
Chris@293 439 }
Chris@293 440
Chris@293 441