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