annotate widgets/PluginParameterBox.cpp @ 1605:ae2d5f8ff005

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