svgui  1.9
PluginParameterBox.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "PluginParameterBox.h"
00017 
00018 #include "AudioDial.h"
00019 
00020 #include "plugin/PluginXml.h"
00021 #include "plugin/RealTimePluginInstance.h" // for PortHint stuff
00022 
00023 #include "base/RangeMapper.h"
00024 
00025 #include <QDoubleSpinBox>
00026 #include <QGridLayout>
00027 #include <QComboBox>
00028 #include <QCheckBox>
00029 #include <QLayout>
00030 #include <QLabel>
00031 
00032 #include <iostream>
00033 #include <string>
00034 
00035 #include <cmath>
00036 
00037 PluginParameterBox::PluginParameterBox(Vamp::PluginBase *plugin, QWidget *parent) :
00038     QFrame(parent),
00039     m_plugin(plugin),
00040     m_programCombo(0)
00041 {
00042     m_layout = new QGridLayout;
00043     setLayout(m_layout);
00044     populate();
00045 }
00046 
00047 PluginParameterBox::~PluginParameterBox()
00048 {
00049 }
00050 
00051 void
00052 PluginParameterBox::populate()
00053 {
00054     Vamp::PluginBase::ParameterList params = m_plugin->getParameterDescriptors();
00055     m_programs = m_plugin->getPrograms();
00056 
00057     m_params.clear();
00058 
00059     if (params.empty() && m_programs.empty()) {
00060         m_layout->addWidget
00061             (new QLabel(tr("This plugin has no adjustable parameters.")),
00062              0, 0);
00063     }
00064 
00065     int offset = 0;
00066 
00067     if (!m_programs.empty()) {
00068 
00069         std::string currentProgram = m_plugin->getCurrentProgram();
00070 
00071         m_programCombo = new QComboBox;
00072         m_programCombo->setMaxVisibleItems
00073             (m_programs.size() < 25 ? m_programs.size() : 20);
00074 
00075         for (size_t i = 0; i < m_programs.size(); ++i) {
00076             m_programCombo->addItem(m_programs[i].c_str());
00077             if (m_programs[i] == currentProgram) {
00078                 m_programCombo->setCurrentIndex(i);
00079             }
00080         }
00081 
00082         m_layout->addWidget(new QLabel(tr("Program")), 0, 0);
00083         m_layout->addWidget(m_programCombo, 0, 1, 1, 2);
00084 
00085         connect(m_programCombo, SIGNAL(currentIndexChanged(const QString &)),
00086                 this, SLOT(programComboChanged(const QString &)));
00087 
00088         offset = 1;
00089     }
00090 
00091     for (size_t i = 0; i < params.size(); ++i) {
00092 
00093         QString identifier = params[i].identifier.c_str();
00094         QString name = params[i].name.c_str();
00095         QString unit = params[i].unit.c_str();
00096 
00097         float min = params[i].minValue;
00098         float max = params[i].maxValue;
00099         float deft = params[i].defaultValue;
00100         float value = m_plugin->getParameter(params[i].identifier);
00101 
00102         int hint = PortHint::NoHint;
00103         RealTimePluginInstance *rtpi = dynamic_cast<RealTimePluginInstance *>
00104             (m_plugin);
00105         if (rtpi) {
00106             hint = rtpi->getParameterDisplayHint(i);
00107         }
00108 
00109         float qtz = 0.0;
00110         if (params[i].isQuantized) qtz = params[i].quantizeStep;
00111 
00112 //        cerr << "PluginParameterBox: hint = " << hint << ", min = " << min << ", max = "
00113 //                  << max << ", qtz = " << qtz << endl;
00114 
00115         std::vector<std::string> valueNames = params[i].valueNames;
00116 
00117         // construct an integer range
00118 
00119         int imin = 0, imax = 100;
00120 
00121         if (!(hint & PortHint::Logarithmic)) {
00122             if (qtz > 0.0) {
00123                 imax = lrintf((max - min) / qtz);
00124             } else {
00125                 qtz = (max - min) / 100.0;
00126             }
00127         }
00128 
00130         // an integer!
00131 
00132         QLabel *label = new QLabel(name);
00133         if (params[i].description != "") {
00134             label->setToolTip(QString("<qt>%1</qt>")
00135                               .arg(params[i].description.c_str())
00136                               .replace("\n", "<br>"));
00137         }
00138         m_layout->addWidget(label, i + offset, 0);
00139 
00140         ParamRec rec;
00141         rec.param = params[i];
00142         rec.dial = 0;
00143         rec.spin = 0;
00144         rec.check = 0;
00145         rec.combo = 0;
00146         
00147         if (params[i].isQuantized && !valueNames.empty()) {
00148             
00149             QComboBox *combobox = new QComboBox;
00150             combobox->setObjectName(identifier);
00151             for (unsigned int j = 0; j < valueNames.size(); ++j) {
00152                 combobox->addItem(valueNames[j].c_str());
00153                 if ((unsigned int)(lrintf(fabsf((value - min) / qtz))) == j) {
00154                     combobox->setCurrentIndex(j);
00155                 }
00156             }
00157             connect(combobox, SIGNAL(activated(int)),
00158                     this, SLOT(dialChanged(int)));
00159             m_layout->addWidget(combobox, i + offset, 1, 1, 2);
00160             rec.combo = combobox;
00161 
00162         } else if (min == 0.0 && max == 1.0 && qtz == 1.0) {
00163             
00164             QCheckBox *checkbox = new QCheckBox;
00165             checkbox->setObjectName(identifier);
00166             checkbox->setCheckState(value < 0.5 ? Qt::Unchecked : Qt::Checked);
00167             connect(checkbox, SIGNAL(stateChanged(int)),
00168                     this, SLOT(checkBoxChanged(int)));
00169             m_layout->addWidget(checkbox, i + offset, 2);
00170             rec.check = checkbox;
00171 
00172         } else {
00173             
00174             AudioDial *dial = new AudioDial;
00175             dial->setObjectName(name);
00176             dial->setMinimum(imin);
00177             dial->setMaximum(imax);
00178             dial->setPageStep(1);
00179             dial->setNotchesVisible((imax - imin) <= 12);
00181 //            dial->setValue(lrintf((value - min) / qtz));
00182             dial->setFixedWidth(32);
00183             dial->setFixedHeight(32);
00184             RangeMapper *rm = 0;
00185             if (hint & PortHint::Logarithmic) {
00186                 rm = new LogRangeMapper(imin, imax, min, max, unit);
00187             } else {
00188                 rm = new LinearRangeMapper(imin, imax, min, max, unit);
00189             }
00190             dial->setRangeMapper(rm);
00191             dial->setDefaultValue(rm->getPositionForValue(deft));
00192             dial->setValue(rm->getPositionForValue(value));
00193             dial->setShowToolTip(true);
00194             connect(dial, SIGNAL(valueChanged(int)),
00195                     this, SLOT(dialChanged(int)));
00196             m_layout->addWidget(dial, i + offset, 1);
00197 
00198             QDoubleSpinBox *spinbox = new QDoubleSpinBox;
00199             spinbox->setObjectName(identifier);
00200             spinbox->setMinimum(min);
00201             spinbox->setMaximum(max);
00202             spinbox->setSuffix(QString(" %1").arg(unit));
00203             if (qtz != 0) spinbox->setSingleStep(qtz);
00204             spinbox->setValue(value);
00205             spinbox->setDecimals(4);
00206             connect(spinbox, SIGNAL(valueChanged(double)),
00207                     this, SLOT(spinBoxChanged(double)));
00208             m_layout->addWidget(spinbox, i + offset, 2);
00209             rec.dial = dial;
00210             rec.spin = spinbox;
00211         }
00212 
00213         m_params[identifier] = rec;
00214         m_nameMap[name] = identifier;
00215     }
00216 }
00217 
00218 void
00219 PluginParameterBox::dialChanged(int ival)
00220 {
00221     QObject *obj = sender();
00222     QString identifier = obj->objectName();
00223 
00224     if (m_params.find(identifier) == m_params.end() &&
00225         m_nameMap.find(identifier) != m_nameMap.end()) {
00226         identifier = m_nameMap[identifier];
00227     }
00228 
00229     if (m_params.find(identifier) == m_params.end()) {
00230         cerr << "WARNING: PluginParameterBox::dialChanged: Unknown parameter \"" << identifier << "\"" << endl;
00231         return;
00232     }
00233 
00234     Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
00235 
00236     float min = params.minValue;
00237     float max = params.maxValue;
00238 
00239     float newValue;
00240 
00241     float qtz = 0.0;
00242     if (params.isQuantized) qtz = params.quantizeStep;
00243 
00244     AudioDial *ad = dynamic_cast<AudioDial *>(obj);
00245     
00246     if (ad && ad->rangeMapper()) {
00247         
00248         newValue = ad->mappedValue();
00249         if (newValue < min) newValue = min;
00250         if (newValue > max) newValue = max;
00251         if (qtz != 0.0) {
00252             ival = lrintf((newValue - min) / qtz);
00253             newValue = min + ival * qtz;
00254         }
00255 
00256     } else {
00257         if (qtz == 0.0) {
00258             qtz = (max - min) / 100.0;
00259         }
00260         newValue = min + ival * qtz;
00261     }
00262 
00263 //    SVDEBUG << "PluginParameterBox::dialChanged: newValue = " << newValue << endl;
00264 
00265     QDoubleSpinBox *spin = m_params[identifier].spin;
00266     if (spin) {
00267         spin->blockSignals(true);
00268         spin->setValue(newValue);
00269         spin->blockSignals(false);
00270     }
00271 
00272 //    SVDEBUG << "setting plugin parameter \"" << identifier << "\" to value " << newValue << endl;
00273 
00274     m_plugin->setParameter(identifier.toStdString(), newValue);
00275 
00276     updateProgramCombo();
00277 
00278     emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
00279 }
00280 
00281 void
00282 PluginParameterBox::checkBoxChanged(int state)
00283 {
00284     QObject *obj = sender();
00285     QString identifier = obj->objectName();
00286 
00287     if (m_params.find(identifier) == m_params.end() &&
00288         m_nameMap.find(identifier) != m_nameMap.end()) {
00289         identifier = m_nameMap[identifier];
00290     }
00291 
00292     if (m_params.find(identifier) == m_params.end()) {
00293         cerr << "WARNING: PluginParameterBox::checkBoxChanged: Unknown parameter \"" << identifier << "\"" << endl;
00294         return;
00295     }
00296 
00297     Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
00298 
00299     if (state) m_plugin->setParameter(identifier.toStdString(), 1.0);
00300     else m_plugin->setParameter(identifier.toStdString(), 0.0);
00301 
00302     updateProgramCombo();
00303 
00304     emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
00305 }
00306 
00307 void
00308 PluginParameterBox::spinBoxChanged(double value)
00309 {
00310     QObject *obj = sender();
00311     QString identifier = obj->objectName();
00312 
00313     if (m_params.find(identifier) == m_params.end() &&
00314         m_nameMap.find(identifier) != m_nameMap.end()) {
00315         identifier = m_nameMap[identifier];
00316     }
00317 
00318     if (m_params.find(identifier) == m_params.end()) {
00319         cerr << "WARNING: PluginParameterBox::spinBoxChanged: Unknown parameter \"" << identifier << "\"" << endl;
00320         return;
00321     }
00322 
00323     Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
00324 
00325     float min = params.minValue;
00326     float max = params.maxValue;
00327 
00328     float qtz = 0.0;
00329     if (params.isQuantized) qtz = params.quantizeStep;
00330     
00331     if (qtz > 0.0) {
00332         int step = lrintf((value - min) / qtz);
00333         value = min + step * qtz;
00334     }
00335 
00336 //    int imax = 100;
00337     
00338     if (qtz > 0.0) {
00339 //        imax = lrintf((max - min) / qtz);
00340     } else {
00341         qtz = (max - min) / 100.0;
00342     }
00343 
00344     int ival = lrintf((value - min) / qtz);
00345 
00346     AudioDial *dial = m_params[identifier].dial;
00347     if (dial) {
00348         dial->blockSignals(true);
00349         if (dial->rangeMapper()) {
00350             dial->setMappedValue(value);
00351         } else {
00352             dial->setValue(ival);
00353         }
00354         dial->blockSignals(false);
00355     }
00356 
00357     SVDEBUG << "setting plugin parameter \"" << identifier << "\" to value " << value << endl;
00358 
00359     m_plugin->setParameter(identifier.toStdString(), value);
00360 
00361     updateProgramCombo();
00362 
00363     emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
00364 }
00365 
00366 void
00367 PluginParameterBox::programComboChanged(const QString &newProgram)
00368 {
00369     m_plugin->selectProgram(newProgram.toStdString());
00370 
00371     for (std::map<QString, ParamRec>::iterator i = m_params.begin();
00372          i != m_params.end(); ++i) {
00373 
00374         Vamp::PluginBase::ParameterDescriptor &param = i->second.param;
00375         float value = m_plugin->getParameter(param.identifier);
00376 
00377         if (i->second.spin) {
00378             i->second.spin->blockSignals(true);
00379             i->second.spin->setValue(value);
00380             i->second.spin->blockSignals(false);
00381         }
00382 
00383         if (i->second.dial) {
00384 
00385             float min = param.minValue;
00386             float max = param.maxValue;
00387 
00388             float qtz = 0.0;
00389             if (param.isQuantized) qtz = param.quantizeStep;
00390 
00391             if (qtz == 0.0) {
00392                 qtz = (max - min) / 100.0;
00393             }
00394 
00395             i->second.dial->blockSignals(true);
00396             i->second.dial->setValue(lrintf((value - min) / qtz));
00397             i->second.dial->blockSignals(false);
00398         }
00399 
00400         if (i->second.combo) {
00401             i->second.combo->blockSignals(true);
00402             i->second.combo->setCurrentIndex(lrintf(value));
00403             i->second.combo->blockSignals(false);
00404         }
00405 
00406         if (i->second.check) {
00407             i->second.check->blockSignals(true);
00408             i->second.check->setCheckState(value < 0.5 ? Qt::Unchecked : Qt::Checked);
00409             i->second.check->blockSignals(false);
00410         }            
00411     }
00412 
00413     emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
00414 }
00415 
00416 void
00417 PluginParameterBox::updateProgramCombo()
00418 {
00419     if (!m_programCombo || m_programs.empty()) return;
00420 
00421     std::string currentProgram = m_plugin->getCurrentProgram();
00422 
00423     for (size_t i = 0; i < m_programs.size(); ++i) {
00424         if (m_programs[i] == currentProgram) {
00425             m_programCombo->setCurrentIndex(i);
00426         }
00427     }
00428 }
00429 
00430