annotate widgets/PluginParameterBox.cpp @ 309:b7d45fed8146

* fix misbehaving apply-to-selection-only checkbox, fix default step size for frequency domain plugins
author Chris Cannam
date Tue, 09 Oct 2007 16:21:59 +0000
parents 15b8a4bfe855
children a904364dfb6e
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@71 21
Chris@167 22 #include "base/RangeMapper.h"
Chris@167 23
Chris@60 24 #include <QDoubleSpinBox>
Chris@60 25 #include <QGridLayout>
Chris@63 26 #include <QComboBox>
Chris@63 27 #include <QCheckBox>
Chris@60 28 #include <QLayout>
Chris@60 29 #include <QLabel>
Chris@60 30
Chris@60 31 #include <iostream>
Chris@60 32 #include <string>
Chris@60 33
Chris@78 34 #include <cmath>
Chris@78 35
Chris@71 36 PluginParameterBox::PluginParameterBox(Vamp::PluginBase *plugin, QWidget *parent) :
Chris@62 37 QFrame(parent),
Chris@293 38 m_plugin(plugin),
Chris@293 39 m_programCombo(0)
Chris@60 40 {
Chris@60 41 m_layout = new QGridLayout;
Chris@60 42 setLayout(m_layout);
Chris@60 43 populate();
Chris@60 44 }
Chris@60 45
Chris@60 46 PluginParameterBox::~PluginParameterBox()
Chris@60 47 {
Chris@60 48 }
Chris@60 49
Chris@60 50 void
Chris@60 51 PluginParameterBox::populate()
Chris@60 52 {
Chris@71 53 Vamp::PluginBase::ParameterList params = m_plugin->getParameterDescriptors();
Chris@293 54 m_programs = m_plugin->getPrograms();
Chris@60 55
Chris@60 56 m_params.clear();
Chris@60 57
Chris@293 58 if (params.empty() && m_programs.empty()) {
Chris@62 59 m_layout->addWidget
Chris@62 60 (new QLabel(tr("This plugin has no adjustable parameters.")),
Chris@62 61 0, 0);
Chris@62 62 }
Chris@62 63
Chris@63 64 int offset = 0;
Chris@63 65
Chris@293 66 if (!m_programs.empty()) {
Chris@63 67
Chris@63 68 std::string currentProgram = m_plugin->getCurrentProgram();
Chris@63 69
Chris@293 70 m_programCombo = new QComboBox;
Chris@293 71 m_programCombo->setMaxVisibleItems
Chris@293 72 (m_programs.size() < 25 ? m_programs.size() : 20);
Chris@63 73
Chris@293 74 for (size_t i = 0; i < m_programs.size(); ++i) {
Chris@293 75 m_programCombo->addItem(m_programs[i].c_str());
Chris@293 76 if (m_programs[i] == currentProgram) {
Chris@293 77 m_programCombo->setCurrentIndex(i);
Chris@63 78 }
Chris@63 79 }
Chris@63 80
Chris@63 81 m_layout->addWidget(new QLabel(tr("Program")), 0, 0);
Chris@293 82 m_layout->addWidget(m_programCombo, 0, 1, 1, 2);
Chris@63 83
Chris@293 84 connect(m_programCombo, SIGNAL(currentIndexChanged(const QString &)),
Chris@63 85 this, SLOT(programComboChanged(const QString &)));
Chris@63 86
Chris@63 87 offset = 1;
Chris@63 88 }
Chris@63 89
Chris@60 90 for (size_t i = 0; i < params.size(); ++i) {
Chris@60 91
Chris@207 92 QString identifier = params[i].identifier.c_str();
Chris@60 93 QString name = params[i].name.c_str();
Chris@60 94 QString unit = params[i].unit.c_str();
Chris@60 95
Chris@60 96 float min = params[i].minValue;
Chris@60 97 float max = params[i].maxValue;
Chris@60 98 float deft = params[i].defaultValue;
Chris@207 99 float value = m_plugin->getParameter(params[i].identifier);
Chris@60 100
Chris@60 101 float qtz = 0.0;
Chris@60 102 if (params[i].isQuantized) qtz = params[i].quantizeStep;
Chris@60 103
Chris@74 104 std::vector<std::string> valueNames = params[i].valueNames;
Chris@74 105
Chris@60 106 // construct an integer range
Chris@60 107
Chris@60 108 int imin = 0, imax = 100;
Chris@60 109
Chris@60 110 if (qtz > 0.0) {
Chris@60 111 imax = int((max - min) / qtz);
Chris@60 112 } else {
Chris@60 113 qtz = (max - min) / 100.0;
Chris@60 114 }
Chris@60 115
Chris@60 116 //!!! would be nice to ensure the default value corresponds to
Chris@60 117 // an integer!
Chris@60 118
Chris@207 119 QLabel *label = new QLabel(name);
Chris@208 120 if (params[i].description != "") {
Chris@208 121 label->setToolTip(params[i].description.c_str());
Chris@208 122 }
Chris@63 123 m_layout->addWidget(label, i + offset, 0);
Chris@60 124
Chris@60 125 ParamRec rec;
Chris@60 126 rec.param = params[i];
Chris@63 127 rec.dial = 0;
Chris@63 128 rec.spin = 0;
Chris@63 129 rec.check = 0;
Chris@74 130 rec.combo = 0;
Chris@63 131
Chris@74 132 if (params[i].isQuantized && !valueNames.empty()) {
Chris@74 133
Chris@74 134 QComboBox *combobox = new QComboBox;
Chris@207 135 combobox->setObjectName(identifier);
Chris@74 136 for (unsigned int j = 0; j < valueNames.size(); ++j) {
Chris@74 137 combobox->addItem(valueNames[j].c_str());
Chris@249 138 if ((unsigned int)(lrintf(fabsf((value - min) / qtz))) == j) {
Chris@74 139 combobox->setCurrentIndex(j);
Chris@74 140 }
Chris@74 141 }
Chris@74 142 connect(combobox, SIGNAL(activated(int)),
Chris@74 143 this, SLOT(dialChanged(int)));
Chris@74 144 m_layout->addWidget(combobox, i + offset, 1, 1, 2);
Chris@74 145 rec.combo = combobox;
Chris@74 146
Chris@74 147 } else if (min == 0.0 && max == 1.0 && qtz == 1.0) {
Chris@63 148
Chris@63 149 QCheckBox *checkbox = new QCheckBox;
Chris@207 150 checkbox->setObjectName(identifier);
Chris@293 151 checkbox->setCheckState(value < 0.5 ? Qt::Unchecked : Qt::Checked);
Chris@63 152 connect(checkbox, SIGNAL(stateChanged(int)),
Chris@63 153 this, SLOT(checkBoxChanged(int)));
Chris@63 154 m_layout->addWidget(checkbox, i + offset, 2);
Chris@63 155 rec.check = checkbox;
Chris@63 156
Chris@63 157 } else {
Chris@63 158
Chris@63 159 AudioDial *dial = new AudioDial;
Chris@207 160 dial->setObjectName(name);
Chris@63 161 dial->setMinimum(imin);
Chris@63 162 dial->setMaximum(imax);
Chris@63 163 dial->setPageStep(1);
Chris@63 164 dial->setNotchesVisible((imax - imin) <= 12);
Chris@74 165 dial->setDefaultValue(lrintf((deft - min) / qtz));
Chris@74 166 dial->setValue(lrintf((value - min) / qtz));
Chris@63 167 dial->setFixedWidth(32);
Chris@63 168 dial->setFixedHeight(32);
Chris@167 169 dial->setRangeMapper(new LinearRangeMapper
Chris@167 170 (imin, imax, min, max, unit));
Chris@168 171 dial->setShowToolTip(true);
Chris@63 172 connect(dial, SIGNAL(valueChanged(int)),
Chris@63 173 this, SLOT(dialChanged(int)));
Chris@63 174 m_layout->addWidget(dial, i + offset, 1);
Chris@63 175
Chris@63 176 QDoubleSpinBox *spinbox = new QDoubleSpinBox;
Chris@207 177 spinbox->setObjectName(identifier);
Chris@63 178 spinbox->setMinimum(min);
Chris@63 179 spinbox->setMaximum(max);
Chris@63 180 spinbox->setSuffix(QString(" %1").arg(unit));
Chris@63 181 spinbox->setSingleStep(qtz);
Chris@63 182 spinbox->setValue(value);
Chris@103 183 spinbox->setDecimals(4);
Chris@63 184 connect(spinbox, SIGNAL(valueChanged(double)),
Chris@63 185 this, SLOT(spinBoxChanged(double)));
Chris@63 186 m_layout->addWidget(spinbox, i + offset, 2);
Chris@63 187 rec.dial = dial;
Chris@63 188 rec.spin = spinbox;
Chris@63 189 }
Chris@63 190
Chris@207 191 m_params[identifier] = rec;
Chris@207 192 m_nameMap[name] = identifier;
Chris@60 193 }
Chris@60 194 }
Chris@60 195
Chris@60 196 void
Chris@60 197 PluginParameterBox::dialChanged(int ival)
Chris@60 198 {
Chris@60 199 QObject *obj = sender();
Chris@207 200 QString identifier = obj->objectName();
Chris@60 201
Chris@207 202 if (m_params.find(identifier) == m_params.end() &&
Chris@207 203 m_nameMap.find(identifier) != m_nameMap.end()) {
Chris@207 204 identifier = m_nameMap[identifier];
Chris@167 205 }
Chris@167 206
Chris@207 207 if (m_params.find(identifier) == m_params.end()) {
Chris@207 208 std::cerr << "WARNING: PluginParameterBox::dialChanged: Unknown parameter \"" << identifier.toStdString() << "\"" << std::endl;
Chris@60 209 return;
Chris@60 210 }
Chris@60 211
Chris@207 212 Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
Chris@60 213
Chris@60 214 float min = params.minValue;
Chris@60 215 float max = params.maxValue;
Chris@60 216
Chris@168 217 float newValue;
Chris@168 218
Chris@60 219 float qtz = 0.0;
Chris@60 220 if (params.isQuantized) qtz = params.quantizeStep;
Chris@168 221
Chris@168 222 AudioDial *ad = dynamic_cast<AudioDial *>(obj);
Chris@60 223
Chris@168 224 if (ad && ad->rangeMapper()) {
Chris@168 225
Chris@168 226 newValue = ad->mappedValue();
Chris@168 227 if (newValue < min) newValue = min;
Chris@168 228 if (newValue > max) newValue = max;
Chris@168 229 if (qtz != 0.0) {
Chris@168 230 ival = lrintf((newValue - min) / qtz);
Chris@168 231 newValue = min + ival * qtz;
Chris@168 232 }
Chris@168 233
Chris@168 234 } else {
Chris@168 235 if (qtz == 0.0) {
Chris@168 236 qtz = (max - min) / 100.0;
Chris@168 237 }
Chris@168 238 newValue = min + ival * qtz;
Chris@60 239 }
Chris@60 240
Chris@207 241 QDoubleSpinBox *spin = m_params[identifier].spin;
Chris@63 242 if (spin) {
Chris@63 243 spin->blockSignals(true);
Chris@63 244 spin->setValue(newValue);
Chris@63 245 spin->blockSignals(false);
Chris@63 246 }
Chris@60 247
Chris@207 248 m_plugin->setParameter(identifier.toStdString(), newValue);
Chris@64 249
Chris@293 250 updateProgramCombo();
Chris@293 251
Chris@71 252 emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
Chris@60 253 }
Chris@60 254
Chris@60 255 void
Chris@63 256 PluginParameterBox::checkBoxChanged(int state)
Chris@63 257 {
Chris@63 258 QObject *obj = sender();
Chris@207 259 QString identifier = obj->objectName();
Chris@63 260
Chris@207 261 if (m_params.find(identifier) == m_params.end() &&
Chris@207 262 m_nameMap.find(identifier) != m_nameMap.end()) {
Chris@207 263 identifier = m_nameMap[identifier];
Chris@167 264 }
Chris@167 265
Chris@207 266 if (m_params.find(identifier) == m_params.end()) {
Chris@207 267 std::cerr << "WARNING: PluginParameterBox::checkBoxChanged: Unknown parameter \"" << identifier.toStdString() << "\"" << std::endl;
Chris@63 268 return;
Chris@63 269 }
Chris@63 270
Chris@207 271 Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
Chris@63 272
Chris@207 273 if (state) m_plugin->setParameter(identifier.toStdString(), 1.0);
Chris@207 274 else m_plugin->setParameter(identifier.toStdString(), 0.0);
Chris@64 275
Chris@293 276 updateProgramCombo();
Chris@293 277
Chris@71 278 emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
Chris@63 279 }
Chris@63 280
Chris@63 281 void
Chris@60 282 PluginParameterBox::spinBoxChanged(double value)
Chris@60 283 {
Chris@60 284 QObject *obj = sender();
Chris@207 285 QString identifier = obj->objectName();
Chris@60 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@207 293 std::cerr << "WARNING: PluginParameterBox::spinBoxChanged: Unknown parameter \"" << identifier.toStdString() << "\"" << std::endl;
Chris@60 294 return;
Chris@60 295 }
Chris@60 296
Chris@207 297 Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
Chris@60 298
Chris@60 299 float min = params.minValue;
Chris@60 300 float max = params.maxValue;
Chris@60 301
Chris@60 302 float qtz = 0.0;
Chris@60 303 if (params.isQuantized) qtz = params.quantizeStep;
Chris@60 304
Chris@60 305 if (qtz > 0.0) {
Chris@60 306 int step = int((value - min) / qtz);
Chris@60 307 value = min + step * qtz;
Chris@60 308 }
Chris@60 309
Chris@249 310 int imax = 100;
Chris@60 311
Chris@60 312 if (qtz > 0.0) {
Chris@60 313 imax = int((max - min) / qtz);
Chris@60 314 } else {
Chris@60 315 qtz = (max - min) / 100.0;
Chris@60 316 }
Chris@60 317
Chris@249 318 int ival = lrintf((value - min) / qtz);
Chris@60 319
Chris@207 320 AudioDial *dial = m_params[identifier].dial;
Chris@63 321 if (dial) {
Chris@63 322 dial->blockSignals(true);
Chris@63 323 dial->setValue(ival);
Chris@63 324 dial->blockSignals(false);
Chris@63 325 }
Chris@60 326
Chris@207 327 m_plugin->setParameter(identifier.toStdString(), value);
Chris@64 328
Chris@293 329 updateProgramCombo();
Chris@293 330
Chris@71 331 emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
Chris@60 332 }
Chris@60 333
Chris@63 334 void
Chris@63 335 PluginParameterBox::programComboChanged(const QString &newProgram)
Chris@63 336 {
Chris@63 337 m_plugin->selectProgram(newProgram.toStdString());
Chris@60 338
Chris@63 339 for (std::map<QString, ParamRec>::iterator i = m_params.begin();
Chris@63 340 i != m_params.end(); ++i) {
Chris@63 341
Chris@71 342 Vamp::PluginBase::ParameterDescriptor &param = i->second.param;
Chris@207 343 float value = m_plugin->getParameter(param.identifier);
Chris@63 344
Chris@63 345 if (i->second.spin) {
Chris@63 346 i->second.spin->blockSignals(true);
Chris@63 347 i->second.spin->setValue(value);
Chris@63 348 i->second.spin->blockSignals(false);
Chris@63 349 }
Chris@63 350
Chris@63 351 if (i->second.dial) {
Chris@63 352
Chris@63 353 float min = param.minValue;
Chris@63 354 float max = param.maxValue;
Chris@63 355
Chris@63 356 float qtz = 0.0;
Chris@63 357 if (param.isQuantized) qtz = param.quantizeStep;
Chris@63 358
Chris@63 359 if (qtz == 0.0) {
Chris@63 360 qtz = (max - min) / 100.0;
Chris@63 361 }
Chris@63 362
Chris@63 363 i->second.dial->blockSignals(true);
Chris@74 364 i->second.dial->setValue(lrintf((value - min) / qtz));
Chris@63 365 i->second.dial->blockSignals(false);
Chris@63 366 }
Chris@74 367
Chris@74 368 if (i->second.combo) {
Chris@74 369 i->second.combo->blockSignals(true);
Chris@249 370 i->second.combo->setCurrentIndex(lrintf(value));
Chris@74 371 i->second.combo->blockSignals(false);
Chris@74 372 }
Chris@293 373
Chris@293 374 if (i->second.check) {
Chris@293 375 i->second.check->blockSignals(true);
Chris@293 376 i->second.check->setCheckState(value < 0.5 ? Qt::Unchecked : Qt::Checked);
Chris@293 377 i->second.check->blockSignals(false);
Chris@293 378 }
Chris@63 379 }
Chris@64 380
Chris@71 381 emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
Chris@63 382 }
Chris@63 383
Chris@293 384 void
Chris@293 385 PluginParameterBox::updateProgramCombo()
Chris@293 386 {
Chris@293 387 if (!m_programCombo || m_programs.empty()) return;
Chris@293 388
Chris@293 389 std::string currentProgram = m_plugin->getCurrentProgram();
Chris@293 390
Chris@293 391 for (size_t i = 0; i < m_programs.size(); ++i) {
Chris@293 392 if (m_programs[i] == currentProgram) {
Chris@293 393 m_programCombo->setCurrentIndex(i);
Chris@293 394 }
Chris@293 395 }
Chris@293 396 }
Chris@293 397
Chris@293 398