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