drumstick 2.6.1
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
27#include "fluidsettingsdialog.h"
28#include "ui_fluidsettingsdialog.h"
31
37namespace drumstick { namespace widgets {
38
39const QString FluidSettingsDialog::QSTR_PREFERENCES = QStringLiteral("FluidSynth");
40const QString FluidSettingsDialog::QSTR_INSTRUMENTSDEFINITION = QStringLiteral("InstrumentsDefinition");
41const QString FluidSettingsDialog::QSTR_DATADIR = QStringLiteral("soundfonts");
42const QString FluidSettingsDialog::QSTR_DATADIR2 = QStringLiteral("sounds/sf2");
43const QString FluidSettingsDialog::QSTR_SOUNDFONT = QStringLiteral("default.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 }
89 ui->bufferTime->blockSignals(true);
90 ui->periodSize->blockSignals(true);
91 ui->periods->blockSignals(true);
92 //qDebug() << Q_FUNC_INFO;
93}
94
95FluidSettingsDialog::~FluidSettingsDialog()
96{
97 //qDebug() << Q_FUNC_INFO;
98 if (m_driver != nullptr) {
99 m_driver->close();
100 }
101 delete ui;
102}
103
104bool FluidSettingsDialog::checkRanges() const
105{
106 //qDebug() << Q_FUNC_INFO;
107 if (ui->gain->hasAcceptableInput()) {
108 ui->gain->deselect();
109 } else {
110 ui->gain->selectAll();
111 }
112 if (ui->polyphony->hasAcceptableInput()) {
113 ui->polyphony->deselect();
114 } else {
115 ui->polyphony->selectAll();
116 }
117 if (ui->sampleRate->hasAcceptableInput()) {
118 ui->sampleRate->deselect();
119 } else {
120 ui->sampleRate->selectAll();
121 }
122 return
123 ui->bufferTime->hasAcceptableInput() &&
124 ui->periodSize->hasAcceptableInput() &&
125 ui->periods->hasAcceptableInput() &&
126 ui->gain->hasAcceptableInput() &&
127 ui->polyphony->hasAcceptableInput() &&
128 ui->sampleRate->hasAcceptableInput();
129}
130
131void FluidSettingsDialog::accept()
132{
133 //qDebug() << Q_FUNC_INFO;
134 if (checkRanges()) {
135 writeSettings();
136 if (m_driver != nullptr) {
137 QString title;
138 QVariant varStatus = m_driver->property("status");
139 if (varStatus.isValid()) {
140 title = varStatus.toBool() ? tr("FluidSynth Initialized") : tr("FluidSynth Initialization Failed");
141 QVariant varDiag = m_driver->property("diagnostics");
142 if (varDiag.isValid()) {
143 QString text = varDiag.toStringList().join(QChar::LineFeed).trimmed();
144 if (varStatus.toBool()) {
145 if (!text.isEmpty()) {
146 QMessageBox::information(this, title, text);
147 }
148 } else {
149 QMessageBox::critical(this, title, text);
150 return;
151 }
152 }
153 }
154 }
155 QDialog::accept();
156 }
157}
158
159void FluidSettingsDialog::showEvent(QShowEvent *event)
160{
161 readSettings();
162 event->accept();
163}
164
165QString FluidSettingsDialog::defaultAudioDriver() const
166{
167 const QString QSTR_DEFAULT_AUDIODRIVER =
168#if defined(Q_OS_WIN)
169 QLatin1String("wasapi");
170#elif defined(Q_OS_OSX)
171 QLatin1String("coreaudio");
172#elif defined(Q_OS_LINUX)
173 QSTR_PULSEAUDIO;
174#else
175 QLatin1String("oss");
176#endif
177 return QSTR_DEFAULT_AUDIODRIVER;
178}
179
180void FluidSettingsDialog::chkDriverProperties(QSettings *settings)
181{
182 //qDebug() << Q_FUNC_INFO;
183 if (m_driver != nullptr) {
185 m_driver->close();
186 m_driver->initialize(settings);
187 m_driver->open(conn);
188
189 QVariant drivers = m_driver->property("audiodrivers");
190 if (drivers.isValid()) {
191 auto text = ui->audioDriver->currentText();
192 ui->audioDriver->blockSignals(true);
193 ui->audioDriver->clear();
194 ui->audioDriver->addItems(drivers.toStringList());
195 ui->audioDriver->setCurrentText(text);
196 ui->audioDriver->blockSignals(false);
197 }
198 QVariant varVersion = m_driver->property("libversion");
199 if (varVersion.isValid()) {
200 ui->lblVersion->clear();
201 ui->lblVersion->setText(varVersion.toString());
202 }
203 QVariant varStatus = m_driver->property("status");
204 if (varStatus.isValid()) {
205 ui->lblStatus->clear();
206 ui->lblStatus->setText(varStatus.toBool() ? tr("Ready") : tr("Failed") );
207 ui->lblStatusIcon->setPixmap(varStatus.toBool() ? QPixmap(":/checked.png") : QPixmap(":/error.png") );
208 }
209 }
210}
211
212void drumstick::widgets::FluidSettingsDialog::initBuffer()
213{
214 if (ui->audioDriver->currentText() == QSTR_PULSEAUDIO) {
215 //qDebug() << Q_FUNC_INFO << QSTR_PULSEAUDIO;
216 int bufferTime = ui->bufferTime->value();
217 int minBufTime = ui->bufferTime->minimum();
218 if (qEnvironmentVariableIsSet("PULSE_LATENCY_MSEC")) {
219 bufferTime = qEnvironmentVariableIntValue("PULSE_LATENCY_MSEC");
220 }
221 if (bufferTime < minBufTime) {
222 bufferTime = minBufTime;
223 }
224 ui->bufferTime->setValue( bufferTime );
225 bufferTimeChanged( bufferTime );
226 } else {
227 //qDebug() << Q_FUNC_INFO;
228 bufferSizeChanged();
229 }
230}
231
232void FluidSettingsDialog::readSettings()
233{
234 //qDebug() << Q_FUNC_INFO;
235 SettingsFactory settings;
236 QString fs_defSoundFont = QSTR_SOUNDFONT;
237 QDir dir(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QSTR_DATADIR, QStandardPaths::LocateDirectory));
238 if (!dir.exists()) {
239 dir = QDir(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QSTR_DATADIR2, QStandardPaths::LocateDirectory));
240 }
241 QFileInfo sf2(dir, QSTR_SOUNDFONT);
242 if (sf2.exists()) {
243 fs_defSoundFont = sf2.absoluteFilePath();
244 }
245
246 settings->beginGroup(QSTR_PREFERENCES);
247 ui->audioDriver->setCurrentText( settings->value(QSTR_AUDIODRIVER, defaultAudioDriver()).toString() );
248 ui->bufferTime->setValue( settings->value(QSTR_BUFFERTIME, DEFAULT_BUFFERTIME).toInt() );
249 ui->periodSize->setValue( settings->value(QSTR_PERIODSIZE, DEFAULT_PERIODSIZE).toInt() );
250 ui->periods->setValue( settings->value(QSTR_PERIODS, DEFAULT_PERIODS).toInt() );
251 ui->sampleRate->setText( settings->value(QSTR_SAMPLERATE, DEFAULT_SAMPLERATE).toString() );
252 ui->chorus->setChecked( settings->value(QSTR_CHORUS, DEFAULT_CHORUS).toInt() != 0 );
253 ui->reverb->setChecked( settings->value(QSTR_REVERB, DEFAULT_REVERB).toInt() != 0 );
254 ui->gain->setText( settings->value(QSTR_GAIN, DEFAULT_GAIN).toString() );
255 ui->polyphony->setText( settings->value(QSTR_POLYPHONY, DEFAULT_POLYPHONY).toString() );
256 ui->soundFont->setText( settings->value(QSTR_INSTRUMENTSDEFINITION, fs_defSoundFont).toString() );
257 settings->endGroup();
258
259 audioDriverChanged( ui->audioDriver->currentText() );
260 chkDriverProperties(settings.getQSettings());
261}
262
263void FluidSettingsDialog::writeSettings()
264{
265 //qDebug() << Q_FUNC_INFO;
266 SettingsFactory settings;
267 QString audioDriver;
268 QString soundFont(QSTR_SOUNDFONT);
269 int bufferTime(DEFAULT_BUFFERTIME);
270 int periodSize(DEFAULT_PERIODSIZE);
271 int periods(DEFAULT_PERIODS);
272 double sampleRate(DEFAULT_SAMPLERATE);
273 int chorus(DEFAULT_CHORUS);
274 int reverb(DEFAULT_REVERB);
275 double gain(DEFAULT_GAIN);
276 int polyphony(DEFAULT_POLYPHONY);
277
278 audioDriver = ui->audioDriver->currentText();
279 if (audioDriver.isEmpty()) {
280 audioDriver = defaultAudioDriver();
281 }
282 soundFont = ui->soundFont->text();
283 bufferTime = ui->bufferTime->value();
284 periodSize = ui->periodSize->value();
285 periods = ui->periods->value();
286 sampleRate = ui->sampleRate->text().toDouble();
287 chorus = (ui->chorus->isChecked() ? 1 : 0);
288 reverb = (ui->reverb->isChecked() ? 1 : 0);
289 gain = ui->gain->text().toDouble();
290 polyphony = ui->polyphony->text().toInt();
291
292 settings->beginGroup(QSTR_PREFERENCES);
293 settings->setValue(QSTR_INSTRUMENTSDEFINITION, soundFont);
294 settings->setValue(QSTR_AUDIODRIVER, audioDriver);
295 settings->setValue(QSTR_BUFFERTIME, bufferTime);
296 settings->setValue(QSTR_PERIODSIZE, periodSize);
297 settings->setValue(QSTR_PERIODS, periods);
298 settings->setValue(QSTR_SAMPLERATE, sampleRate);
299 settings->setValue(QSTR_CHORUS, chorus);
300 settings->setValue(QSTR_REVERB, reverb);
301 settings->setValue(QSTR_GAIN, gain);
302 settings->setValue(QSTR_POLYPHONY, polyphony);
303 settings->endGroup();
304 settings->sync();
305
306 if ( audioDriver == QSTR_PULSEAUDIO ) {
307 qputenv("PULSE_LATENCY_MSEC", QByteArray::number( bufferTime ) );
308 }
309 chkDriverProperties(settings.getQSettings());
310}
311
312void FluidSettingsDialog::restoreDefaults()
313{
314 //qDebug() << Q_FUNC_INFO;
315 ui->audioDriver->setCurrentText( defaultAudioDriver() );
316 ui->bufferTime->setValue( DEFAULT_BUFFERTIME );
317 ui->periodSize->setValue( DEFAULT_PERIODSIZE );
318 ui->periods->setValue( DEFAULT_PERIODS );
319 ui->sampleRate->setText( QString::number( DEFAULT_SAMPLERATE ));
320 ui->chorus->setChecked( DEFAULT_CHORUS != 0 );
321 ui->reverb->setChecked( DEFAULT_REVERB != 0 );
322 ui->gain->setText( QString::number( DEFAULT_GAIN ) );
323 ui->polyphony->setText( QString::number( DEFAULT_POLYPHONY ));
324 ui->soundFont->setText( QSTR_SOUNDFONT );
325 initBuffer();
326}
327
328void FluidSettingsDialog::showFileDialog()
329{
330 QDir dir(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QSTR_DATADIR, QStandardPaths::LocateDirectory));
331 if (!dir.exists()) {
332 dir = QDir(QStandardPaths::locate(QStandardPaths::GenericDataLocation, QSTR_DATADIR2, QStandardPaths::LocateDirectory));
333 }
334 QString fileName = QFileDialog::getOpenFileName(this, tr("Select SoundFont"), dir.absolutePath(), tr("SoundFont Files (*.sf2 *.sf3 *.dls)"));
335 if (!fileName.isEmpty()) {
336 ui->soundFont->setText(fileName);
337 }
338}
339
340void FluidSettingsDialog::audioDriverChanged(const QString &text)
341{
342 //qDebug() << Q_FUNC_INFO << text;
343 if (text == QSTR_PULSEAUDIO) {
344 ui->bufferTime->setDisabled(false);
345 ui->bufferTime->blockSignals(false);
346 ui->periodSize->setDisabled(true);
347 ui->periodSize->blockSignals(true);
348 ui->periods->setDisabled(true);
349 ui->periods->blockSignals(true);
350 } else {
351 ui->bufferTime->setDisabled(true);
352 ui->bufferTime->blockSignals(true);
353 ui->periodSize->setDisabled(false);
354 ui->periodSize->blockSignals(false);
355 ui->periods->setDisabled(false);
356 ui->periods->blockSignals(false);
357 }
358 initBuffer();
359}
360
361void FluidSettingsDialog::bufferTimeChanged(int value)
362{
363 double rate = ui->sampleRate->text().toDouble();
364 int size = qRound( value * rate / 1000.0 );
365 ui->periodSize->setValue( size );
366 ui->periods->setValue( ui->periods->minimum() );
367 //qDebug() << Q_FUNC_INFO << "time:" << value << "rate:" << rate << "size:" << size;
368}
369
370void FluidSettingsDialog::bufferSizeChanged()
371{
372 QString audioDriver = ui->audioDriver->currentText();
373 double rate = ui->sampleRate->text().toDouble();
374 int size = ui->periodSize->value();
375 if (audioDriver != QSTR_PULSEAUDIO) {
376 size *= ui->periods->value();
377 }
378 int ms = qRound( 1000.0 * size / rate );
379 ui->bufferTime->setValue(ms);
380 //qDebug() << Q_FUNC_INFO << "time:" << ms << "rate:" << rate << "size:" << size;
381}
382
383void FluidSettingsDialog::changeSoundFont(const QString& fileName)
384{
385 readSettings();
386 ui->soundFont->setText(fileName);
387 writeSettings();
388}
389
390} // namespace widgets
391} // 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.