annotate widgets/PluginParameterBox.cpp @ 349:369a197737c7

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