annotate widgets/PluginParameterBox.cpp @ 1020:69c4f8403ebf colourschemes

Fix integer overflow in getFrameForX
author Chris Cannam
date Fri, 22 Jan 2016 15:16:36 +0000
parents 4a578a360011
children 01778052e663
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@293 40 m_programCombo(0)
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@342 124 } else {
Chris@908 125 qtz = (max - min) / 100.f;
Chris@342 126 }
Chris@60 127 }
Chris@60 128
Chris@60 129 //!!! would be nice to ensure the default value corresponds to
Chris@60 130 // an integer!
Chris@60 131
Chris@207 132 QLabel *label = new QLabel(name);
Chris@208 133 if (params[i].description != "") {
Chris@828 134 label->setToolTip(QString("<qt>%1</qt>")
Chris@828 135 .arg(params[i].description.c_str())
Chris@828 136 .replace("\n", "<br>"));
Chris@208 137 }
Chris@63 138 m_layout->addWidget(label, i + offset, 0);
Chris@60 139
Chris@60 140 ParamRec rec;
Chris@60 141 rec.param = params[i];
Chris@63 142 rec.dial = 0;
Chris@63 143 rec.spin = 0;
Chris@63 144 rec.check = 0;
Chris@74 145 rec.combo = 0;
Chris@63 146
Chris@74 147 if (params[i].isQuantized && !valueNames.empty()) {
Chris@74 148
Chris@74 149 QComboBox *combobox = new QComboBox;
Chris@207 150 combobox->setObjectName(identifier);
Chris@74 151 for (unsigned int j = 0; j < valueNames.size(); ++j) {
Chris@74 152 combobox->addItem(valueNames[j].c_str());
Chris@249 153 if ((unsigned int)(lrintf(fabsf((value - min) / qtz))) == j) {
Chris@74 154 combobox->setCurrentIndex(j);
Chris@74 155 }
Chris@74 156 }
Chris@74 157 connect(combobox, SIGNAL(activated(int)),
Chris@74 158 this, SLOT(dialChanged(int)));
Chris@74 159 m_layout->addWidget(combobox, i + offset, 1, 1, 2);
Chris@74 160 rec.combo = combobox;
Chris@74 161
Chris@74 162 } else if (min == 0.0 && max == 1.0 && qtz == 1.0) {
Chris@63 163
Chris@63 164 QCheckBox *checkbox = new QCheckBox;
Chris@207 165 checkbox->setObjectName(identifier);
Chris@293 166 checkbox->setCheckState(value < 0.5 ? Qt::Unchecked : Qt::Checked);
Chris@63 167 connect(checkbox, SIGNAL(stateChanged(int)),
Chris@63 168 this, SLOT(checkBoxChanged(int)));
Chris@63 169 m_layout->addWidget(checkbox, i + offset, 2);
Chris@63 170 rec.check = checkbox;
Chris@63 171
Chris@63 172 } else {
Chris@63 173
Chris@63 174 AudioDial *dial = new AudioDial;
Chris@207 175 dial->setObjectName(name);
Chris@63 176 dial->setMinimum(imin);
Chris@63 177 dial->setMaximum(imax);
Chris@63 178 dial->setPageStep(1);
Chris@63 179 dial->setNotchesVisible((imax - imin) <= 12);
Chris@342 180 //!!! dial->setDefaultValue(lrintf((deft - min) / qtz));
Chris@342 181 // dial->setValue(lrintf((value - min) / qtz));
Chris@63 182 dial->setFixedWidth(32);
Chris@63 183 dial->setFixedHeight(32);
Chris@342 184 RangeMapper *rm = 0;
Chris@342 185 if (hint & PortHint::Logarithmic) {
Chris@342 186 rm = new LogRangeMapper(imin, imax, min, max, unit);
Chris@342 187 } else {
Chris@342 188 rm = new LinearRangeMapper(imin, imax, min, max, unit);
Chris@342 189 }
Chris@342 190 dial->setRangeMapper(rm);
Chris@342 191 dial->setDefaultValue(rm->getPositionForValue(deft));
Chris@342 192 dial->setValue(rm->getPositionForValue(value));
Chris@168 193 dial->setShowToolTip(true);
Chris@63 194 connect(dial, SIGNAL(valueChanged(int)),
Chris@63 195 this, SLOT(dialChanged(int)));
Chris@63 196 m_layout->addWidget(dial, i + offset, 1);
Chris@63 197
Chris@63 198 QDoubleSpinBox *spinbox = new QDoubleSpinBox;
Chris@207 199 spinbox->setObjectName(identifier);
Chris@63 200 spinbox->setMinimum(min);
Chris@63 201 spinbox->setMaximum(max);
Chris@63 202 spinbox->setSuffix(QString(" %1").arg(unit));
Chris@342 203 if (qtz != 0) spinbox->setSingleStep(qtz);
Chris@63 204 spinbox->setValue(value);
Chris@103 205 spinbox->setDecimals(4);
Chris@63 206 connect(spinbox, SIGNAL(valueChanged(double)),
Chris@63 207 this, SLOT(spinBoxChanged(double)));
Chris@63 208 m_layout->addWidget(spinbox, i + offset, 2);
Chris@63 209 rec.dial = dial;
Chris@63 210 rec.spin = spinbox;
Chris@63 211 }
Chris@63 212
Chris@207 213 m_params[identifier] = rec;
Chris@207 214 m_nameMap[name] = identifier;
Chris@60 215 }
Chris@60 216 }
Chris@60 217
Chris@60 218 void
Chris@60 219 PluginParameterBox::dialChanged(int ival)
Chris@60 220 {
Chris@60 221 QObject *obj = sender();
Chris@207 222 QString identifier = obj->objectName();
Chris@60 223
Chris@207 224 if (m_params.find(identifier) == m_params.end() &&
Chris@207 225 m_nameMap.find(identifier) != m_nameMap.end()) {
Chris@207 226 identifier = m_nameMap[identifier];
Chris@167 227 }
Chris@167 228
Chris@207 229 if (m_params.find(identifier) == m_params.end()) {
Chris@682 230 cerr << "WARNING: PluginParameterBox::dialChanged: Unknown parameter \"" << identifier << "\"" << endl;
Chris@60 231 return;
Chris@60 232 }
Chris@60 233
Chris@207 234 Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
Chris@60 235
Chris@60 236 float min = params.minValue;
Chris@60 237 float max = params.maxValue;
Chris@60 238
Chris@168 239 float newValue;
Chris@168 240
Chris@60 241 float qtz = 0.0;
Chris@60 242 if (params.isQuantized) qtz = params.quantizeStep;
Chris@168 243
Chris@168 244 AudioDial *ad = dynamic_cast<AudioDial *>(obj);
Chris@60 245
Chris@168 246 if (ad && ad->rangeMapper()) {
Chris@168 247
Chris@908 248 newValue = float(ad->mappedValue());
Chris@168 249 if (newValue < min) newValue = min;
Chris@168 250 if (newValue > max) newValue = max;
Chris@168 251 if (qtz != 0.0) {
Chris@908 252 ival = int(lrintf((newValue - min) / qtz));
Chris@908 253 newValue = min + float(ival) * qtz;
Chris@168 254 }
Chris@168 255
Chris@168 256 } else {
Chris@908 257 if (qtz == 0.f) {
Chris@908 258 qtz = (max - min) / 100.f;
Chris@168 259 }
Chris@908 260 newValue = min + float(ival) * qtz;
Chris@60 261 }
Chris@60 262
Chris@587 263 // SVDEBUG << "PluginParameterBox::dialChanged: newValue = " << newValue << endl;
Chris@342 264
Chris@207 265 QDoubleSpinBox *spin = m_params[identifier].spin;
Chris@63 266 if (spin) {
Chris@63 267 spin->blockSignals(true);
Chris@63 268 spin->setValue(newValue);
Chris@63 269 spin->blockSignals(false);
Chris@63 270 }
Chris@60 271
Chris@587 272 // SVDEBUG << "setting plugin parameter \"" << identifier << "\" to value " << newValue << endl;
Chris@530 273
Chris@207 274 m_plugin->setParameter(identifier.toStdString(), newValue);
Chris@64 275
Chris@293 276 updateProgramCombo();
Chris@293 277
Chris@71 278 emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
Chris@60 279 }
Chris@60 280
Chris@60 281 void
Chris@63 282 PluginParameterBox::checkBoxChanged(int state)
Chris@63 283 {
Chris@63 284 QObject *obj = sender();
Chris@207 285 QString identifier = obj->objectName();
Chris@63 286
Chris@207 287 if (m_params.find(identifier) == m_params.end() &&
Chris@207 288 m_nameMap.find(identifier) != m_nameMap.end()) {
Chris@207 289 identifier = m_nameMap[identifier];
Chris@167 290 }
Chris@167 291
Chris@207 292 if (m_params.find(identifier) == m_params.end()) {
Chris@682 293 cerr << "WARNING: PluginParameterBox::checkBoxChanged: Unknown parameter \"" << identifier << "\"" << endl;
Chris@63 294 return;
Chris@63 295 }
Chris@63 296
Chris@207 297 Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
Chris@63 298
Chris@207 299 if (state) m_plugin->setParameter(identifier.toStdString(), 1.0);
Chris@207 300 else m_plugin->setParameter(identifier.toStdString(), 0.0);
Chris@64 301
Chris@293 302 updateProgramCombo();
Chris@293 303
Chris@71 304 emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
Chris@63 305 }
Chris@63 306
Chris@63 307 void
Chris@60 308 PluginParameterBox::spinBoxChanged(double value)
Chris@60 309 {
Chris@60 310 QObject *obj = sender();
Chris@207 311 QString identifier = obj->objectName();
Chris@60 312
Chris@207 313 if (m_params.find(identifier) == m_params.end() &&
Chris@207 314 m_nameMap.find(identifier) != m_nameMap.end()) {
Chris@207 315 identifier = m_nameMap[identifier];
Chris@167 316 }
Chris@167 317
Chris@207 318 if (m_params.find(identifier) == m_params.end()) {
Chris@682 319 cerr << "WARNING: PluginParameterBox::spinBoxChanged: Unknown parameter \"" << identifier << "\"" << endl;
Chris@60 320 return;
Chris@60 321 }
Chris@60 322
Chris@207 323 Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
Chris@60 324
Chris@60 325 float min = params.minValue;
Chris@60 326 float max = params.maxValue;
Chris@60 327
Chris@60 328 float qtz = 0.0;
Chris@60 329 if (params.isQuantized) qtz = params.quantizeStep;
Chris@60 330
Chris@60 331 if (qtz > 0.0) {
Chris@908 332 int step = int(lrintf(float(value - min) / qtz));
Chris@908 333 value = min + float(step) * qtz;
Chris@60 334 }
Chris@60 335
Chris@807 336 // int imax = 100;
Chris@60 337
Chris@60 338 if (qtz > 0.0) {
Chris@807 339 // imax = lrintf((max - min) / qtz);
Chris@60 340 } else {
Chris@908 341 qtz = (max - min) / 100.f;
Chris@60 342 }
Chris@60 343
Chris@908 344 int ival = int(lrintf(float(value - min) / qtz));
Chris@60 345
Chris@207 346 AudioDial *dial = m_params[identifier].dial;
Chris@63 347 if (dial) {
Chris@63 348 dial->blockSignals(true);
Chris@342 349 if (dial->rangeMapper()) {
Chris@342 350 dial->setMappedValue(value);
Chris@342 351 } else {
Chris@342 352 dial->setValue(ival);
Chris@342 353 }
Chris@63 354 dial->blockSignals(false);
Chris@63 355 }
Chris@60 356
Chris@587 357 SVDEBUG << "setting plugin parameter \"" << identifier << "\" to value " << value << endl;
Chris@530 358
Chris@908 359 m_plugin->setParameter(identifier.toStdString(), float(value));
Chris@64 360
Chris@293 361 updateProgramCombo();
Chris@293 362
Chris@71 363 emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
Chris@60 364 }
Chris@60 365
Chris@63 366 void
Chris@63 367 PluginParameterBox::programComboChanged(const QString &newProgram)
Chris@63 368 {
Chris@63 369 m_plugin->selectProgram(newProgram.toStdString());
Chris@60 370
Chris@63 371 for (std::map<QString, ParamRec>::iterator i = m_params.begin();
Chris@63 372 i != m_params.end(); ++i) {
Chris@63 373
Chris@71 374 Vamp::PluginBase::ParameterDescriptor &param = i->second.param;
Chris@207 375 float value = m_plugin->getParameter(param.identifier);
Chris@63 376
Chris@63 377 if (i->second.spin) {
Chris@63 378 i->second.spin->blockSignals(true);
Chris@63 379 i->second.spin->setValue(value);
Chris@63 380 i->second.spin->blockSignals(false);
Chris@63 381 }
Chris@63 382
Chris@63 383 if (i->second.dial) {
Chris@63 384
Chris@63 385 float min = param.minValue;
Chris@63 386 float max = param.maxValue;
Chris@63 387
Chris@63 388 float qtz = 0.0;
Chris@63 389 if (param.isQuantized) qtz = param.quantizeStep;
Chris@63 390
Chris@63 391 if (qtz == 0.0) {
Chris@908 392 qtz = (max - min) / 100.f;
Chris@63 393 }
Chris@63 394
Chris@63 395 i->second.dial->blockSignals(true);
Chris@908 396 i->second.dial->setValue(int(lrintf(float(value - min) / qtz)));
Chris@63 397 i->second.dial->blockSignals(false);
Chris@63 398 }
Chris@74 399
Chris@74 400 if (i->second.combo) {
Chris@74 401 i->second.combo->blockSignals(true);
Chris@908 402 i->second.combo->setCurrentIndex(int(lrintf(value)));
Chris@74 403 i->second.combo->blockSignals(false);
Chris@74 404 }
Chris@293 405
Chris@293 406 if (i->second.check) {
Chris@293 407 i->second.check->blockSignals(true);
Chris@293 408 i->second.check->setCheckState(value < 0.5 ? Qt::Unchecked : Qt::Checked);
Chris@293 409 i->second.check->blockSignals(false);
Chris@293 410 }
Chris@63 411 }
Chris@64 412
Chris@71 413 emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
Chris@63 414 }
Chris@63 415
Chris@293 416 void
Chris@293 417 PluginParameterBox::updateProgramCombo()
Chris@293 418 {
Chris@293 419 if (!m_programCombo || m_programs.empty()) return;
Chris@293 420
Chris@293 421 std::string currentProgram = m_plugin->getCurrentProgram();
Chris@293 422
Chris@908 423 for (int i = 0; in_range_for(m_programs, i); ++i) {
Chris@293 424 if (m_programs[i] == currentProgram) {
Chris@293 425 m_programCombo->setCurrentIndex(i);
Chris@293 426 }
Chris@293 427 }
Chris@293 428 }
Chris@293 429
Chris@293 430