drumstick 2.9.0
C++ MIDI libraries using Qt objects, idioms, and style.
fluidsettingsdialog.cpp
Go to the documentation of this file.
1/*
2 Drumstick MIDI Sequencer C++ library
3 Copyright (C) 2006-2023, 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 <QPushButton>
23#include <QStandardPaths>
24#include <QToolButton>
25#include <QMessageBox>
26#include <QVersionNumber>
27
28#include "fluidsettingsdialog.h"
29#include "ui_fluidsettingsdialog.h"
32
38namespace drumstick { namespace widgets {
39
40const QString FluidSettingsDialog::QSTR_PREFERENCES = QStringLiteral("FluidSynth");
41const QString FluidSettingsDialog::QSTR_INSTRUMENTSDEFINITION = QStringLiteral("InstrumentsDefinition");
42const QString FluidSettingsDialog::QSTR_DATADIR = QStringLiteral("soundfonts");
43const QString FluidSettingsDialog::QSTR_DATADIR2 = QStringLiteral("sounds/sf2");
44const QString FluidSettingsDialog::QSTR_AUDIODRIVER = QStringLiteral("AudioDriver");
45const QString FluidSettingsDialog::QSTR_PERIODSIZE = QStringLiteral("PeriodSize");
46const QString FluidSettingsDialog::QSTR_PERIODS = QStringLiteral("Periods");
47const QString FluidSettingsDialog::QSTR_SAMPLERATE = QStringLiteral("SampleRate");
48const QString FluidSettingsDialog::QSTR_CHORUS = QStringLiteral("Chorus");
49const QString FluidSettingsDialog::QSTR_REVERB = QStringLiteral("Reverb");
50const QString FluidSettingsDialog::QSTR_GAIN = QStringLiteral("Gain");
51const QString FluidSettingsDialog::QSTR_POLYPHONY = QStringLiteral("Polyphony");
52const QString FluidSettingsDialog::QSTR_BUFFERTIME = QStringLiteral("BufferTime");
53const QString FluidSettingsDialog::QSTR_PULSEAUDIO = QStringLiteral("pulseaudio");
54
55FluidSettingsDialog::FluidSettingsDialog(QWidget *parent) :
56 QDialog(parent),
57 ui(new Ui::FluidSettingsDialog)
58{
59 ui->setupUi(this);
60 connect(ui->audioDriver, &QComboBox::currentTextChanged, this, &FluidSettingsDialog::audioDriverChanged);
61 connect(ui->bufferTime, QOverload<int>::of(&QSpinBox::valueChanged), this, &FluidSettingsDialog::bufferTimeChanged);
62 connect(ui->periodSize, QOverload<int>::of(&QSpinBox::valueChanged), this, &FluidSettingsDialog::bufferSizeChanged);
63 connect(ui->periods, QOverload<int>::of(&QSpinBox::valueChanged), this, &FluidSettingsDialog::bufferSizeChanged);
64 connect(ui->btnFile, &QToolButton::clicked, this, &FluidSettingsDialog::showFileDialog);
65 connect(ui->buttonBox->button(QDialogButtonBox::RestoreDefaults), &QPushButton::clicked,
66 this, &FluidSettingsDialog::restoreDefaults);
67 auto sampleRateValidator = new QDoubleValidator(8000.0, 96000.0, 1, this);
68 sampleRateValidator->setNotation(QDoubleValidator::StandardNotation);
69 sampleRateValidator->setLocale(QLocale::c());
70 ui->sampleRate->setValidator(sampleRateValidator);
71 auto gainValidator = new QDoubleValidator(0.1, 10.0, 2, this);
72 gainValidator->setNotation(QDoubleValidator::StandardNotation);
73 gainValidator->setLocale(QLocale::c());
74 ui->gain->setValidator(gainValidator);
75 auto polyphonyValidator = new QIntValidator(1, 65535, this);
76 ui->polyphony->setValidator(polyphonyValidator);
77
79 m_driver = man.outputBackendByName("FluidSynth");
80 if (m_driver != nullptr) {
81 QVariant v = m_driver->property("audiodrivers");
82 if (v.isValid()) {
83 ui->audioDriver->blockSignals(true);
84 ui->audioDriver->clear();
85 ui->audioDriver->addItems(v.toStringList());
86 ui->audioDriver->blockSignals(false);
87 }
88 v = m_driver->property("soundfont");
89 if (v.isValid()) {
90 m_defSoundFont = v.toString();
91 }
92 }
93 ui->bufferTime->blockSignals(true);
94 ui->periodSize->blockSignals(true);
95 ui->periods->blockSignals(true);
96 //qDebug() << Q_FUNC_INFO;
97}
98
99FluidSettingsDialog::~FluidSettingsDialog()
100{
101 //qDebug() << Q_FUNC_INFO;
102 if (m_driver != nullptr) {
103 m_driver->close();
104 }
105 delete ui;
106}
107
108bool FluidSettingsDialog::checkRanges() const
109{
110 //qDebug() << Q_FUNC_INFO;
111 if (ui->gain->hasAcceptableInput()) {
112 ui->gain->deselect();
113 } else {
114 ui->gain->selectAll();
115 }
116 if (ui->polyphony->hasAcceptableInput()) {
117 ui->polyphony->deselect();
118 } else {
119 ui->polyphony->selectAll();
120 }
121 if (ui->sampleRate->hasAcceptableInput()) {
122 ui->sampleRate->deselect();
123 } else {
124 ui->sampleRate->selectAll();
125 }
126 return
127 ui->bufferTime->hasAcceptableInput() &&
128 ui->periodSize->hasAcceptableInput() &&
129 ui->periods->hasAcceptableInput() &&
130 ui->gain->hasAcceptableInput() &&
131 ui->polyphony->hasAcceptableInput() &&
132 ui->sampleRate->hasAcceptableInput();
133}
134
135void FluidSettingsDialog::accept()
136{
137 //qDebug() << Q_FUNC_INFO;
138 if (checkRanges()) {
139 writeSettings();
140 if (m_driver != nullptr) {
141 QString title;
142 QVariant varStatus = m_driver->property("status");
143 if (varStatus.isValid()) {
144 title = varStatus.toBool() ? tr("FluidSynth Initialized") : tr("FluidSynth Initialization Failed");
145 QVariant varDiag = m_driver->property("diagnostics");
146 if (varDiag.isValid()) {
147 QString text = varDiag.toStringList().join(QChar::LineFeed).trimmed();
148 if (varStatus.toBool()) {
149 if (!text.isEmpty()) {
150 QMessageBox::information(this, title, text);
151 }
152 } else {
153 QMessageBox::critical(this, title, text);
154 return;
155 }
156 }
157 }
158 }
159 QDialog::accept();
160 }
161}
162
163void FluidSettingsDialog::showEvent(QShowEvent *event)
164{
165 readSettings();
166 event->accept();
167}
168
169QString FluidSettingsDialog::defaultAudioDriver() const
170{
171 const QString QSTR_DEFAULT_AUDIODRIVER =
172#if defined(Q_OS_WIN)
173 QLatin1String("wasapi");
174#elif defined(Q_OS_OSX)
175 QLatin1String("coreaudio");
176#elif defined(Q_OS_LINUX)
177 QSTR_PULSEAUDIO;
178#else
179 QLatin1String("oss");
180#endif
181 return QSTR_DEFAULT_AUDIODRIVER;
182}
183
184void FluidSettingsDialog::chkDriverProperties(QSettings *settings)
185{
186 //qDebug() << Q_FUNC_INFO;
187 if (m_driver != nullptr) {
189 m_driver->close();
190 m_driver->initialize(settings);
191 m_driver->open(conn);
192
193 QVariant drivers = m_driver->property("audiodrivers");
194 if (drivers.isValid()) {
195 auto text = ui->audioDriver->currentText();
196 ui->audioDriver->blockSignals(true);
197 ui->audioDriver->clear();
198 ui->audioDriver->addItems(drivers.toStringList());
199 ui->audioDriver->setCurrentText(text);
200 ui->audioDriver->blockSignals(false);
201 }
202 ui->lblVersion->clear();
203 ui->lblVersion->setText(driverVersion());
204 QVariant varStatus = m_driver->property("status");
205 if (varStatus.isValid()) {
206 ui->lblStatus->clear();
207 ui->lblStatus->setText(varStatus.toBool() ? tr("Ready") : tr("Failed") );
208 ui->lblStatusIcon->setPixmap(varStatus.toBool() ? QPixmap(":/checked.png") : QPixmap(":/error.png") );
209 }
210 }
211}
212
213void drumstick::widgets::FluidSettingsDialog::initBuffer()
214{
215 if ((ui->audioDriver->currentText() == QSTR_PULSEAUDIO) && driverVersionLessThan_2_2_8()) {
216 //qDebug() << Q_FUNC_INFO << QSTR_PULSEAUDIO << driverVersion();
217 int bufferTime = ui->bufferTime->value();
218 int minBufTime = ui->bufferTime->minimum();
219 if (bufferTime < minBufTime) {
220 bufferTime = minBufTime;
221 }
222 ui->bufferTime->setValue( bufferTime );
223 bufferTimeChanged( bufferTime );
224 } else {
225 //qDebug() << Q_FUNC_INFO;
226 bufferSizeChanged();
227 }
228}
229
230QString FluidSettingsDialog::driverVersion() const
231{
232 static QString result;
233 if (m_driver != nullptr && result.isEmpty()) {
234 QVariant varVersion = m_driver->property("libversion");
235 if (varVersion.isValid()) {
236 result = varVersion.toString();
237 }
238 }
239 return result;
240}
241
242bool FluidSettingsDialog::driverVersionLessThan_2_2_8()
243{
244 static const QVersionNumber check_2_2_8(2, 2, 8);
245 QVersionNumber driverV = QVersionNumber::fromString(driverVersion());
246 return driverV < check_2_2_8;
247}
248
249void FluidSettingsDialog::readSettings()
250{
251 //qDebug() << Q_FUNC_INFO;
252 SettingsFactory settings;
253 settings->beginGroup(QSTR_PREFERENCES);
254 ui->audioDriver->setCurrentText( settings->value(QSTR_AUDIODRIVER, defaultAudioDriver()).toString() );
255 ui->bufferTime->setValue( settings->value(QSTR_BUFFERTIME, DEFAULT_BUFFERTIME).toInt() );
256 ui->periodSize->setValue( settings->value(QSTR_PERIODSIZE, DEFAULT_PERIODSIZE).toInt() );
257 ui->periods->setValue( settings->value(QSTR_PERIODS, DEFAULT_PERIODS).toInt() );
258 ui->sampleRate->setText( settings->value(QSTR_SAMPLERATE, DEFAULT_SAMPLERATE).toString() );
259 ui->chorus->setChecked( settings->value(QSTR_CHORUS, DEFAULT_CHORUS).toInt() != 0 );
260 ui->reverb->setChecked( settings->value(QSTR_REVERB, DEFAULT_REVERB).toInt() != 0 );
261 ui->gain->setText( settings->value(QSTR_GAIN, DEFAULT_GAIN).toString() );
262 ui->polyphony->setText( settings->value(QSTR_POLYPHONY, DEFAULT_POLYPHONY).toString() );
263 ui->soundFont->setText( settings->value(QSTR_INSTRUMENTSDEFINITION, m_defSoundFont).toString() );
264 settings->endGroup();
265
266 audioDriverChanged( ui->audioDriver->currentText() );
267 chkDriverProperties(settings.getQSettings());
268}
269
270void FluidSettingsDialog::writeSettings()
271{
272 //qDebug() << Q_FUNC_INFO;
273 SettingsFactory settings;
274 QString audioDriver;
275 QString soundFont(m_defSoundFont);
276 int bufferTime(DEFAULT_BUFFERTIME);
277 int periodSize(DEFAULT_PERIODSIZE);
278 int periods(DEFAULT_PERIODS);
279 double sampleRate(DEFAULT_SAMPLERATE);
280 int chorus(DEFAULT_CHORUS);
281 int reverb(DEFAULT_REVERB);
282 double gain(DEFAULT_GAIN);
283 int polyphony(DEFAULT_POLYPHONY);
284
285 audioDriver = ui->audioDriver->currentText();
286 if (audioDriver.isEmpty()) {
287 audioDriver = defaultAudioDriver();
288 }
289 soundFont = ui->soundFont->text();
290 bufferTime = ui->bufferTime->value();
291 periodSize = ui->periodSize->value();
292 periods = ui->periods->value();
293 sampleRate = ui->sampleRate->text().toDouble();
294 chorus = (ui->chorus->isChecked() ? 1 : 0);
295 reverb = (ui->reverb->isChecked() ? 1 : 0);
296 gain = ui->gain->text().toDouble();
297 polyphony = ui->polyphony->text().toInt();
298
299 settings->beginGroup(QSTR_PREFERENCES);
300 settings->setValue(QSTR_INSTRUMENTSDEFINITION, soundFont);
301 settings->setValue(QSTR_AUDIODRIVER, audioDriver);
302 settings->setValue(QSTR_BUFFERTIME, bufferTime);
303 settings->setValue(QSTR_PERIODSIZE, periodSize);
304 settings->setValue(QSTR_PERIODS, periods);
305 settings->setValue(QSTR_SAMPLERATE, sampleRate);
306 settings->setValue(QSTR_CHORUS, chorus);
307 settings->setValue(QSTR_REVERB, reverb);
308 settings->setValue(QSTR_GAIN, gain);
309 settings->setValue(QSTR_POLYPHONY, polyphony);
310 settings->endGroup();
311 settings->sync();
312
313 chkDriverProperties(settings.getQSettings());
314}
315
316void FluidSettingsDialog::restoreDefaults()
317{
318 //qDebug() << Q_FUNC_INFO;
319 ui->audioDriver->setCurrentText( defaultAudioDriver() );
320 ui->bufferTime->setValue( DEFAULT_BUFFERTIME );
321 ui->periodSize->setValue( DEFAULT_PERIODSIZE );
322 ui->periods->setValue( DEFAULT_PERIODS );
323 ui->sampleRate->setText( QString::number( DEFAULT_SAMPLERATE ));
324 ui->chorus->setChecked( DEFAULT_CHORUS != 0 );
325 ui->reverb->setChecked( DEFAULT_REVERB != 0 );
326 ui->gain->setText( QString::number( DEFAULT_GAIN ) );
327 ui->polyphony->setText( QString::number( DEFAULT_POLYPHONY ));
328 ui->soundFont->setText( m_defSoundFont );
329 initBuffer();
330}
331
332void FluidSettingsDialog::showFileDialog()
333{
334 QDir dir(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QSTR_DATADIR, QStandardPaths::LocateDirectory));
335 if (!dir.exists()) {
336 dir = QDir(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QSTR_DATADIR2, QStandardPaths::LocateDirectory));
337 }
338 QString fileName = QFileDialog::getOpenFileName(this, tr("Select SoundFont"), dir.absolutePath(), tr("SoundFont Files (*.sf2 *.sf3 *.dls)"));
339 if (!fileName.isEmpty()) {
340 ui->soundFont->setText(fileName);
341 }
342}
343
344void FluidSettingsDialog::audioDriverChanged(const QString &text)
345{
346 //qDebug() << Q_FUNC_INFO << text;
347 if ((text == QSTR_PULSEAUDIO) && driverVersionLessThan_2_2_8()) {
348 ui->bufferTime->setDisabled(false);
349 ui->bufferTime->blockSignals(false);
350 ui->periodSize->setDisabled(true);
351 ui->periodSize->blockSignals(true);
352 ui->periods->setVisible(false);
353 ui->periods->setDisabled(true);
354 ui->periods->blockSignals(true);
355 } else {
356 ui->bufferTime->setDisabled(true);
357 ui->bufferTime->blockSignals(true);
358 ui->periodSize->setDisabled(false);
359 ui->periodSize->blockSignals(false);
360 ui->periods->setVisible(true);
361 ui->periods->setDisabled(false);
362 ui->periods->blockSignals(false);
363 }
364 initBuffer();
365}
366
367void FluidSettingsDialog::bufferTimeChanged(int value)
368{
369 double rate = ui->sampleRate->text().toDouble();
370 int size = qRound( value * rate / 1000.0 );
371 ui->periodSize->setValue( size );
372 ui->periods->setValue( ui->periods->minimum() );
373 //qDebug() << Q_FUNC_INFO << "time:" << value << "rate:" << rate << "size:" << size;
374}
375
376void FluidSettingsDialog::bufferSizeChanged()
377{
378 QString audioDriver = ui->audioDriver->currentText();
379 double rate = ui->sampleRate->text().toDouble();
380 int size = ui->periodSize->value();
381 if ((audioDriver != QSTR_PULSEAUDIO) || !driverVersionLessThan_2_2_8()) {
382 size *= ui->periods->value();
383 }
384 int ms = qRound( 1000.0 * size / rate );
385 ui->bufferTime->setValue(ms);
386 //qDebug() << Q_FUNC_INFO << "time:" << ms << "rate:" << rate << "size:" << size;
387}
388
389void FluidSettingsDialog::changeSoundFont(const QString& fileName)
390{
391 readSettings();
392 ui->soundFont->setText(fileName);
393 writeSettings();
394}
395
396} // namespace widgets
397} // namespace drumstick
BackendManager class declaration.
The QSettings class provides persistent platform-independent application settings.
The BackendManager class manages lists of dynamic and static backends for applications based on drums...
MIDIOutput * outputBackendByName(const QString name)
outputBackendByName
virtual void close()=0
close the MIDI port
Declaration of the Fluidsynth configuration dialog.
QPair< QString, QVariant > MIDIConnection
MIDIConnection represents a connection identifier.
Definition: rtmidioutput.h:116
Drumstick common.
Definition: alsaclient.cpp:68
SettingsFactory class declaration.