PluginParameterBox.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam and QMUL.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #include "PluginParameterBox.h"
17 
18 #include "AudioDial.h"
19 
20 #include "plugin/PluginXml.h"
21 #include "plugin/RealTimePluginInstance.h" // for PortHint stuff
22 
23 #include "base/RangeMapper.h"
24 
25 #include <QDoubleSpinBox>
26 #include <QGridLayout>
27 #include <QComboBox>
28 #include <QCheckBox>
29 #include <QLayout>
30 #include <QLabel>
31 
32 #include <iostream>
33 #include <string>
34 
35 #include <cmath>
36 
37 PluginParameterBox::PluginParameterBox(std::shared_ptr<Vamp::PluginBase> plugin,
38  QWidget *parent) :
39  QFrame(parent),
40  m_plugin(plugin),
41  m_programCombo(nullptr)
42 {
43  m_layout = new QGridLayout;
44  setLayout(m_layout);
45  populate();
46 }
47 
49 {
50 }
51 
52 void
54 {
55  Vamp::PluginBase::ParameterList params = m_plugin->getParameterDescriptors();
56  m_programs = m_plugin->getPrograms();
57 
58  m_params.clear();
59 
60  if (params.empty() && m_programs.empty()) {
61  m_layout->addWidget
62  (new QLabel(tr("This plugin has no adjustable parameters.")),
63  0, 0);
64  }
65 
66  int offset = 0;
67 
68  if (!m_programs.empty()) {
69 
70  std::string currentProgram = m_plugin->getCurrentProgram();
71 
72  m_programCombo = new QComboBox;
73  m_programCombo->setMaxVisibleItems
74  (int(m_programs.size() < 25 ? m_programs.size() : 20));
75 
76  for (int i = 0; in_range_for(m_programs, i); ++i) {
77  m_programCombo->addItem(m_programs[i].c_str());
78  if (m_programs[i] == currentProgram) {
79  m_programCombo->setCurrentIndex(int(i));
80  }
81  }
82 
83  m_layout->addWidget(new QLabel(tr("Program")), 0, 0);
84  m_layout->addWidget(m_programCombo, 0, 1, 1, 2);
85 
86  connect(m_programCombo, SIGNAL(currentIndexChanged(const QString &)),
87  this, SLOT(programComboChanged(const QString &)));
88 
89  offset = 1;
90  }
91 
92  for (int i = 0; in_range_for(params, i); ++i) {
93 
94  QString identifier = params[i].identifier.c_str();
95  QString name = params[i].name.c_str();
96  QString unit = params[i].unit.c_str();
97 
98  float min = params[i].minValue;
99  float max = params[i].maxValue;
100  float deft = params[i].defaultValue;
101  float value = m_plugin->getParameter(params[i].identifier);
102 
103  int hint = PortHint::NoHint;
104  auto rtpi = std::dynamic_pointer_cast<RealTimePluginInstance>
105  (m_plugin);
106  if (rtpi) {
107  hint = rtpi->getParameterDisplayHint(i);
108  }
109 
110  float qtz = 0.0;
111  if (params[i].isQuantized) qtz = params[i].quantizeStep;
112 
113 // cerr << "PluginParameterBox: hint = " << hint << ", min = " << min << ", max = "
114 // << max << ", qtz = " << qtz << endl;
115 
116  std::vector<std::string> valueNames = params[i].valueNames;
117 
118  // construct an integer range
119 
120  int imin = 0, imax = 100;
121 
122  if (!(hint & PortHint::Logarithmic)) {
123  if (qtz > 0.0) {
124  imax = int(lrintf((max - min) / qtz));
125  if (imax <= imin) {
126  imax = 100;
127  qtz = (max - min) / 100.f;
128  }
129  } else {
130  qtz = (max - min) / 100.f;
131  }
132  }
133 
135  // an integer!
136 
137  QLabel *label = new QLabel(name);
138  if (params[i].description != "") {
139  label->setToolTip(QString("<qt>%1</qt>")
140  .arg(params[i].description.c_str())
141  .replace("\n", "<br>"));
142  }
143  m_layout->addWidget(label, i + offset, 0);
144 
145  ParamRec rec;
146  rec.param = params[i];
147  rec.dial = nullptr;
148  rec.spin = nullptr;
149  rec.check = nullptr;
150  rec.combo = nullptr;
151 
152  if (params[i].isQuantized && !valueNames.empty()) {
153 
154  QComboBox *combobox = new QComboBox;
155  combobox->setObjectName(identifier);
156  for (unsigned int j = 0; j < valueNames.size(); ++j) {
157  combobox->addItem(valueNames[j].c_str());
158  if ((unsigned int)(lrintf(fabsf((value - min) / qtz))) == j) {
159  combobox->setCurrentIndex(j);
160  }
161  }
162  connect(combobox, SIGNAL(activated(int)),
163  this, SLOT(dialChanged(int)));
164  m_layout->addWidget(combobox, i + offset, 1, 1, 2);
165  rec.combo = combobox;
166 
167  } else if (min == 0.0 && max == 1.0 && qtz == 1.0) {
168 
169  QCheckBox *checkbox = new QCheckBox;
170  checkbox->setObjectName(identifier);
171  checkbox->setCheckState(value < 0.5 ? Qt::Unchecked : Qt::Checked);
172  connect(checkbox, SIGNAL(stateChanged(int)),
173  this, SLOT(checkBoxChanged(int)));
174  m_layout->addWidget(checkbox, i + offset, 2);
175  rec.check = checkbox;
176 
177  } else {
178 
179  AudioDial *dial = new AudioDial;
180  dial->setObjectName(name);
181  dial->setMinimum(imin);
182  dial->setMaximum(imax);
183  dial->setPageStep(1);
184  dial->setNotchesVisible((imax - imin) <= 12);
186 // dial->setValue(lrintf((value - min) / qtz));
187  dial->setFixedWidth(32);
188  dial->setFixedHeight(32);
189  if (max == min || imax == imin) {
190  SVCERR << "WARNING: for parameter \"" << name
191  << "\" of plugin \"" << m_plugin->getName()
192  << "\": invalid range " << min << " -> " << max
193  << " with quantize step " << qtz << endl;
194  } else {
195  RangeMapper *rm = nullptr;
196  if (hint & PortHint::Logarithmic) {
197  rm = new LogRangeMapper(imin, imax, min, max, unit);
198  } else {
199  rm = new LinearRangeMapper(imin, imax, min, max, unit);
200  }
201  dial->setRangeMapper(rm);
202  dial->setDefaultValue(rm->getPositionForValue(deft));
203  dial->setValue(rm->getPositionForValue(value));
204  }
205  dial->setShowToolTip(true);
206  connect(dial, SIGNAL(valueChanged(int)),
207  this, SLOT(dialChanged(int)));
208  m_layout->addWidget(dial, i + offset, 1);
209 
210  QDoubleSpinBox *spinbox = new QDoubleSpinBox;
211  spinbox->setObjectName(identifier);
212  spinbox->setMinimum(min);
213  spinbox->setMaximum(max);
214  spinbox->setSuffix(QString(" %1").arg(unit));
215  if (qtz != 0) spinbox->setSingleStep(qtz);
216  spinbox->setValue(value);
217  spinbox->setDecimals(4);
218  connect(spinbox, SIGNAL(valueChanged(double)),
219  this, SLOT(spinBoxChanged(double)));
220  m_layout->addWidget(spinbox, i + offset, 2);
221  rec.dial = dial;
222  rec.spin = spinbox;
223  }
224 
225  m_params[identifier] = rec;
226  m_nameMap[name] = identifier;
227  }
228 }
229 
230 void
232 {
233  QObject *obj = sender();
234  QString identifier = obj->objectName();
235 
236  if (m_params.find(identifier) == m_params.end() &&
237  m_nameMap.find(identifier) != m_nameMap.end()) {
238  identifier = m_nameMap[identifier];
239  }
240 
241  if (m_params.find(identifier) == m_params.end()) {
242  cerr << "WARNING: PluginParameterBox::dialChanged: Unknown parameter \"" << identifier << "\"" << endl;
243  return;
244  }
245 
246  Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
247 
248  float min = params.minValue;
249  float max = params.maxValue;
250 
251  float newValue;
252 
253  float qtz = 0.0;
254  if (params.isQuantized) qtz = params.quantizeStep;
255 
256  AudioDial *ad = dynamic_cast<AudioDial *>(obj);
257 
258  if (ad && ad->rangeMapper()) {
259 
260  newValue = float(ad->mappedValue());
261  if (newValue < min) newValue = min;
262  if (newValue > max) newValue = max;
263  if (qtz != 0.0) {
264  ival = int(lrintf((newValue - min) / qtz));
265  newValue = min + float(ival) * qtz;
266  }
267 
268  } else {
269  if (qtz == 0.f) {
270  qtz = (max - min) / 100.f;
271  }
272  newValue = min + float(ival) * qtz;
273  }
274 
275 // SVDEBUG << "PluginParameterBox::dialChanged: newValue = " << newValue << endl;
276 
277  QDoubleSpinBox *spin = m_params[identifier].spin;
278  if (spin) {
279  spin->blockSignals(true);
280  spin->setValue(newValue);
281  spin->blockSignals(false);
282  }
283 
284 // SVDEBUG << "setting plugin parameter \"" << identifier << "\" to value " << newValue << endl;
285 
286  m_plugin->setParameter(identifier.toStdString(), newValue);
287 
289 
290  emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
291 }
292 
293 void
295 {
296  QObject *obj = sender();
297  QString identifier = obj->objectName();
298 
299  if (m_params.find(identifier) == m_params.end() &&
300  m_nameMap.find(identifier) != m_nameMap.end()) {
301  identifier = m_nameMap[identifier];
302  }
303 
304  if (m_params.find(identifier) == m_params.end()) {
305  cerr << "WARNING: PluginParameterBox::checkBoxChanged: Unknown parameter \"" << identifier << "\"" << endl;
306  return;
307  }
308 
309  Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
310 
311  if (state) m_plugin->setParameter(identifier.toStdString(), 1.0);
312  else m_plugin->setParameter(identifier.toStdString(), 0.0);
313 
315 
316  emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
317 }
318 
319 void
321 {
322  QObject *obj = sender();
323  QString identifier = obj->objectName();
324 
325  if (m_params.find(identifier) == m_params.end() &&
326  m_nameMap.find(identifier) != m_nameMap.end()) {
327  identifier = m_nameMap[identifier];
328  }
329 
330  if (m_params.find(identifier) == m_params.end()) {
331  cerr << "WARNING: PluginParameterBox::spinBoxChanged: Unknown parameter \"" << identifier << "\"" << endl;
332  return;
333  }
334 
335  Vamp::PluginBase::ParameterDescriptor params = m_params[identifier].param;
336 
337  float min = params.minValue;
338  float max = params.maxValue;
339 
340  float qtz = 0.0;
341  if (params.isQuantized) qtz = params.quantizeStep;
342 
343  if (qtz > 0.0) {
344  int step = int(lrintf(float(value - min) / qtz));
345  value = min + float(step) * qtz;
346  }
347 
348 // int imax = 100;
349 
350  if (qtz > 0.0) {
351 // imax = lrintf((max - min) / qtz);
352  } else {
353  qtz = (max - min) / 100.f;
354  }
355 
356  int ival = int(lrintf(float(value - min) / qtz));
357 
358  AudioDial *dial = m_params[identifier].dial;
359  if (dial) {
360  dial->blockSignals(true);
361  if (dial->rangeMapper()) {
362  dial->setMappedValue(value);
363  } else {
364  dial->setValue(ival);
365  }
366  dial->blockSignals(false);
367  }
368 
369  SVDEBUG << "setting plugin parameter \"" << identifier << "\" to value " << value << endl;
370 
371  m_plugin->setParameter(identifier.toStdString(), float(value));
372 
374 
375  emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
376 }
377 
378 void
379 PluginParameterBox::programComboChanged(const QString &newProgram)
380 {
381  m_plugin->selectProgram(newProgram.toStdString());
382 
383  for (std::map<QString, ParamRec>::iterator i = m_params.begin();
384  i != m_params.end(); ++i) {
385 
386  Vamp::PluginBase::ParameterDescriptor &param = i->second.param;
387  float value = m_plugin->getParameter(param.identifier);
388 
389  if (i->second.spin) {
390  i->second.spin->blockSignals(true);
391  i->second.spin->setValue(value);
392  i->second.spin->blockSignals(false);
393  }
394 
395  if (i->second.dial) {
396 
397  float min = param.minValue;
398  float max = param.maxValue;
399 
400  float qtz = 0.0;
401  if (param.isQuantized) qtz = param.quantizeStep;
402 
403  if (qtz == 0.0) {
404  qtz = (max - min) / 100.f;
405  }
406 
407  i->second.dial->blockSignals(true);
408  i->second.dial->setValue(int(lrintf(float(value - min) / qtz)));
409  i->second.dial->blockSignals(false);
410  }
411 
412  if (i->second.combo) {
413  i->second.combo->blockSignals(true);
414  i->second.combo->setCurrentIndex(int(lrintf(value)));
415  i->second.combo->blockSignals(false);
416  }
417 
418  if (i->second.check) {
419  i->second.check->blockSignals(true);
420  i->second.check->setCheckState(value < 0.5 ? Qt::Unchecked : Qt::Checked);
421  i->second.check->blockSignals(false);
422  }
423  }
424 
425  emit pluginConfigurationChanged(PluginXml(m_plugin).toXmlString());
426 }
427 
428 void
430 {
431  if (!m_programCombo || m_programs.empty()) return;
432 
433  std::string currentProgram = m_plugin->getCurrentProgram();
434 
435  for (int i = 0; in_range_for(m_programs, i); ++i) {
436  if (m_programs[i] == currentProgram) {
437  m_programCombo->setCurrentIndex(i);
438  }
439  }
440 }
441 
442 
void setMappedValue(double mappedValue)
Definition: AudioDial.cpp:420
QComboBox * m_programCombo
void setDefaultValue(int defaultValue)
Definition: AudioDial.cpp:398
void pluginConfigurationChanged(QString)
double mappedValue() const
Definition: AudioDial.cpp:455
std::map< QString, ParamRec > m_params
const RangeMapper * rangeMapper() const
Definition: AudioDial.h:76
std::map< QString, QString > m_nameMap
AudioDial is a nicer-looking QDial that by default reacts to mouse movement on horizontal and vertica...
Definition: AudioDial.h:60
QGridLayout * m_layout
void programComboChanged(const QString &)
Vamp::PluginBase::ProgramList m_programs
void setValue(int value)
Definition: AudioDial.cpp:406
PluginParameterBox(std::shared_ptr< Vamp::PluginBase >, QWidget *parent=0)
std::shared_ptr< Vamp::PluginBase > m_plugin
Vamp::PluginBase::ParameterDescriptor param
void setRangeMapper(RangeMapper *mapper)
Definition: AudioDial.cpp:126
void setShowToolTip(bool show)
Definition: AudioDial.cpp:440