lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: This file copyright 2006 Chris Cannam and QMUL. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@0: lbajardsilogic@0: #include "PluginParameterBox.h" lbajardsilogic@0: lbajardsilogic@0: #include "AudioDial.h" lbajardsilogic@0: lbajardsilogic@0: #include "plugin/PluginXml.h" lbajardsilogic@0: lbajardsilogic@0: #include "base/RangeMapper.h" lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@0: PluginParameterBox::PluginParameterBox(Vamp::PluginBase *plugin, QWidget *parent) : lbajardsilogic@0: QFrame(parent), lbajardsilogic@0: m_plugin(plugin) lbajardsilogic@0: { lbajardsilogic@0: m_layout = new QGridLayout; lbajardsilogic@0: setLayout(m_layout); lbajardsilogic@0: populate(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: PluginParameterBox::~PluginParameterBox() lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: PluginParameterBox::populate() lbajardsilogic@0: { lbajardsilogic@0: Vamp::PluginBase::ParameterList params = m_plugin->getParameterDescriptors(); lbajardsilogic@0: Vamp::PluginBase::ProgramList programs = m_plugin->getPrograms(); lbajardsilogic@0: lbajardsilogic@0: m_params.clear(); lbajardsilogic@0: lbajardsilogic@0: if (params.empty() && programs.empty()) { lbajardsilogic@0: m_layout->addWidget lbajardsilogic@0: (new QLabel(tr("This plugin has no adjustable parameters.")), lbajardsilogic@0: 0, 0); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int offset = 0; lbajardsilogic@0: lbajardsilogic@0: if (!programs.empty()) { lbajardsilogic@0: lbajardsilogic@0: std::string currentProgram = m_plugin->getCurrentProgram(); lbajardsilogic@0: lbajardsilogic@0: QComboBox *programCombo = new QComboBox; lbajardsilogic@0: programCombo->setMaxVisibleItems(20); lbajardsilogic@0: lbajardsilogic@0: for (size_t i = 0; i < programs.size(); ++i) { lbajardsilogic@0: programCombo->addItem(programs[i].c_str()); lbajardsilogic@0: if (programs[i] == currentProgram) { lbajardsilogic@0: programCombo->setCurrentIndex(i); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_layout->addWidget(new QLabel(tr("Program")), 0, 0); lbajardsilogic@0: m_layout->addWidget(programCombo, 0, 1, 1, 2); lbajardsilogic@0: lbajardsilogic@0: connect(programCombo, SIGNAL(currentIndexChanged(const QString &)), lbajardsilogic@0: this, SLOT(programComboChanged(const QString &))); lbajardsilogic@0: lbajardsilogic@0: offset = 1; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: for (size_t i = 0; i < params.size(); ++i) { lbajardsilogic@0: lbajardsilogic@0: QString identifier = params[i].identifier.c_str(); lbajardsilogic@0: QString name = params[i].name.c_str(); lbajardsilogic@0: QString unit = params[i].unit.c_str(); lbajardsilogic@0: lbajardsilogic@0: float min = params[i].minValue; lbajardsilogic@0: float max = params[i].maxValue; lbajardsilogic@0: float deft = params[i].defaultValue; lbajardsilogic@0: float value = m_plugin->getParameter(params[i].identifier); lbajardsilogic@0: lbajardsilogic@0: float qtz = 0.0; lbajardsilogic@0: if (params[i].isQuantized) qtz = params[i].quantizeStep; lbajardsilogic@0: lbajardsilogic@0: std::vector valueNames = params[i].valueNames; lbajardsilogic@0: lbajardsilogic@0: // construct an integer range lbajardsilogic@0: lbajardsilogic@0: int imin = 0, imax = 100; lbajardsilogic@0: lbajardsilogic@0: if (qtz > 0.0) { lbajardsilogic@0: imax = int((max - min) / qtz); lbajardsilogic@0: } else { lbajardsilogic@0: qtz = (max - min) / 100.0; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: //!!! would be nice to ensure the default value corresponds to lbajardsilogic@0: // an integer! lbajardsilogic@0: lbajardsilogic@0: QLabel *label = new QLabel(name); lbajardsilogic@0: if (params[i].description != "") { lbajardsilogic@0: label->setToolTip(params[i].description.c_str()); lbajardsilogic@0: } lbajardsilogic@0: m_layout->addWidget(label, i + offset, 0); lbajardsilogic@0: lbajardsilogic@0: ParamRec rec; lbajardsilogic@0: rec.param = params[i]; lbajardsilogic@0: rec.dial = 0; lbajardsilogic@0: rec.spin = 0; lbajardsilogic@0: rec.check = 0; lbajardsilogic@0: rec.combo = 0; lbajardsilogic@0: lbajardsilogic@0: if (params[i].isQuantized && !valueNames.empty()) { lbajardsilogic@0: lbajardsilogic@0: QComboBox *combobox = new QComboBox; lbajardsilogic@0: combobox->setObjectName(identifier); lbajardsilogic@0: for (unsigned int j = 0; j < valueNames.size(); ++j) { lbajardsilogic@0: combobox->addItem(valueNames[j].c_str()); lbajardsilogic@0: if ((unsigned int)(lrintf(fabsf((value - min) / qtz))) == j) { lbajardsilogic@0: combobox->setCurrentIndex(j); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: connect(combobox, SIGNAL(activated(int)), lbajardsilogic@0: this, SLOT(dialChanged(int))); lbajardsilogic@0: m_layout->addWidget(combobox, i + offset, 1, 1, 2); lbajardsilogic@0: rec.combo = combobox; lbajardsilogic@0: lbajardsilogic@0: } else if (min == 0.0 && max == 1.0 && qtz == 1.0) { lbajardsilogic@0: lbajardsilogic@0: QCheckBox *checkbox = new QCheckBox; lbajardsilogic@0: checkbox->setObjectName(identifier); lbajardsilogic@0: checkbox->setCheckState(value == 0.0 ? Qt::Unchecked : Qt::Checked); lbajardsilogic@0: connect(checkbox, SIGNAL(stateChanged(int)), lbajardsilogic@0: this, SLOT(checkBoxChanged(int))); lbajardsilogic@0: m_layout->addWidget(checkbox, i + offset, 2); lbajardsilogic@0: rec.check = checkbox; lbajardsilogic@0: lbajardsilogic@0: } else { lbajardsilogic@0: lbajardsilogic@0: AudioDial *dial = new AudioDial; lbajardsilogic@0: dial->setObjectName(name); lbajardsilogic@0: dial->setMinimum(imin); lbajardsilogic@0: dial->setMaximum(imax); lbajardsilogic@0: dial->setPageStep(1); lbajardsilogic@0: dial->setNotchesVisible((imax - imin) <= 12); lbajardsilogic@0: dial->setDefaultValue(lrintf((deft - min) / qtz)); lbajardsilogic@0: dial->setValue(lrintf((value - min) / qtz)); lbajardsilogic@0: dial->setFixedWidth(32); lbajardsilogic@0: dial->setFixedHeight(32); lbajardsilogic@0: dial->setRangeMapper(new LinearRangeMapper lbajardsilogic@0: (imin, imax, min, max, unit)); lbajardsilogic@0: dial->setShowToolTip(true); lbajardsilogic@0: connect(dial, SIGNAL(valueChanged(int)), lbajardsilogic@0: this, SLOT(dialChanged(int))); lbajardsilogic@0: m_layout->addWidget(dial, i + offset, 1); lbajardsilogic@0: lbajardsilogic@0: QDoubleSpinBox *spinbox = new QDoubleSpinBox; lbajardsilogic@0: spinbox->setObjectName(identifier); lbajardsilogic@0: spinbox->setMinimum(min); lbajardsilogic@0: spinbox->setMaximum(max); lbajardsilogic@0: spinbox->setSuffix(QString(" %1").arg(unit)); lbajardsilogic@0: spinbox->setSingleStep(qtz); lbajardsilogic@0: spinbox->setValue(value); lbajardsilogic@0: spinbox->setDecimals(4); lbajardsilogic@0: connect(spinbox, SIGNAL(valueChanged(double)), lbajardsilogic@0: this, SLOT(spinBoxChanged(double))); lbajardsilogic@0: m_layout->addWidget(spinbox, i + offset, 2); lbajardsilogic@0: rec.dial = dial; lbajardsilogic@0: rec.spin = spinbox; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_params[identifier] = rec; lbajardsilogic@0: m_nameMap[name] = identifier; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: PluginParameterBox::dialChanged(int ival) lbajardsilogic@0: { lbajardsilogic@0: QObject *obj = sender(); lbajardsilogic@0: QString identifier = obj->objectName(); lbajardsilogic@0: lbajardsilogic@0: if (m_params.find(identifier) == m_params.end() && lbajardsilogic@0: m_nameMap.find(identifier) != m_nameMap.end()) { lbajardsilogic@0: identifier = m_nameMap[identifier]; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_params.find(identifier) == m_params.end()) { lbajardsilogic@0: std::cerr << "WARNING: PluginParameterBox::dialChanged: Unknown parameter \"" << identifier.toStdString() << "\"" << std::endl; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param; lbajardsilogic@0: lbajardsilogic@0: float min = params.minValue; lbajardsilogic@0: float max = params.maxValue; lbajardsilogic@0: lbajardsilogic@0: float newValue; lbajardsilogic@0: lbajardsilogic@0: float qtz = 0.0; lbajardsilogic@0: if (params.isQuantized) qtz = params.quantizeStep; lbajardsilogic@0: lbajardsilogic@0: AudioDial *ad = dynamic_cast(obj); lbajardsilogic@0: lbajardsilogic@0: if (ad && ad->rangeMapper()) { lbajardsilogic@0: lbajardsilogic@0: newValue = ad->mappedValue(); lbajardsilogic@0: if (newValue < min) newValue = min; lbajardsilogic@0: if (newValue > max) newValue = max; lbajardsilogic@0: if (qtz != 0.0) { lbajardsilogic@0: ival = lrintf((newValue - min) / qtz); lbajardsilogic@0: newValue = min + ival * qtz; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: } else { lbajardsilogic@0: if (qtz == 0.0) { lbajardsilogic@0: qtz = (max - min) / 100.0; lbajardsilogic@0: } lbajardsilogic@0: newValue = min + ival * qtz; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QDoubleSpinBox *spin = m_params[identifier].spin; lbajardsilogic@0: if (spin) { lbajardsilogic@0: spin->blockSignals(true); lbajardsilogic@0: spin->setValue(newValue); lbajardsilogic@0: spin->blockSignals(false); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_plugin->setParameter(identifier.toStdString(), newValue); lbajardsilogic@0: lbajardsilogic@0: emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString()); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: PluginParameterBox::checkBoxChanged(int state) lbajardsilogic@0: { lbajardsilogic@0: QObject *obj = sender(); lbajardsilogic@0: QString identifier = obj->objectName(); lbajardsilogic@0: lbajardsilogic@0: if (m_params.find(identifier) == m_params.end() && lbajardsilogic@0: m_nameMap.find(identifier) != m_nameMap.end()) { lbajardsilogic@0: identifier = m_nameMap[identifier]; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_params.find(identifier) == m_params.end()) { lbajardsilogic@0: std::cerr << "WARNING: PluginParameterBox::checkBoxChanged: Unknown parameter \"" << identifier.toStdString() << "\"" << std::endl; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param; lbajardsilogic@0: lbajardsilogic@0: if (state) m_plugin->setParameter(identifier.toStdString(), 1.0); lbajardsilogic@0: else m_plugin->setParameter(identifier.toStdString(), 0.0); lbajardsilogic@0: lbajardsilogic@0: emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString()); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: PluginParameterBox::spinBoxChanged(double value) lbajardsilogic@0: { lbajardsilogic@0: QObject *obj = sender(); lbajardsilogic@0: QString identifier = obj->objectName(); lbajardsilogic@0: lbajardsilogic@0: if (m_params.find(identifier) == m_params.end() && lbajardsilogic@0: m_nameMap.find(identifier) != m_nameMap.end()) { lbajardsilogic@0: identifier = m_nameMap[identifier]; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (m_params.find(identifier) == m_params.end()) { lbajardsilogic@0: std::cerr << "WARNING: PluginParameterBox::spinBoxChanged: Unknown parameter \"" << identifier.toStdString() << "\"" << std::endl; lbajardsilogic@0: return; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param; lbajardsilogic@0: lbajardsilogic@0: float min = params.minValue; lbajardsilogic@0: float max = params.maxValue; lbajardsilogic@0: lbajardsilogic@0: float qtz = 0.0; lbajardsilogic@0: if (params.isQuantized) qtz = params.quantizeStep; lbajardsilogic@0: lbajardsilogic@0: if (qtz > 0.0) { lbajardsilogic@0: int step = int((value - min) / qtz); lbajardsilogic@0: value = min + step * qtz; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int imax = 100; lbajardsilogic@0: lbajardsilogic@0: if (qtz > 0.0) { lbajardsilogic@0: imax = int((max - min) / qtz); lbajardsilogic@0: } else { lbajardsilogic@0: qtz = (max - min) / 100.0; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: int ival = lrintf((value - min) / qtz); lbajardsilogic@0: lbajardsilogic@0: AudioDial *dial = m_params[identifier].dial; lbajardsilogic@0: if (dial) { lbajardsilogic@0: dial->blockSignals(true); lbajardsilogic@0: dial->setValue(ival); lbajardsilogic@0: dial->blockSignals(false); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: m_plugin->setParameter(identifier.toStdString(), value); lbajardsilogic@0: lbajardsilogic@0: emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString()); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: PluginParameterBox::programComboChanged(const QString &newProgram) lbajardsilogic@0: { lbajardsilogic@0: m_plugin->selectProgram(newProgram.toStdString()); lbajardsilogic@0: lbajardsilogic@0: for (std::map::iterator i = m_params.begin(); lbajardsilogic@0: i != m_params.end(); ++i) { lbajardsilogic@0: lbajardsilogic@0: Vamp::PluginBase::ParameterDescriptor ¶m = i->second.param; lbajardsilogic@0: float value = m_plugin->getParameter(param.identifier); lbajardsilogic@0: lbajardsilogic@0: if (i->second.spin) { lbajardsilogic@0: i->second.spin->blockSignals(true); lbajardsilogic@0: i->second.spin->setValue(value); lbajardsilogic@0: i->second.spin->blockSignals(false); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (i->second.dial) { lbajardsilogic@0: lbajardsilogic@0: float min = param.minValue; lbajardsilogic@0: float max = param.maxValue; lbajardsilogic@0: lbajardsilogic@0: float qtz = 0.0; lbajardsilogic@0: if (param.isQuantized) qtz = param.quantizeStep; lbajardsilogic@0: lbajardsilogic@0: if (qtz == 0.0) { lbajardsilogic@0: qtz = (max - min) / 100.0; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: i->second.dial->blockSignals(true); lbajardsilogic@0: i->second.dial->setValue(lrintf((value - min) / qtz)); lbajardsilogic@0: i->second.dial->blockSignals(false); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (i->second.combo) { lbajardsilogic@0: i->second.combo->blockSignals(true); lbajardsilogic@0: i->second.combo->setCurrentIndex(lrintf(value)); lbajardsilogic@0: i->second.combo->blockSignals(false); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString()); lbajardsilogic@0: } lbajardsilogic@0: