annotate widgets/PluginParameterBox.cpp @ 333:e74b56f07c73

* Some work on correct alignment when moving panes during playback * Overhaul alignment for playback frame values (view manager now always refers to reference-timeline values, only the play source deals in playback model timeline values) * When making a selection, ensure the selection regions shown in other panes (and used for playback constraints if appropriate) are aligned correctly. This may be the coolest feature ever implemented in any program ever.
author Chris Cannam
date Thu, 22 Nov 2007 14:17:19 +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