drumstick  2.9.1
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  auto sampleRateValidator = new QDoubleValidator(8000.0, 96000.0, 1, this);
77  sampleRateValidator->setNotation(QDoubleValidator::StandardNotation);
78  sampleRateValidator->setLocale(QLocale::c());
79  ui->sampleRate->setValidator(sampleRateValidator);
80  auto gainValidator = new QDoubleValidator(0.1, 10.0, 2, this);
81  gainValidator->setNotation(QDoubleValidator::StandardNotation);
82  gainValidator->setLocale(QLocale::c());
83  ui->gain->setValidator(gainValidator);
84  auto polyphonyValidator = new QIntValidator(1, 65535, this);
85  ui->polyphony->setValidator(polyphonyValidator);
86  connect(ui->chorus_depth, &QAbstractSlider::valueChanged, this, [=](int val) {
87  setWidgetTip(ui->chorus_depth, QString::number(val / 10.0));
88  });
89  connect(ui->chorus_level, &QAbstractSlider::valueChanged, this, [=](int val) {
90  setWidgetTip(ui->chorus_level, QString::number(val / 10.0));
91  });
92  connect(ui->chorus_nr, &QAbstractSlider::valueChanged, this, [=](int val) {
93  setWidgetTip(ui->chorus_nr, QString::number(val));
94  });
95  connect(ui->chorus_speed, &QAbstractSlider::valueChanged, this, [=](int val) {
96  setWidgetTip(ui->chorus_speed, QString::number(val / 10.0));
97  });
98 
99  connect(ui->reverb_damp, &QAbstractSlider::valueChanged, this, [=](int val) {
100  setWidgetTip(ui->reverb_damp, QString::number(val / 10.0));
101  });
102  connect(ui->reverb_level, &QAbstractSlider::valueChanged, this, [=](int val) {
103  setWidgetTip(ui->reverb_level, QString::number(val / 10.0));
104  });
105  connect(ui->reverb_size, &QAbstractSlider::valueChanged, this, [=](int val) {
106  setWidgetTip(ui->reverb_size, QString::number(val / 10.0));
107  });
108  connect(ui->reverb_width, &QAbstractSlider::valueChanged, this, [=](int val) {
109  setWidgetTip(ui->reverb_width, QString::number(val / 10.0));
110  });
111 
113  m_driver = man.outputBackendByName("FluidSynth");
114  if (m_driver != nullptr) {
115  QVariant v = m_driver->property("audiodrivers");
116  if (v.isValid()) {
117  ui->audioDriver->blockSignals(true);
118  ui->audioDriver->clear();
119  ui->audioDriver->addItems(v.toStringList());
120  ui->audioDriver->blockSignals(false);
121  }
122  v = m_driver->property("soundfont");
123  if (v.isValid()) {
124  m_defSoundFont = v.toString();
125  }
126  }
127  ui->bufferTime->blockSignals(true);
128  ui->periodSize->blockSignals(true);
129  ui->periods->blockSignals(true);
130  //qDebug() << Q_FUNC_INFO;
131 }
132 
133 FluidSettingsDialog::~FluidSettingsDialog()
134 {
135  //qDebug() << Q_FUNC_INFO;
136  if (m_driver != nullptr) {
137  m_driver->close();
138  }
139  delete ui;
140 }
141 
142 bool FluidSettingsDialog::checkRanges() const
143 {
144  //qDebug() << Q_FUNC_INFO;
145  if (ui->gain->hasAcceptableInput()) {
146  ui->gain->deselect();
147  } else {
148  ui->gain->selectAll();
149  }
150  if (ui->polyphony->hasAcceptableInput()) {
151  ui->polyphony->deselect();
152  } else {
153  ui->polyphony->selectAll();
154  }
155  if (ui->sampleRate->hasAcceptableInput()) {
156  ui->sampleRate->deselect();
157  } else {
158  ui->sampleRate->selectAll();
159  }
160  return
161  ui->bufferTime->hasAcceptableInput() &&
162  ui->periodSize->hasAcceptableInput() &&
163  ui->periods->hasAcceptableInput() &&
164  ui->gain->hasAcceptableInput() &&
165  ui->polyphony->hasAcceptableInput() &&
166  ui->sampleRate->hasAcceptableInput();
167 }
168 
169 void FluidSettingsDialog::accept()
170 {
171  //qDebug() << Q_FUNC_INFO;
172  if (checkRanges()) {
173  writeSettings();
174  if (m_driver != nullptr) {
175  QString title;
176  QVariant varStatus = m_driver->property("status");
177  if (varStatus.isValid()) {
178  title = varStatus.toBool() ? tr("FluidSynth Initialized") : tr("FluidSynth Initialization Failed");
179  QVariant varDiag = m_driver->property("diagnostics");
180  if (varDiag.isValid()) {
181  QString text = varDiag.toStringList().join(QChar::LineFeed).trimmed();
182  if (varStatus.toBool()) {
183  if (!text.isEmpty()) {
184  QMessageBox::information(this, title, text);
185  }
186  } else {
187  QMessageBox::critical(this, title, text);
188  return;
189  }
190  }
191  }
192  }
193  QDialog::accept();
194  }
195 }
196 
197 void FluidSettingsDialog::showEvent(QShowEvent *event)
198 {
199  readSettings();
200  event->accept();
201 }
202 
203 QString FluidSettingsDialog::defaultAudioDriver() const
204 {
205  const QString QSTR_DEFAULT_AUDIODRIVER =
206 #if defined(Q_OS_WIN)
207  QLatin1String("wasapi");
208 #elif defined(Q_OS_OSX)
209  QLatin1String("coreaudio");
210 #elif defined(Q_OS_LINUX)
211  QSTR_PULSEAUDIO;
212 #else
213  QLatin1String("oss");
214 #endif
215  return QSTR_DEFAULT_AUDIODRIVER;
216 }
217 
218 void FluidSettingsDialog::chkDriverProperties(QSettings *settings)
219 {
220  //qDebug() << Q_FUNC_INFO;
221  if (m_driver != nullptr) {
223  m_driver->close();
224  m_driver->initialize(settings);
225  m_driver->open(conn);
226 
227  QVariant drivers = m_driver->property("audiodrivers");
228  if (drivers.isValid()) {
229  auto text = ui->audioDriver->currentText();
230  ui->audioDriver->blockSignals(true);
231  ui->audioDriver->clear();
232  ui->audioDriver->addItems(drivers.toStringList());
233  ui->audioDriver->setCurrentText(text);
234  ui->audioDriver->blockSignals(false);
235  }
236  ui->lblVersion->clear();
237  ui->lblVersion->setText(driverVersion());
238  QVariant varStatus = m_driver->property("status");
239  if (varStatus.isValid()) {
240  ui->lblStatus->clear();
241  ui->lblStatus->setText(varStatus.toBool() ? tr("Ready") : tr("Failed") );
242  ui->lblStatusIcon->setPixmap(varStatus.toBool() ? QPixmap(":/checked.png") : QPixmap(":/error.png") );
243  }
244  }
245 }
246 
247 void FluidSettingsDialog::setWidgetTip(QWidget *w, const QString &tip)
248 {
249  w->setToolTip(tip);
250  QToolTip::showText(w->parentWidget()->mapToGlobal(w->pos()), tip);
251 }
252 
253 void drumstick::widgets::FluidSettingsDialog::initBuffer()
254 {
255  if ((ui->audioDriver->currentText() == QSTR_PULSEAUDIO) && driverVersionLessThan_2_2_8()) {
256  //qDebug() << Q_FUNC_INFO << QSTR_PULSEAUDIO << driverVersion();
257  int bufferTime = ui->bufferTime->value();
258  int minBufTime = ui->bufferTime->minimum();
259  if (bufferTime < minBufTime) {
260  bufferTime = minBufTime;
261  }
262  ui->bufferTime->setValue( bufferTime );
263  bufferTimeChanged( bufferTime );
264  } else {
265  //qDebug() << Q_FUNC_INFO;
266  bufferSizeChanged();
267  }
268 }
269 
270 QString FluidSettingsDialog::driverVersion() const
271 {
272  static QString result;
273  if (m_driver != nullptr && result.isEmpty()) {
274  QVariant varVersion = m_driver->property("libversion");
275  if (varVersion.isValid()) {
276  result = varVersion.toString();
277  }
278  }
279  return result;
280 }
281 
282 bool FluidSettingsDialog::driverVersionLessThan_2_2_8()
283 {
284  static const QVersionNumber check_2_2_8(2, 2, 8);
285  QVersionNumber driverV = QVersionNumber::fromString(driverVersion());
286  return driverV < check_2_2_8;
287 }
288 
289 void FluidSettingsDialog::readSettings()
290 {
291  //qDebug() << Q_FUNC_INFO;
292  SettingsFactory settings;
293  settings->beginGroup(QSTR_PREFERENCES);
294  ui->audioDriver->setCurrentText( settings->value(QSTR_AUDIODRIVER, defaultAudioDriver()).toString() );
295  ui->bufferTime->setValue( settings->value(QSTR_BUFFERTIME, DEFAULT_BUFFERTIME).toInt() );
296  ui->periodSize->setValue( settings->value(QSTR_PERIODSIZE, DEFAULT_PERIODSIZE).toInt() );
297  ui->periods->setValue( settings->value(QSTR_PERIODS, DEFAULT_PERIODS).toInt() );
298  ui->sampleRate->setText( settings->value(QSTR_SAMPLERATE, DEFAULT_SAMPLERATE).toString() );
299  ui->gain->setText( settings->value(QSTR_GAIN, DEFAULT_GAIN).toString() );
300  ui->polyphony->setText( settings->value(QSTR_POLYPHONY, DEFAULT_POLYPHONY).toString() );
301  ui->soundFont->setText( settings->value(QSTR_INSTRUMENTSDEFINITION, m_defSoundFont).toString() );
302 
303  ui->chorus_depth->setValue(settings->value(QSTR_CHORUS_DEPTH, DEFAULT_CHORUS_DEPTH).toFloat()
304  * 10);
305  ui->chorus_level->setValue(settings->value(QSTR_CHORUS_LEVEL, DEFAULT_CHORUS_LEVEL).toFloat()
306  * 10);
307  ui->chorus_nr->setValue(settings->value(QSTR_CHORUS_NR, DEFAULT_CHORUS_NR).toInt());
308  ui->chorus_speed->setValue(settings->value(QSTR_CHORUS_SPEED, DEFAULT_CHORUS_SPEED).toFloat()
309  * 10);
310 
311  ui->reverb_damp->setValue(settings->value(QSTR_REVERB_DAMP, DEFAULT_REVERB_DAMP).toFloat() * 10);
312  ui->reverb_level->setValue(settings->value(QSTR_REVERB_LEVEL, DEFAULT_REVERB_LEVEL).toFloat()
313  * 10);
314  ui->reverb_size->setValue(settings->value(QSTR_REVERB_SIZE, DEFAULT_REVERB_SIZE).toFloat() * 10);
315  ui->reverb_width->setValue(settings->value(QSTR_REVERB_WIDTH, DEFAULT_REVERB_WIDTH).toFloat()
316  * 10);
317 
318  ui->chorus->setChecked(settings->value(QSTR_CHORUS, DEFAULT_CHORUS).toInt() != 0);
319  ui->reverb->setChecked(settings->value(QSTR_REVERB, DEFAULT_REVERB).toInt() != 0);
320 
321  settings->endGroup();
322 
323  audioDriverChanged( ui->audioDriver->currentText() );
324  chkDriverProperties(settings.getQSettings());
325 }
326 
327 void FluidSettingsDialog::writeSettings()
328 {
329  //qDebug() << Q_FUNC_INFO;
330  SettingsFactory settings;
331  QString audioDriver;
332  QString soundFont(m_defSoundFont);
333  int bufferTime(DEFAULT_BUFFERTIME);
334  int periodSize(DEFAULT_PERIODSIZE);
335  int periods(DEFAULT_PERIODS);
336  double sampleRate(DEFAULT_SAMPLERATE);
337  int chorus(DEFAULT_CHORUS);
338  int reverb(DEFAULT_REVERB);
339  double gain(DEFAULT_GAIN);
340  int polyphony(DEFAULT_POLYPHONY);
341 
342  double chorus_depth(DEFAULT_CHORUS_DEPTH);
343  double chorus_level(DEFAULT_CHORUS_LEVEL);
344  int chorus_nr(DEFAULT_CHORUS_NR);
345  double chorus_speed(DEFAULT_CHORUS_SPEED);
346 
347  double reverb_damp(DEFAULT_REVERB_DAMP);
348  double reverb_level(DEFAULT_REVERB_LEVEL);
349  double reverb_size(DEFAULT_REVERB_SIZE);
350  double reverb_width(DEFAULT_REVERB_WIDTH);
351 
352  audioDriver = ui->audioDriver->currentText();
353  if (audioDriver.isEmpty()) {
354  audioDriver = defaultAudioDriver();
355  }
356  soundFont = ui->soundFont->text();
357  bufferTime = ui->bufferTime->value();
358  periodSize = ui->periodSize->value();
359  periods = ui->periods->value();
360  sampleRate = ui->sampleRate->text().toDouble();
361  chorus = (ui->chorus->isChecked() ? 1 : 0);
362  reverb = (ui->reverb->isChecked() ? 1 : 0);
363  gain = ui->gain->text().toDouble();
364  polyphony = ui->polyphony->text().toInt();
365 
366  chorus_depth = ui->chorus_depth->value() / 10.0;
367  chorus_level = ui->chorus_level->value() / 10.0;
368  chorus_nr = ui->chorus_nr->value();
369  chorus_speed = ui->chorus_speed->value() / 10.0;
370  reverb_damp = ui->reverb_damp->value() / 10.0;
371  reverb_level = ui->reverb_level->value() / 10.0;
372  reverb_size = ui->reverb_size->value() / 10.0;
373  reverb_width = ui->reverb_width->value() / 10.0;
374 
375  settings->beginGroup(QSTR_PREFERENCES);
376  settings->setValue(QSTR_INSTRUMENTSDEFINITION, soundFont);
377  settings->setValue(QSTR_AUDIODRIVER, audioDriver);
378  settings->setValue(QSTR_BUFFERTIME, bufferTime);
379  settings->setValue(QSTR_PERIODSIZE, periodSize);
380  settings->setValue(QSTR_PERIODS, periods);
381  settings->setValue(QSTR_SAMPLERATE, sampleRate);
382  settings->setValue(QSTR_CHORUS, chorus);
383  settings->setValue(QSTR_REVERB, reverb);
384  settings->setValue(QSTR_GAIN, gain);
385  settings->setValue(QSTR_POLYPHONY, polyphony);
386  settings->setValue(QSTR_CHORUS_DEPTH, chorus_depth);
387  settings->setValue(QSTR_CHORUS_LEVEL, chorus_level);
388  settings->setValue(QSTR_CHORUS_NR, chorus_nr);
389  settings->setValue(QSTR_CHORUS_SPEED, chorus_speed);
390  settings->setValue(QSTR_REVERB_DAMP, reverb_damp);
391  settings->setValue(QSTR_REVERB_LEVEL, reverb_level);
392  settings->setValue(QSTR_REVERB_SIZE, reverb_size);
393  settings->setValue(QSTR_REVERB_WIDTH, reverb_width);
394  settings->endGroup();
395  settings->sync();
396 
397  chkDriverProperties(settings.getQSettings());
398 }
399 
400 void FluidSettingsDialog::restoreDefaults()
401 {
402  //qDebug() << Q_FUNC_INFO;
403  ui->audioDriver->setCurrentText(defaultAudioDriver());
404  ui->bufferTime->setValue(DEFAULT_BUFFERTIME);
405  ui->periodSize->setValue(DEFAULT_PERIODSIZE);
406  ui->periods->setValue(DEFAULT_PERIODS);
407  ui->sampleRate->setText(QString::number(DEFAULT_SAMPLERATE));
408  ui->gain->setText(QString::number(DEFAULT_GAIN));
409  ui->polyphony->setText(QString::number(DEFAULT_POLYPHONY));
410  ui->soundFont->setText(m_defSoundFont);
411  ui->chorus_depth->setValue(DEFAULT_CHORUS_DEPTH * 10);
412  ui->chorus_level->setValue(DEFAULT_CHORUS_LEVEL * 10);
413  ui->chorus_nr->setValue(DEFAULT_CHORUS_NR);
414  ui->chorus_speed->setValue(DEFAULT_CHORUS_SPEED * 10);
415  ui->reverb_damp->setValue(DEFAULT_REVERB_DAMP * 10);
416  ui->reverb_level->setValue(DEFAULT_REVERB_LEVEL * 10);
417  ui->reverb_size->setValue(DEFAULT_REVERB_SIZE * 10);
418  ui->reverb_width->setValue(DEFAULT_REVERB_WIDTH * 10);
419  ui->chorus->setChecked(DEFAULT_CHORUS != 0);
420  ui->reverb->setChecked(DEFAULT_REVERB != 0);
421  initBuffer();
422 }
423 
424 void FluidSettingsDialog::showFileDialog()
425 {
426  QDir dir(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QSTR_DATADIR, QStandardPaths::LocateDirectory));
427  if (!dir.exists()) {
428  dir = QDir(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QSTR_DATADIR2, QStandardPaths::LocateDirectory));
429  }
430  QStringList fileNames
431  = QFileDialog::getOpenFileNames(this,
432  tr("Select SoundFont"),
433  dir.absolutePath(),
434  tr("SoundFont Files (*.sf2 *.sf3 *.dls)"));
435  if (!fileNames.isEmpty()) {
436  ui->soundFont->setText(fileNames.join(';'));
437  }
438 }
439 
440 void FluidSettingsDialog::audioDriverChanged(const QString &text)
441 {
442  //qDebug() << Q_FUNC_INFO << text;
443  if ((text == QSTR_PULSEAUDIO) && driverVersionLessThan_2_2_8()) {
444  ui->bufferTime->setDisabled(false);
445  ui->bufferTime->blockSignals(false);
446  ui->periodSize->setDisabled(true);
447  ui->periodSize->blockSignals(true);
448  ui->periods->setVisible(false);
449  ui->periods->setDisabled(true);
450  ui->periods->blockSignals(true);
451  } else {
452  ui->bufferTime->setDisabled(true);
453  ui->bufferTime->blockSignals(true);
454  ui->periodSize->setDisabled(false);
455  ui->periodSize->blockSignals(false);
456  ui->periods->setVisible(true);
457  ui->periods->setDisabled(false);
458  ui->periods->blockSignals(false);
459  }
460  initBuffer();
461 }
462 
463 void FluidSettingsDialog::bufferTimeChanged(int value)
464 {
465  double rate = ui->sampleRate->text().toDouble();
466  int size = qRound( value * rate / 1000.0 );
467  ui->periodSize->setValue( size );
468  ui->periods->setValue( ui->periods->minimum() );
469  //qDebug() << Q_FUNC_INFO << "time:" << value << "rate:" << rate << "size:" << size;
470 }
471 
472 void FluidSettingsDialog::bufferSizeChanged()
473 {
474  QString audioDriver = ui->audioDriver->currentText();
475  double rate = ui->sampleRate->text().toDouble();
476  int size = ui->periodSize->value();
477  if ((audioDriver != QSTR_PULSEAUDIO) || !driverVersionLessThan_2_2_8()) {
478  size *= ui->periods->value();
479  }
480  int ms = qRound( 1000.0 * size / rate );
481  ui->bufferTime->setValue(ms);
482  //qDebug() << Q_FUNC_INFO << "time:" << ms << "rate:" << rate << "size:" << size;
483 }
484 
485 void FluidSettingsDialog::changeSoundFont(const QString& fileName)
486 {
487  readSettings();
488  ui->soundFont->setText(fileName);
489  writeSettings();
490 }
491 
492 } // namespace widgets
493 } // 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:68
Declaration of the Fluidsynth configuration dialog.
MIDIOutput * outputBackendByName(const QString name)
outputBackendByName
SettingsFactory class declaration.