drumstick  2.10.0
C++MIDIlibrariesusingQtobjects,idioms,andstyle.
fluidsettingsdialog.cpp
Go to the documentation of this file.
1 /*
2  Drumstick MIDI Sequencer C++ library
3  Copyright (C) 2006-2024, Pedro Lopez-Cabanillas <plcl@users.sf.net>
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include <QDir>
20 #include <QFileDialog>
21 #include <QFileInfo>
22 #include <QMessageBox>
23 #include <QPushButton>
24 #include <QStandardPaths>
25 #include <QToolButton>
26 #include <QToolTip>
27 #include <QVersionNumber>
28 
29 #include "fluidsettingsdialog.h"
30 #include "ui_fluidsettingsdialog.h"
33 
39 namespace drumstick { namespace widgets {
40 
41 const QString FluidSettingsDialog::QSTR_PREFERENCES = QStringLiteral("FluidSynth");
42 const QString FluidSettingsDialog::QSTR_INSTRUMENTSDEFINITION = QStringLiteral("InstrumentsDefinition");
43 const QString FluidSettingsDialog::QSTR_DATADIR = QStringLiteral("soundfonts");
44 const QString FluidSettingsDialog::QSTR_DATADIR2 = QStringLiteral("sounds/sf2");
45 const QString FluidSettingsDialog::QSTR_AUDIODRIVER = QStringLiteral("AudioDriver");
46 const QString FluidSettingsDialog::QSTR_PERIODSIZE = QStringLiteral("PeriodSize");
47 const QString FluidSettingsDialog::QSTR_PERIODS = QStringLiteral("Periods");
48 const QString FluidSettingsDialog::QSTR_SAMPLERATE = QStringLiteral("SampleRate");
49 const QString FluidSettingsDialog::QSTR_CHORUS = QStringLiteral("Chorus");
50 const QString FluidSettingsDialog::QSTR_REVERB = QStringLiteral("Reverb");
51 const QString FluidSettingsDialog::QSTR_GAIN = QStringLiteral("Gain");
52 const QString FluidSettingsDialog::QSTR_POLYPHONY = QStringLiteral("Polyphony");
53 const QString FluidSettingsDialog::QSTR_BUFFERTIME = QStringLiteral("BufferTime");
54 const QString FluidSettingsDialog::QSTR_PULSEAUDIO = QStringLiteral("pulseaudio");
55 const QString FluidSettingsDialog::QSTR_CHORUS_DEPTH = QStringLiteral("chorus_depth");
56 const QString FluidSettingsDialog::QSTR_CHORUS_LEVEL = QStringLiteral("chorus_level");
57 const QString FluidSettingsDialog::QSTR_CHORUS_NR = QStringLiteral("chorus_nr");
58 const QString FluidSettingsDialog::QSTR_CHORUS_SPEED = QStringLiteral("chorus_speed");
59 const QString FluidSettingsDialog::QSTR_REVERB_DAMP = QStringLiteral("reverb_damp");
60 const QString FluidSettingsDialog::QSTR_REVERB_LEVEL = QStringLiteral("reverb_level");
61 const QString FluidSettingsDialog::QSTR_REVERB_SIZE = QStringLiteral("reverb_size");
62 const QString FluidSettingsDialog::QSTR_REVERB_WIDTH = QStringLiteral("reverb_width");
63 
64 FluidSettingsDialog::FluidSettingsDialog(QWidget *parent) :
65  QDialog(parent),
66  ui(new Ui::FluidSettingsDialog)
67 {
68  ui->setupUi(this);
69  connect(ui->audioDriver, &QComboBox::currentTextChanged, this, &FluidSettingsDialog::audioDriverChanged);
70  connect(ui->bufferTime, QOverload<int>::of(&QSpinBox::valueChanged), this, &FluidSettingsDialog::bufferTimeChanged);
71  connect(ui->periodSize, QOverload<int>::of(&QSpinBox::valueChanged), this, &FluidSettingsDialog::bufferSizeChanged);
72  connect(ui->periods, QOverload<int>::of(&QSpinBox::valueChanged), this, &FluidSettingsDialog::bufferSizeChanged);
73  connect(ui->btnFile, &QToolButton::clicked, this, &FluidSettingsDialog::showFileDialog);
74  connect(ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked,
75  this, &FluidSettingsDialog::restoreDefaults);
76  connect(ui->chorus_depth, &QAbstractSlider::valueChanged, this, [=](int val) {
77  QString v = QString::number(val / CHORUS_REVERB_VALUE_SCALE, 'f', 2);
78  ui->label_CDepth->setText(v);
79  });
80  connect(ui->chorus_level, &QAbstractSlider::valueChanged, this, [=](int val) {
81  QString v = QString::number(val / CHORUS_REVERB_VALUE_SCALE, 'f', 2);
82  ui->label_CLevel->setText(v);
83  });
84  connect(ui->chorus_nr, &QAbstractSlider::valueChanged, this, [=](int val) {
85  QString v = QString::number(val);
86  ui->label_CNR->setText(v);
87  });
88  connect(ui->chorus_speed, &QAbstractSlider::valueChanged, this, [=](int val) {
89  QString v = QString::number(val / CHORUS_REVERB_VALUE_SCALE, 'f', 2);
90  ui->label_CSpeed->setText(v);
91  });
92  connect(ui->reverb_damp, &QAbstractSlider::valueChanged, this, [=](int val) {
93  QString v = QString::number(val / CHORUS_REVERB_VALUE_SCALE, 'f', 2);
94  ui->label_RDamp->setText(v);
95  });
96  connect(ui->reverb_level, &QAbstractSlider::valueChanged, this, [=](int val) {
97  QString v = QString::number(val / CHORUS_REVERB_VALUE_SCALE, 'f', 2);
98  ui->label_RLevel->setText(v);
99  });
100  connect(ui->reverb_size, &QAbstractSlider::valueChanged, this, [=](int val) {
101  QString v = QString::number(val / CHORUS_REVERB_VALUE_SCALE, 'f', 2);
102  ui->label_RSize->setText(v);
103  });
104  connect(ui->reverb_width, &QAbstractSlider::valueChanged, this, [=](int val) {
105  QString v = QString::number(val / CHORUS_REVERB_VALUE_SCALE, 'f', 2);
106  ui->label_RWidth->setText(v);
107  });
108 
110  m_driver = man.outputBackendByName("FluidSynth");
111  if (m_driver != nullptr) {
112  QVariant v = m_driver->property("audiodrivers");
113  if (v.isValid()) {
114  ui->audioDriver->blockSignals(true);
115  ui->audioDriver->clear();
116  ui->audioDriver->addItems(v.toStringList());
117  ui->audioDriver->blockSignals(false);
118  }
119  v = m_driver->property("soundfont");
120  if (v.isValid()) {
121  m_defSoundFont = v.toString();
122  }
123  }
124  ui->bufferTime->blockSignals(true);
125  ui->periodSize->blockSignals(true);
126  ui->periods->blockSignals(true);
127 }
128 
129 FluidSettingsDialog::~FluidSettingsDialog()
130 {
131  if (m_driver != nullptr) {
132  m_driver->close();
133  }
134  delete ui;
135 }
136 
137 bool FluidSettingsDialog::checkRanges() const
138 {
139  return ui->bufferTime->hasAcceptableInput() && ui->periodSize->hasAcceptableInput()
140  && ui->periods->hasAcceptableInput();
141 }
142 
143 void FluidSettingsDialog::accept()
144 {
145  if (checkRanges()) {
146  writeSettings();
147  if (m_driver != nullptr) {
148  QString title;
149  QVariant varStatus = m_driver->property("status");
150  if (varStatus.isValid()) {
151  title = varStatus.toBool() ? tr("FluidSynth Initialized") : tr("FluidSynth Initialization Failed");
152  QVariant varDiag = m_driver->property("diagnostics");
153  if (varDiag.isValid()) {
154  QString text = varDiag.toStringList().join(QChar::LineFeed).trimmed();
155  if (varStatus.toBool()) {
156  if (!text.isEmpty()) {
157  QMessageBox::information(this, title, text);
158  }
159  } else {
160  QMessageBox::critical(this, title, text);
161  return;
162  }
163  }
164  }
165  }
166  QDialog::accept();
167  }
168 }
169 
170 void FluidSettingsDialog::showEvent(QShowEvent *event)
171 {
172  readSettings();
173  event->accept();
174 }
175 
176 QString FluidSettingsDialog::defaultAudioDriver() const
177 {
178  const QString QSTR_DEFAULT_AUDIODRIVER =
179 #if defined(Q_OS_WIN)
180  QLatin1String("wasapi");
181 #elif defined(Q_OS_OSX)
182  QLatin1String("coreaudio");
183 #elif defined(Q_OS_LINUX)
184  QSTR_PULSEAUDIO;
185 #else
186  QLatin1String("oss");
187 #endif
188  return QSTR_DEFAULT_AUDIODRIVER;
189 }
190 
191 void FluidSettingsDialog::chkDriverProperties(QSettings *settings)
192 {
193  if (m_driver != nullptr) {
195  m_driver->close();
196  m_driver->initialize(settings);
197  m_driver->open(conn);
198 
199  QVariant drivers = m_driver->property("audiodrivers");
200  if (drivers.isValid()) {
201  auto text = ui->audioDriver->currentText();
202  ui->audioDriver->blockSignals(true);
203  ui->audioDriver->clear();
204  ui->audioDriver->addItems(drivers.toStringList());
205  ui->audioDriver->setCurrentText(text);
206  ui->audioDriver->blockSignals(false);
207  }
208  ui->lblVersion->clear();
209  ui->lblVersion->setText(driverVersion());
210  QVariant varStatus = m_driver->property("status");
211  if (varStatus.isValid()) {
212  ui->lblStatus->clear();
213  ui->lblStatus->setText(varStatus.toBool() ? tr("Ready") : tr("Failed") );
214  ui->lblStatusIcon->setPixmap(varStatus.toBool() ? QPixmap(":/checked.png") : QPixmap(":/error.png") );
215  }
216  }
217 }
218 
219 void FluidSettingsDialog::setWidgetTip(QWidget *w, const QString &tip)
220 {
221  w->setToolTip(tip);
222  QToolTip::showText(w->parentWidget()->mapToGlobal(w->pos()), tip);
223 }
224 
225 void drumstick::widgets::FluidSettingsDialog::initBuffer()
226 {
227  if ((ui->audioDriver->currentText() == QSTR_PULSEAUDIO) && driverVersionLessThan_2_2_8()) {
228  int bufferTime = ui->bufferTime->value();
229  int minBufTime = ui->bufferTime->minimum();
230  if (bufferTime < minBufTime) {
231  bufferTime = minBufTime;
232  }
233  ui->bufferTime->setValue( bufferTime );
234  bufferTimeChanged( bufferTime );
235  } else {
236  bufferSizeChanged();
237  }
238 }
239 
240 QString FluidSettingsDialog::driverVersion() const
241 {
242  static QString result;
243  if (m_driver != nullptr && result.isEmpty()) {
244  QVariant varVersion = m_driver->property("libversion");
245  if (varVersion.isValid()) {
246  result = varVersion.toString();
247  }
248  }
249  return result;
250 }
251 
252 bool FluidSettingsDialog::driverVersionLessThan_2_2_8()
253 {
254  static const QVersionNumber check_2_2_8(2, 2, 8);
255  QVersionNumber driverV = QVersionNumber::fromString(driverVersion());
256  return driverV < check_2_2_8;
257 }
258 
259 void FluidSettingsDialog::readSettings()
260 {
261  SettingsFactory settings;
262  settings->beginGroup(QSTR_PREFERENCES);
263  ui->audioDriver->setCurrentText( settings->value(QSTR_AUDIODRIVER, defaultAudioDriver()).toString() );
264  ui->bufferTime->setValue( settings->value(QSTR_BUFFERTIME, DEFAULT_BUFFERTIME).toInt() );
265  ui->periodSize->setValue( settings->value(QSTR_PERIODSIZE, DEFAULT_PERIODSIZE).toInt() );
266  ui->periods->setValue( settings->value(QSTR_PERIODS, DEFAULT_PERIODS).toInt() );
267  ui->sampleRate->setCurrentText(settings->value(QSTR_SAMPLERATE, DEFAULT_SAMPLERATE).toString());
268  ui->gain->setValue(settings->value(QSTR_GAIN, DEFAULT_GAIN).toDouble());
269  ui->polyphony->setValue(settings->value(QSTR_POLYPHONY, DEFAULT_POLYPHONY).toInt());
270  ui->soundFont->setText( settings->value(QSTR_INSTRUMENTSDEFINITION, m_defSoundFont).toString() );
271 
272  ui->chorus_depth->setValue(settings->value(QSTR_CHORUS_DEPTH, DEFAULT_CHORUS_DEPTH).toDouble()
273  * CHORUS_REVERB_VALUE_SCALE);
274  ui->chorus_level->setValue(settings->value(QSTR_CHORUS_LEVEL, DEFAULT_CHORUS_LEVEL).toDouble()
275  * CHORUS_REVERB_VALUE_SCALE);
276  ui->chorus_nr->setValue(settings->value(QSTR_CHORUS_NR, DEFAULT_CHORUS_NR).toInt());
277  ui->chorus_speed->setValue(settings->value(QSTR_CHORUS_SPEED, DEFAULT_CHORUS_SPEED).toDouble()
278  * CHORUS_REVERB_VALUE_SCALE);
279 
280  ui->reverb_damp->setValue(settings->value(QSTR_REVERB_DAMP, DEFAULT_REVERB_DAMP).toDouble()
281  * CHORUS_REVERB_VALUE_SCALE);
282  ui->reverb_level->setValue(settings->value(QSTR_REVERB_LEVEL, DEFAULT_REVERB_LEVEL).toDouble()
283  * CHORUS_REVERB_VALUE_SCALE);
284  ui->reverb_size->setValue(settings->value(QSTR_REVERB_SIZE, DEFAULT_REVERB_SIZE).toDouble()
285  * CHORUS_REVERB_VALUE_SCALE);
286  ui->reverb_width->setValue(settings->value(QSTR_REVERB_WIDTH, DEFAULT_REVERB_WIDTH).toDouble()
287  * CHORUS_REVERB_VALUE_SCALE);
288 
289  ui->chorus->setChecked(settings->value(QSTR_CHORUS, DEFAULT_CHORUS).toInt() != 0);
290  ui->reverb->setChecked(settings->value(QSTR_REVERB, DEFAULT_REVERB).toInt() != 0);
291 
292  settings->endGroup();
293 
294  audioDriverChanged( ui->audioDriver->currentText() );
295  chkDriverProperties(settings.getQSettings());
296 }
297 
298 void FluidSettingsDialog::writeSettings()
299 {
300  SettingsFactory settings;
301  QString audioDriver;
302  QString soundFont(m_defSoundFont);
303  int bufferTime(DEFAULT_BUFFERTIME);
304  int periodSize(DEFAULT_PERIODSIZE);
305  int periods(DEFAULT_PERIODS);
306  double sampleRate(DEFAULT_SAMPLERATE);
307  int chorus(DEFAULT_CHORUS);
308  int reverb(DEFAULT_REVERB);
309  double gain(DEFAULT_GAIN);
310  int polyphony(DEFAULT_POLYPHONY);
311 
312  double chorus_depth(DEFAULT_CHORUS_DEPTH);
313  double chorus_level(DEFAULT_CHORUS_LEVEL);
314  int chorus_nr(DEFAULT_CHORUS_NR);
315  double chorus_speed(DEFAULT_CHORUS_SPEED);
316 
317  double reverb_damp(DEFAULT_REVERB_DAMP);
318  double reverb_level(DEFAULT_REVERB_LEVEL);
319  double reverb_size(DEFAULT_REVERB_SIZE);
320  double reverb_width(DEFAULT_REVERB_WIDTH);
321 
322  audioDriver = ui->audioDriver->currentText();
323  if (audioDriver.isEmpty()) {
324  audioDriver = defaultAudioDriver();
325  }
326  soundFont = ui->soundFont->text();
327  bufferTime = ui->bufferTime->value();
328  periodSize = ui->periodSize->value();
329  periods = ui->periods->value();
330  sampleRate = ui->sampleRate->currentText().toDouble();
331  chorus = (ui->chorus->isChecked() ? 1 : 0);
332  reverb = (ui->reverb->isChecked() ? 1 : 0);
333  gain = ui->gain->value();
334  polyphony = ui->polyphony->value();
335 
336  chorus_depth = ui->chorus_depth->value() / CHORUS_REVERB_VALUE_SCALE;
337  chorus_level = ui->chorus_level->value() / CHORUS_REVERB_VALUE_SCALE;
338  chorus_nr = ui->chorus_nr->value();
339  chorus_speed = ui->chorus_speed->value() / CHORUS_REVERB_VALUE_SCALE;
340  reverb_damp = ui->reverb_damp->value() / CHORUS_REVERB_VALUE_SCALE;
341  reverb_level = ui->reverb_level->value() / CHORUS_REVERB_VALUE_SCALE;
342  reverb_size = ui->reverb_size->value() / CHORUS_REVERB_VALUE_SCALE;
343  reverb_width = ui->reverb_width->value() / CHORUS_REVERB_VALUE_SCALE;
344 
345  settings->beginGroup(QSTR_PREFERENCES);
346  settings->setValue(QSTR_INSTRUMENTSDEFINITION, soundFont);
347  settings->setValue(QSTR_AUDIODRIVER, audioDriver);
348  settings->setValue(QSTR_BUFFERTIME, bufferTime);
349  settings->setValue(QSTR_PERIODSIZE, periodSize);
350  settings->setValue(QSTR_PERIODS, periods);
351  settings->setValue(QSTR_SAMPLERATE, sampleRate);
352  settings->setValue(QSTR_CHORUS, chorus);
353  settings->setValue(QSTR_REVERB, reverb);
354  settings->setValue(QSTR_GAIN, gain);
355  settings->setValue(QSTR_POLYPHONY, polyphony);
356  settings->setValue(QSTR_CHORUS_DEPTH, chorus_depth);
357  settings->setValue(QSTR_CHORUS_LEVEL, chorus_level);
358  settings->setValue(QSTR_CHORUS_NR, chorus_nr);
359  settings->setValue(QSTR_CHORUS_SPEED, chorus_speed);
360  settings->setValue(QSTR_REVERB_DAMP, reverb_damp);
361  settings->setValue(QSTR_REVERB_LEVEL, reverb_level);
362  settings->setValue(QSTR_REVERB_SIZE, reverb_size);
363  settings->setValue(QSTR_REVERB_WIDTH, reverb_width);
364  settings->endGroup();
365  settings->sync();
366 
367  chkDriverProperties(settings.getQSettings());
368 }
369 
370 void FluidSettingsDialog::restoreDefaults()
371 {
372  ui->audioDriver->setCurrentText(defaultAudioDriver());
373  ui->bufferTime->setValue(DEFAULT_BUFFERTIME);
374  ui->periodSize->setValue(DEFAULT_PERIODSIZE);
375  ui->periods->setValue(DEFAULT_PERIODS);
376  ui->sampleRate->setCurrentText(QString::number(DEFAULT_SAMPLERATE));
377  ui->gain->setValue(DEFAULT_GAIN);
378  ui->polyphony->setValue(DEFAULT_POLYPHONY);
379  ui->soundFont->setText(m_defSoundFont);
380  ui->chorus_depth->setValue(DEFAULT_CHORUS_DEPTH * CHORUS_REVERB_VALUE_SCALE);
381  ui->chorus_level->setValue(DEFAULT_CHORUS_LEVEL * CHORUS_REVERB_VALUE_SCALE);
382  ui->chorus_nr->setValue(DEFAULT_CHORUS_NR);
383  ui->chorus_speed->setValue(DEFAULT_CHORUS_SPEED * CHORUS_REVERB_VALUE_SCALE);
384  ui->reverb_damp->setValue(DEFAULT_REVERB_DAMP * CHORUS_REVERB_VALUE_SCALE);
385  ui->reverb_level->setValue(DEFAULT_REVERB_LEVEL * CHORUS_REVERB_VALUE_SCALE);
386  ui->reverb_size->setValue(DEFAULT_REVERB_SIZE * CHORUS_REVERB_VALUE_SCALE);
387  ui->reverb_width->setValue(DEFAULT_REVERB_WIDTH * CHORUS_REVERB_VALUE_SCALE);
388  ui->chorus->setChecked(DEFAULT_CHORUS != 0);
389  ui->reverb->setChecked(DEFAULT_REVERB != 0);
390  initBuffer();
391 }
392 
393 void FluidSettingsDialog::showFileDialog()
394 {
395  QDir dir(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QSTR_DATADIR, QStandardPaths::LocateDirectory));
396  if (!dir.exists()) {
397  dir = QDir(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QSTR_DATADIR2, QStandardPaths::LocateDirectory));
398  }
399  QStringList fileNames
400  = QFileDialog::getOpenFileNames(this,
401  tr("Select SoundFont"),
402  dir.absolutePath(),
403  tr("SoundFont Files (*.sf2 *.sf3 *.dls)"));
404  if (!fileNames.isEmpty()) {
405  ui->soundFont->setText(fileNames.join(';'));
406  }
407 }
408 
409 void FluidSettingsDialog::audioDriverChanged(const QString &text)
410 {
411  if ((text == QSTR_PULSEAUDIO) && driverVersionLessThan_2_2_8()) {
412  ui->bufferTime->setDisabled(false);
413  ui->bufferTime->blockSignals(false);
414  ui->periodSize->setDisabled(true);
415  ui->periodSize->blockSignals(true);
416  ui->periods->setVisible(false);
417  ui->periods->setDisabled(true);
418  ui->periods->blockSignals(true);
419  } else {
420  ui->bufferTime->setDisabled(true);
421  ui->bufferTime->blockSignals(true);
422  ui->periodSize->setDisabled(false);
423  ui->periodSize->blockSignals(false);
424  ui->periods->setVisible(true);
425  ui->periods->setDisabled(false);
426  ui->periods->blockSignals(false);
427  }
428  initBuffer();
429 }
430 
431 void FluidSettingsDialog::bufferTimeChanged(int value)
432 {
433  double rate = ui->sampleRate->currentText().toDouble();
434  int size = qRound( value * rate / 1000.0 );
435  ui->periodSize->setValue( size );
436  ui->periods->setValue( ui->periods->minimum() );
437 }
438 
439 void FluidSettingsDialog::bufferSizeChanged()
440 {
441  QString audioDriver = ui->audioDriver->currentText();
442  double rate = ui->sampleRate->currentText().toDouble();
443  int size = ui->periodSize->value();
444  if ((audioDriver != QSTR_PULSEAUDIO) || !driverVersionLessThan_2_2_8()) {
445  size *= ui->periods->value();
446  }
447  int ms = qRound( 1000.0 * size / rate );
448  ui->bufferTime->setValue(ms);
449 }
450 
451 void FluidSettingsDialog::changeSoundFont(const QString& fileName)
452 {
453  readSettings();
454  ui->soundFont->setText(fileName);
455  writeSettings();
456 }
457 
458 } // namespace widgets
459 } // namespace drumstick
QPair< QString, QVariant > MIDIConnection
MIDIConnection represents a connection identifier.
Definition: rtmidioutput.h:116
The QSettings class provides persistent platform-independent application settings.
The BackendManager class manages lists of dynamic and static backends for applications based on drums...
virtual void close()=0
close the MIDI port
void DRUMSTICK_WIDGETS_EXPORT changeSoundFont(const QString driver, const QString fileName, QWidget *parent=nullptr)
Changes the sound font configuration Some RT output drivers accept soundfonts.
BackendManager class declaration.
Drumstick common.
Definition: alsaclient.cpp:71
Declaration of the Fluidsynth configuration dialog.
MIDIOutput * outputBackendByName(const QString name)
outputBackendByName
SettingsFactory class declaration.