Generalize the backend list
[openal-soft.git] / utils / alsoft-config / mainwindow.cpp
blobf0afbced58d26ce4c9e845f279bfb39b6e5e4c07
2 #include "config.h"
4 #include <QFileDialog>
5 #include <QMessageBox>
6 #include <QCloseEvent>
7 #include <QSettings>
8 #include <QtGlobal>
9 #include "mainwindow.h"
10 #include "ui_mainwindow.h"
12 namespace {
13 static const struct {
14 char backend_name[16];
15 char full_string[32];
16 } backendList[] = {
17 #ifdef HAVE_JACK
18 { "jack", "JACK" },
19 #endif
20 #ifdef HAVE_PULSEAUDIO
21 { "pulse", "PulseAudio" },
22 #endif
23 #ifdef HAVE_ALSA
24 { "alsa", "ALSA" },
25 #endif
26 #ifdef HAVE_COREAUDIO
27 { "core", "CoreAudio" },
28 #endif
29 #ifdef HAVE_OSS
30 { "oss", "OSS" },
31 #endif
32 #ifdef HAVE_SOLARIS
33 { "solaris", "Solaris" },
34 #endif
35 #ifdef HAVE_SNDIO
36 { "sndio", "SoundIO" },
37 #endif
38 #ifdef HAVE_QSA
39 { "qsa", "QSA" },
40 #endif
41 #ifdef HAVE_MMDEVAPI
42 { "mmdevapi", "MMDevAPI" },
43 #endif
44 #ifdef HAVE_DSOUND
45 { "dsound", "DirectSound" },
46 #endif
47 #ifdef HAVE_WINMM
48 { "winmm", "Windows Multimedia" },
49 #endif
50 #ifdef HAVE_PORTAUDIO
51 { "port", "PortAudio" },
52 #endif
53 #ifdef HAVE_OPENSL
54 { "opensl", "OpenSL" },
55 #endif
57 { "null", "Null Output" },
58 #ifdef HAVE_WAVE
59 { "wave", "Wave Writer" },
60 #endif
61 { "", "" }
64 static const struct {
65 const char name[64];
66 const char value[16];
67 } speakerModeList[] = {
68 { "Autodetect", "" },
69 { "Mono", "mono" },
70 { "Stereo", "stereo" },
71 { "Quadrophonic", "quad" },
72 { "5.1 Surround (Side)", "surround51" },
73 { "5.1 Surround (Rear)", "surround51rear" },
74 { "6.1 Surround", "surround61" },
75 { "7.1 Surround", "surround71" },
77 { "", "" }
78 }, sampleTypeList[] = {
79 { "Autodetect", "" },
80 { "8-bit int", "int8" },
81 { "8-bit uint", "uint8" },
82 { "16-bit int", "int16" },
83 { "16-bit uint", "uint16" },
84 { "32-bit int", "int32" },
85 { "32-bit uint", "uint32" },
86 { "32-bit float", "float32" },
88 { "", "" }
89 }, resamplerList[] = {
90 { "Point", "point" },
91 { "Linear", "linear" },
92 { "Default (Linear)", "" },
93 { "4-Point Sinc", "sinc4" },
94 { "8-Point Sinc", "sinc8" },
95 { "Band-limited Sinc", "bsinc" },
97 { "", "" }
98 }, stereoModeList[] = {
99 { "Autodetect", "" },
100 { "Speakers", "speakers" },
101 { "Headphones", "headphones" },
103 { "", "" }
106 static QString getDefaultConfigName()
108 #ifdef Q_OS_WIN32
109 static const char fname[] = "alsoft.ini";
110 QByteArray base = qgetenv("AppData");
111 #else
112 static const char fname[] = "alsoft.conf";
113 QByteArray base = qgetenv("XDG_CONFIG_HOME");
114 if(base.isEmpty())
116 base = qgetenv("HOME");
117 if(base.isEmpty() == false)
118 base += "/.config";
120 #endif
121 if(base.isEmpty() == false)
122 return base +'/'+ fname;
123 return fname;
126 static QString getBaseDataPath()
128 #ifdef Q_OS_WIN32
129 QByteArray base = qgetenv("AppData");
130 #else
131 QByteArray base = qgetenv("XDG_DATA_HOME");
132 if(base.isEmpty())
134 base = qgetenv("HOME");
135 if(!base.isEmpty())
136 base += "/.local/share";
138 #endif
139 return base;
142 static QStringList getAllDataPaths(QString append=QString())
144 QStringList list;
145 list.append(getBaseDataPath());
146 #ifdef Q_OS_WIN32
147 // TODO: Common AppData path
148 #else
149 QString paths = qgetenv("XDG_DATA_DIRS");
150 if(paths.isEmpty())
151 paths = "/usr/local/share/:/usr/share/";
152 list += paths.split(QChar(':'), QString::SkipEmptyParts);
153 #endif
154 QStringList::iterator iter = list.begin();
155 while(iter != list.end())
157 if(iter->isEmpty())
158 iter = list.erase(iter);
159 else
161 iter->append(append);
162 iter++;
165 return list;
169 MainWindow::MainWindow(QWidget *parent) :
170 QMainWindow(parent),
171 ui(new Ui::MainWindow),
172 mPeriodSizeValidator(NULL),
173 mPeriodCountValidator(NULL),
174 mSourceCountValidator(NULL),
175 mEffectSlotValidator(NULL),
176 mSourceSendValidator(NULL),
177 mSampleRateValidator(NULL),
178 mNeedsSave(false)
180 ui->setupUi(this);
182 for(int i = 0;speakerModeList[i].name[0];i++)
183 ui->channelConfigCombo->addItem(speakerModeList[i].name);
184 ui->channelConfigCombo->adjustSize();
185 for(int i = 0;sampleTypeList[i].name[0];i++)
186 ui->sampleFormatCombo->addItem(sampleTypeList[i].name);
187 ui->sampleFormatCombo->adjustSize();
188 for(int i = 0;stereoModeList[i].name[0];i++)
189 ui->stereoModeCombo->addItem(stereoModeList[i].name);
190 ui->stereoModeCombo->adjustSize();
192 int count;
193 for(count = 0;resamplerList[count].name[0];count++) {
195 ui->resamplerSlider->setRange(0, count-1);
197 ui->hrtfStateComboBox->adjustSize();
199 #if !defined(HAVE_NEON) && !defined(HAVE_SSE)
200 ui->cpuExtDisabledLabel->move(ui->cpuExtDisabledLabel->x(), ui->cpuExtDisabledLabel->y() - 60);
201 #else
202 ui->cpuExtDisabledLabel->setVisible(false);
203 #endif
205 #ifndef HAVE_NEON
207 #ifndef HAVE_SSE4_1
208 #ifndef HAVE_SSE3
209 #ifndef HAVE_SSE2
210 #ifndef HAVE_SSE
211 ui->enableSSECheckBox->setVisible(false);
212 #endif /* !SSE */
213 ui->enableSSE2CheckBox->setVisible(false);
214 #endif /* !SSE2 */
215 ui->enableSSE3CheckBox->setVisible(false);
216 #endif /* !SSE3 */
217 ui->enableSSE41CheckBox->setVisible(false);
218 #endif /* !SSE4.1 */
219 ui->enableNeonCheckBox->setVisible(false);
221 #else /* !Neon */
223 #ifndef HAVE_SSE4_1
224 #ifndef HAVE_SSE3
225 #ifndef HAVE_SSE2
226 #ifndef HAVE_SSE
227 ui->enableNeonCheckBox->move(ui->enableNeonCheckBox->x(), ui->enableNeonCheckBox->y() - 30);
228 ui->enableSSECheckBox->setVisible(false);
229 #endif /* !SSE */
230 ui->enableSSE2CheckBox->setVisible(false);
231 #endif /* !SSE2 */
232 ui->enableSSE3CheckBox->setVisible(false);
233 #endif /* !SSE3 */
234 ui->enableSSE41CheckBox->setVisible(false);
235 #endif /* !SSE4.1 */
237 #endif
239 mPeriodSizeValidator = new QIntValidator(64, 8192, this);
240 ui->periodSizeEdit->setValidator(mPeriodSizeValidator);
241 mPeriodCountValidator = new QIntValidator(2, 16, this);
242 ui->periodCountEdit->setValidator(mPeriodCountValidator);
244 mSourceCountValidator = new QIntValidator(0, 256, this);
245 ui->srcCountLineEdit->setValidator(mSourceCountValidator);
246 mEffectSlotValidator = new QIntValidator(0, 16, this);
247 ui->effectSlotLineEdit->setValidator(mEffectSlotValidator);
248 mSourceSendValidator = new QIntValidator(0, 4, this);
249 ui->srcSendLineEdit->setValidator(mSourceSendValidator);
250 mSampleRateValidator = new QIntValidator(8000, 192000, this);
251 ui->sampleRateCombo->lineEdit()->setValidator(mSampleRateValidator);
253 connect(ui->actionLoad, SIGNAL(triggered()), this, SLOT(loadConfigFromFile()));
254 connect(ui->actionSave_As, SIGNAL(triggered()), this, SLOT(saveConfigAsFile()));
256 connect(ui->closeCancelButton, SIGNAL(clicked()), this, SLOT(cancelCloseAction()));
257 connect(ui->applyButton, SIGNAL(clicked()), this, SLOT(saveCurrentConfig()));
259 connect(ui->channelConfigCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton()));
260 connect(ui->sampleFormatCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton()));
261 connect(ui->stereoModeCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton()));
262 connect(ui->sampleRateCombo, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton()));
263 connect(ui->sampleRateCombo, SIGNAL(editTextChanged(const QString&)), this, SLOT(enableApplyButton()));
265 connect(ui->resamplerSlider, SIGNAL(valueChanged(int)), this, SLOT(updateResamplerLabel(int)));
267 connect(ui->periodSizeSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodSizeEdit(int)));
268 connect(ui->periodSizeEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodSizeSlider()));
269 connect(ui->periodCountSlider, SIGNAL(valueChanged(int)), this, SLOT(updatePeriodCountEdit(int)));
270 connect(ui->periodCountEdit, SIGNAL(editingFinished()), this, SLOT(updatePeriodCountSlider()));
272 connect(ui->preferredHrtfComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton()));
273 connect(ui->hrtfStateComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton()));
274 connect(ui->hrtfAddButton, SIGNAL(clicked()), this, SLOT(addHrtfFile()));
275 connect(ui->hrtfRemoveButton, SIGNAL(clicked()), this, SLOT(removeHrtfFile()));
276 connect(ui->hrtfFileList, SIGNAL(itemSelectionChanged()), this, SLOT(updateHrtfRemoveButton()));
277 connect(ui->defaultHrtfPathsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
279 connect(ui->srcCountLineEdit, SIGNAL(editingFinished()), this, SLOT(enableApplyButton()));
280 connect(ui->srcSendLineEdit, SIGNAL(editingFinished()), this, SLOT(enableApplyButton()));
281 connect(ui->effectSlotLineEdit, SIGNAL(editingFinished()), this, SLOT(enableApplyButton()));
283 connect(ui->enableSSECheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
284 connect(ui->enableSSE2CheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
285 connect(ui->enableSSE3CheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
286 connect(ui->enableSSE41CheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
287 connect(ui->enableNeonCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
289 ui->enabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu);
290 connect(ui->enabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showEnabledBackendMenu(QPoint)));
292 ui->disabledBackendList->setContextMenuPolicy(Qt::CustomContextMenu);
293 connect(ui->disabledBackendList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showDisabledBackendMenu(QPoint)));
294 connect(ui->backendCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
296 connect(ui->defaultReverbComboBox, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(enableApplyButton()));
297 connect(ui->emulateEaxCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
298 connect(ui->enableEaxReverbCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
299 connect(ui->enableStdReverbCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
300 connect(ui->enableChorusCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
301 connect(ui->enableCompressorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
302 connect(ui->enableDistortionCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
303 connect(ui->enableEchoCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
304 connect(ui->enableEqualizerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
305 connect(ui->enableFlangerCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
306 connect(ui->enableModulatorCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
307 connect(ui->enableDedicatedCheck, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
309 connect(ui->pulseAutospawnCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
310 connect(ui->pulseAllowMovesCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
311 connect(ui->pulseFixRateCheckBox, SIGNAL(stateChanged(int)), this, SLOT(enableApplyButton()));
313 ui->backendListWidget->setCurrentRow(0);
314 ui->tabWidget->setCurrentIndex(0);
316 loadConfig(getDefaultConfigName());
319 MainWindow::~MainWindow()
321 delete ui;
322 delete mPeriodSizeValidator;
323 delete mPeriodCountValidator;
324 delete mSourceCountValidator;
325 delete mEffectSlotValidator;
326 delete mSourceSendValidator;
327 delete mSampleRateValidator;
330 void MainWindow::closeEvent(QCloseEvent *event)
332 if(!mNeedsSave)
333 event->accept();
334 else
336 QMessageBox::StandardButton btn = QMessageBox::warning(this,
337 tr("Apply changes?"), tr("Save changes before quitting?"),
338 QMessageBox::Save | QMessageBox::No | QMessageBox::Cancel
340 if(btn == QMessageBox::Save)
341 saveCurrentConfig();
342 if(btn == QMessageBox::Cancel)
343 event->ignore();
344 else
345 event->accept();
349 void MainWindow::cancelCloseAction()
351 mNeedsSave = false;
352 close();
356 QStringList MainWindow::collectHrtfs()
358 QStringList ret;
360 for(int i = 0;i < ui->hrtfFileList->count();i++)
362 QDir dir(ui->hrtfFileList->item(i)->text());
363 QStringList fnames = dir.entryList(QDir::Files | QDir::Readable, QDir::Name);
364 foreach(const QString &fname, fnames)
366 if(fname.endsWith(".mhr", Qt::CaseInsensitive))
368 if(!ret.contains(fname))
369 ret.push_back(fname.left(fname.length()-4));
370 else
372 size_t i = 1;
373 do {
374 QString s = fname.left(fname.length()-4)+" #"+QString::number(i);
375 if(!ret.contains(s))
377 ret.push_back(s);
378 break;
380 ++i;
381 } while(1);
387 if(ui->defaultHrtfPathsCheckBox->isChecked())
389 QStringList paths = getAllDataPaths("/openal/hrtf");
390 foreach(const QString &name, paths)
392 QDir dir(name);
393 QStringList fnames = dir.entryList(QDir::Files | QDir::Readable, QDir::Name);
394 foreach(const QString &fname, fnames)
396 if(fname.endsWith(".mhr", Qt::CaseInsensitive))
398 if(!ret.contains(fname))
399 ret.push_back(fname.left(fname.length()-4));
400 else
402 size_t i = 1;
403 do {
404 QString s = fname.left(fname.length()-4)+" #"+QString::number(i);
405 if(!ret.contains(s))
407 ret.push_back(s);
408 break;
410 ++i;
411 } while(1);
417 return ret;
421 void MainWindow::loadConfigFromFile()
423 QString fname = QFileDialog::getOpenFileName(this, tr("Select Files"));
424 if(fname.isEmpty() == false)
425 loadConfig(fname);
428 void MainWindow::loadConfig(const QString &fname)
430 QSettings settings(fname, QSettings::IniFormat);
432 QString sampletype = settings.value("sample-type").toString();
433 ui->sampleFormatCombo->setCurrentIndex(0);
434 if(sampletype.isEmpty() == false)
436 for(int i = 0;sampleTypeList[i].name[i];i++)
438 if(sampletype == sampleTypeList[i].value)
440 int j = ui->sampleFormatCombo->findText(sampleTypeList[i].name);
441 if(j > 0) ui->sampleFormatCombo->setCurrentIndex(j);
442 break;
447 QString channelconfig = settings.value("channels").toString();
448 ui->channelConfigCombo->setCurrentIndex(0);
449 if(channelconfig.isEmpty() == false)
451 for(int i = 0;speakerModeList[i].name[i];i++)
453 if(channelconfig == speakerModeList[i].value)
455 int j = ui->channelConfigCombo->findText(speakerModeList[i].name);
456 if(j > 0) ui->channelConfigCombo->setCurrentIndex(j);
457 break;
462 QString srate = settings.value("frequency").toString();
463 if(srate.isEmpty())
464 ui->sampleRateCombo->setCurrentIndex(0);
465 else
467 ui->sampleRateCombo->lineEdit()->clear();
468 ui->sampleRateCombo->lineEdit()->insert(srate);
471 ui->srcCountLineEdit->clear();
472 ui->srcCountLineEdit->insert(settings.value("sources").toString());
473 ui->effectSlotLineEdit->clear();
474 ui->effectSlotLineEdit->insert(settings.value("slots").toString());
475 ui->srcSendLineEdit->clear();
476 ui->srcSendLineEdit->insert(settings.value("sends").toString());
478 QString resampler = settings.value("resampler").toString().trimmed();
479 ui->resamplerSlider->setValue(0);
480 /* The "cubic" resampler is no longer supported. It's been replaced by
481 * "sinc4". */
482 if(resampler == "cubic")
483 resampler = "sinc4";
484 for(int i = 0;resamplerList[i].name[i];i++)
486 if(resampler == resamplerList[i].value)
488 ui->resamplerSlider->setValue(i);
489 break;
493 QString stereomode = settings.value("stereo-mode").toString().trimmed();
494 ui->stereoModeCombo->setCurrentIndex(0);
495 if(stereomode.isEmpty() == false)
497 for(int i = 0;stereoModeList[i].name[i];i++)
499 if(stereomode == stereoModeList[i].value)
501 int j = ui->stereoModeCombo->findText(stereoModeList[i].name);
502 if(j > 0) ui->stereoModeCombo->setCurrentIndex(j);
503 break;
508 int periodsize = settings.value("period_size").toInt();
509 ui->periodSizeEdit->clear();
510 if(periodsize >= 64)
512 ui->periodSizeEdit->insert(QString::number(periodsize));
513 updatePeriodSizeSlider();
516 int periodcount = settings.value("periods").toInt();
517 ui->periodCountEdit->clear();
518 if(periodcount >= 2)
520 ui->periodCountEdit->insert(QString::number(periodcount));
521 updatePeriodCountSlider();
524 QStringList disabledCpuExts = settings.value("disable-cpu-exts").toStringList();
525 if(disabledCpuExts.size() == 1)
526 disabledCpuExts = disabledCpuExts[0].split(QChar(','));
527 std::transform(disabledCpuExts.begin(), disabledCpuExts.end(),
528 disabledCpuExts.begin(), std::mem_fun_ref(&QString::trimmed));
529 ui->enableSSECheckBox->setChecked(!disabledCpuExts.contains("sse", Qt::CaseInsensitive));
530 ui->enableSSE2CheckBox->setChecked(!disabledCpuExts.contains("sse2", Qt::CaseInsensitive));
531 ui->enableSSE3CheckBox->setChecked(!disabledCpuExts.contains("sse3", Qt::CaseInsensitive));
532 ui->enableSSE41CheckBox->setChecked(!disabledCpuExts.contains("sse4.1", Qt::CaseInsensitive));
533 ui->enableNeonCheckBox->setChecked(!disabledCpuExts.contains("neon", Qt::CaseInsensitive));
535 QStringList hrtf_paths = settings.value("hrtf-paths").toStringList();
536 if(hrtf_paths.size() == 1)
537 hrtf_paths = hrtf_paths[0].split(QChar(','));
538 std::transform(hrtf_paths.begin(), hrtf_paths.end(),
539 hrtf_paths.begin(), std::mem_fun_ref(&QString::trimmed));
540 if(!hrtf_paths.empty() && !hrtf_paths.back().isEmpty())
541 ui->defaultHrtfPathsCheckBox->setCheckState(Qt::Unchecked);
542 else
544 hrtf_paths.removeAll(QString());
545 ui->defaultHrtfPathsCheckBox->setCheckState(Qt::Checked);
547 hrtf_paths.removeDuplicates();
548 ui->hrtfFileList->clear();
549 ui->hrtfFileList->addItems(hrtf_paths);
550 updateHrtfRemoveButton();
552 QString hrtfstate = settings.value("hrtf").toString().toLower();
553 if(hrtfstate == "true")
554 ui->hrtfStateComboBox->setCurrentIndex(1);
555 else if(hrtfstate == "false")
556 ui->hrtfStateComboBox->setCurrentIndex(2);
557 else
558 ui->hrtfStateComboBox->setCurrentIndex(0);
560 ui->preferredHrtfComboBox->clear();
561 ui->preferredHrtfComboBox->addItem("- Any -");
562 if(ui->defaultHrtfPathsCheckBox->isChecked())
564 QStringList hrtfs = collectHrtfs();
565 foreach(const QString &name, hrtfs)
566 ui->preferredHrtfComboBox->addItem(name);
569 QString defaulthrtf = settings.value("default-hrtf").toString();
570 ui->preferredHrtfComboBox->setCurrentIndex(0);
571 if(defaulthrtf.isEmpty() == false)
573 int i = ui->preferredHrtfComboBox->findText(defaulthrtf);
574 if(i > 0)
575 ui->preferredHrtfComboBox->setCurrentIndex(i);
576 else
578 i = ui->preferredHrtfComboBox->count();
579 ui->preferredHrtfComboBox->addItem(defaulthrtf);
580 ui->preferredHrtfComboBox->setCurrentIndex(i);
583 ui->preferredHrtfComboBox->adjustSize();
585 ui->enabledBackendList->clear();
586 ui->disabledBackendList->clear();
587 QStringList drivers = settings.value("drivers").toStringList();
588 if(drivers.size() == 0)
589 ui->backendCheckBox->setChecked(true);
590 else
592 if(drivers.size() == 1)
593 drivers = drivers[0].split(QChar(','));
594 std::transform(drivers.begin(), drivers.end(),
595 drivers.begin(), std::mem_fun_ref(&QString::trimmed));
597 bool lastWasEmpty = false;
598 foreach(const QString &backend, drivers)
600 lastWasEmpty = backend.isEmpty();
601 if(!backend.startsWith(QChar('-')) && !lastWasEmpty)
602 ui->enabledBackendList->addItem(backend);
603 else if(backend.size() > 1)
604 ui->disabledBackendList->addItem(backend.right(backend.size()-1));
606 ui->backendCheckBox->setChecked(lastWasEmpty);
609 QString defaultreverb = settings.value("default-reverb").toString().toLower();
610 ui->defaultReverbComboBox->setCurrentIndex(0);
611 if(defaultreverb.isEmpty() == false)
613 for(int i = 0;i < ui->defaultReverbComboBox->count();i++)
615 if(defaultreverb.compare(ui->defaultReverbComboBox->itemText(i).toLower()) == 0)
617 ui->defaultReverbComboBox->setCurrentIndex(i);
618 break;
623 ui->emulateEaxCheckBox->setChecked(settings.value("reverb/emulate-eax", false).toBool());
625 QStringList excludefx = settings.value("excludefx").toStringList();
626 if(excludefx.size() == 1)
627 excludefx = excludefx[0].split(QChar(','));
628 std::transform(excludefx.begin(), excludefx.end(),
629 excludefx.begin(), std::mem_fun_ref(&QString::trimmed));
630 ui->enableEaxReverbCheck->setChecked(!excludefx.contains("eaxreverb", Qt::CaseInsensitive));
631 ui->enableStdReverbCheck->setChecked(!excludefx.contains("reverb", Qt::CaseInsensitive));
632 ui->enableChorusCheck->setChecked(!excludefx.contains("chorus", Qt::CaseInsensitive));
633 ui->enableCompressorCheck->setChecked(!excludefx.contains("compressor", Qt::CaseInsensitive));
634 ui->enableDistortionCheck->setChecked(!excludefx.contains("distortion", Qt::CaseInsensitive));
635 ui->enableEchoCheck->setChecked(!excludefx.contains("echo", Qt::CaseInsensitive));
636 ui->enableEqualizerCheck->setChecked(!excludefx.contains("equalizer", Qt::CaseInsensitive));
637 ui->enableFlangerCheck->setChecked(!excludefx.contains("flanger", Qt::CaseInsensitive));
638 ui->enableModulatorCheck->setChecked(!excludefx.contains("modulator", Qt::CaseInsensitive));
639 ui->enableDedicatedCheck->setChecked(!excludefx.contains("dedicated", Qt::CaseInsensitive));
641 ui->pulseAutospawnCheckBox->setChecked(settings.value("pulse/spawn-server", true).toBool());
642 ui->pulseAllowMovesCheckBox->setChecked(settings.value("pulse/allow-moves", false).toBool());
643 ui->pulseFixRateCheckBox->setChecked(settings.value("pulse/fix-rate", false).toBool());
645 ui->applyButton->setEnabled(false);
646 ui->closeCancelButton->setText(tr("Close"));
647 mNeedsSave = false;
650 void MainWindow::saveCurrentConfig()
652 saveConfig(getDefaultConfigName());
653 ui->applyButton->setEnabled(false);
654 ui->closeCancelButton->setText(tr("Close"));
655 mNeedsSave = false;
656 QMessageBox::information(this, tr("Information"),
657 tr("Applications using OpenAL need to be restarted for changes to take effect."));
660 void MainWindow::saveConfigAsFile()
662 QString fname = QFileDialog::getOpenFileName(this, tr("Select Files"));
663 if(fname.isEmpty() == false)
665 saveConfig(fname);
666 ui->applyButton->setEnabled(false);
667 mNeedsSave = false;
671 void MainWindow::saveConfig(const QString &fname) const
673 QSettings settings(fname, QSettings::IniFormat);
675 /* HACK: Compound any stringlist values into a comma-separated string. */
676 QStringList allkeys = settings.allKeys();
677 foreach(const QString &key, allkeys)
679 QStringList vals = settings.value(key).toStringList();
680 if(vals.size() > 1)
681 settings.setValue(key, vals.join(QChar(',')));
684 QString str = ui->sampleFormatCombo->currentText();
685 for(int i = 0;sampleTypeList[i].name[0];i++)
687 if(str == sampleTypeList[i].name)
689 settings.setValue("sample-type", sampleTypeList[i].value);
690 break;
694 str = ui->channelConfigCombo->currentText();
695 for(int i = 0;speakerModeList[i].name[0];i++)
697 if(str == speakerModeList[i].name)
699 settings.setValue("channels", speakerModeList[i].value);
700 break;
704 uint rate = ui->sampleRateCombo->currentText().toUInt();
705 if(!(rate > 0))
706 settings.setValue("frequency", QString());
707 else
708 settings.setValue("frequency", rate);
710 settings.setValue("period_size", ui->periodSizeEdit->text());
711 settings.setValue("periods", ui->periodCountEdit->text());
713 settings.setValue("sources", ui->srcCountLineEdit->text());
714 settings.setValue("slots", ui->effectSlotLineEdit->text());
716 settings.setValue("resampler", resamplerList[ui->resamplerSlider->value()].value);
718 str = ui->stereoModeCombo->currentText();
719 for(int i = 0;stereoModeList[i].name[0];i++)
721 if(str == stereoModeList[i].name)
723 settings.setValue("stereo-mode", stereoModeList[i].value);
724 break;
728 QStringList strlist;
729 if(!ui->enableSSECheckBox->isChecked())
730 strlist.append("sse");
731 if(!ui->enableSSE2CheckBox->isChecked())
732 strlist.append("sse2");
733 if(!ui->enableSSE3CheckBox->isChecked())
734 strlist.append("sse3");
735 if(!ui->enableSSE41CheckBox->isChecked())
736 strlist.append("sse4.1");
737 if(!ui->enableNeonCheckBox->isChecked())
738 strlist.append("neon");
739 settings.setValue("disable-cpu-exts", strlist.join(QChar(',')));
741 if(ui->hrtfStateComboBox->currentIndex() == 1)
742 settings.setValue("hrtf", "true");
743 else if(ui->hrtfStateComboBox->currentIndex() == 2)
744 settings.setValue("hrtf", "false");
745 else
746 settings.setValue("hrtf", QString());
748 if(ui->preferredHrtfComboBox->currentIndex() == 0)
749 settings.setValue("default-hrtf", QString());
750 else
752 str = ui->preferredHrtfComboBox->currentText();
753 settings.setValue("default-hrtf", str);
756 strlist.clear();
757 for(int i = 0;i < ui->hrtfFileList->count();i++)
758 strlist.append(ui->hrtfFileList->item(i)->text());
759 if(!strlist.empty() && ui->defaultHrtfPathsCheckBox->isChecked())
760 strlist.append(QString());
761 settings.setValue("hrtf-paths", strlist.join(QChar(',')));
763 strlist.clear();
764 for(int i = 0;i < ui->enabledBackendList->count();i++)
765 strlist.append(ui->enabledBackendList->item(i)->text());
766 for(int i = 0;i < ui->disabledBackendList->count();i++)
767 strlist.append(QChar('-')+ui->disabledBackendList->item(i)->text());
768 if(strlist.size() == 0 && !ui->backendCheckBox->isChecked())
769 strlist.append("-all");
770 else if(ui->backendCheckBox->isChecked())
771 strlist.append(QString());
772 settings.setValue("drivers", strlist.join(QChar(',')));
774 // TODO: Remove check when we can properly match global values.
775 if(ui->defaultReverbComboBox->currentIndex() == 0)
776 settings.setValue("default-reverb", QString());
777 else
779 str = ui->defaultReverbComboBox->currentText().toLower();
780 settings.setValue("default-reverb", str);
783 if(ui->emulateEaxCheckBox->isChecked())
784 settings.setValue("reverb/emulate-eax", "true");
785 else
786 settings.remove("reverb/emulate-eax"/*, "false"*/);
788 strlist.clear();
789 if(!ui->enableEaxReverbCheck->isChecked())
790 strlist.append("eaxreverb");
791 if(!ui->enableStdReverbCheck->isChecked())
792 strlist.append("reverb");
793 if(!ui->enableChorusCheck->isChecked())
794 strlist.append("chorus");
795 if(!ui->enableDistortionCheck->isChecked())
796 strlist.append("distortion");
797 if(!ui->enableCompressorCheck->isChecked())
798 strlist.append("compressor");
799 if(!ui->enableEchoCheck->isChecked())
800 strlist.append("echo");
801 if(!ui->enableEqualizerCheck->isChecked())
802 strlist.append("equalizer");
803 if(!ui->enableFlangerCheck->isChecked())
804 strlist.append("flanger");
805 if(!ui->enableModulatorCheck->isChecked())
806 strlist.append("modulator");
807 if(!ui->enableDedicatedCheck->isChecked())
808 strlist.append("dedicated");
809 settings.setValue("excludefx", strlist.join(QChar(',')));
811 /* Remove empty keys
812 * FIXME: Should only remove keys whose value matches the globally-specified value.
814 allkeys = settings.allKeys();
815 foreach(const QString &key, allkeys)
817 str = settings.value(key).toString();
818 if(str == QString())
819 settings.remove(key);
822 if(ui->pulseAutospawnCheckBox->isChecked())
823 settings.remove("pulse/spawn-server"/*, "true"*/);
824 else
825 settings.setValue("pulse/spawn-server", "false");
826 if(ui->pulseAllowMovesCheckBox->isChecked())
827 settings.setValue("pulse/allow-moves", "true");
828 else
829 settings.remove("pulse/allow-moves"/*, "false"*/);
830 if(ui->pulseFixRateCheckBox->isChecked())
831 settings.setValue("pulse/fix-rate", "true");
832 else
833 settings.remove("pulse/fix-rate"/*, "false"*/);
837 void MainWindow::enableApplyButton()
839 if(!mNeedsSave)
840 ui->applyButton->setEnabled(true);
841 mNeedsSave = true;
842 ui->closeCancelButton->setText(tr("Cancel"));
846 void MainWindow::updateResamplerLabel(int num)
848 ui->resamplerLabel->setText(resamplerList[num].name);
849 enableApplyButton();
853 void MainWindow::updatePeriodSizeEdit(int size)
855 ui->periodSizeEdit->clear();
856 if(size >= 64)
858 size = (size+32)&~0x3f;
859 ui->periodSizeEdit->insert(QString::number(size));
861 enableApplyButton();
864 void MainWindow::updatePeriodSizeSlider()
866 int pos = ui->periodSizeEdit->text().toInt();
867 if(pos >= 64)
869 if(pos > 8192)
870 pos = 8192;
871 ui->periodSizeSlider->setSliderPosition(pos);
873 enableApplyButton();
876 void MainWindow::updatePeriodCountEdit(int count)
878 ui->periodCountEdit->clear();
879 if(count >= 2)
880 ui->periodCountEdit->insert(QString::number(count));
881 enableApplyButton();
884 void MainWindow::updatePeriodCountSlider()
886 int pos = ui->periodCountEdit->text().toInt();
887 if(pos < 2)
888 pos = 0;
889 else if(pos > 16)
890 pos = 16;
891 ui->periodCountSlider->setSliderPosition(pos);
892 enableApplyButton();
896 void MainWindow::addHrtfFile()
898 QString path = QFileDialog::getExistingDirectory(this, tr("Select HRTF Path"));
899 if(path.isEmpty() == false && !getAllDataPaths("/openal/hrtf").contains(path))
901 ui->hrtfFileList->addItem(path);
902 enableApplyButton();
906 void MainWindow::removeHrtfFile()
908 QList<QListWidgetItem*> selected = ui->hrtfFileList->selectedItems();
909 if(!selected.isEmpty())
911 foreach(QListWidgetItem *item, selected)
912 delete item;
913 enableApplyButton();
917 void MainWindow::updateHrtfRemoveButton()
919 ui->hrtfRemoveButton->setEnabled(ui->hrtfFileList->selectedItems().size() != 0);
922 void MainWindow::showEnabledBackendMenu(QPoint pt)
924 QMap<QAction*,QString> actionMap;
926 pt = ui->enabledBackendList->mapToGlobal(pt);
928 QMenu ctxmenu;
929 QAction *removeAction = ctxmenu.addAction(QIcon::fromTheme("list-remove"), "Remove");
930 if(ui->enabledBackendList->selectedItems().size() == 0)
931 removeAction->setEnabled(false);
932 ctxmenu.addSeparator();
933 for(size_t i = 0;backendList[i].backend_name[0];i++)
935 QAction *action = ctxmenu.addAction(QString("Add ")+backendList[i].full_string);
936 actionMap[action] = backendList[i].backend_name;
937 if(ui->enabledBackendList->findItems(backendList[i].backend_name, Qt::MatchFixedString).size() != 0 ||
938 ui->disabledBackendList->findItems(backendList[i].backend_name, Qt::MatchFixedString).size() != 0)
939 action->setEnabled(false);
942 QAction *gotAction = ctxmenu.exec(pt);
943 if(gotAction == removeAction)
945 QList<QListWidgetItem*> selected = ui->enabledBackendList->selectedItems();
946 foreach(QListWidgetItem *item, selected)
947 delete item;
948 enableApplyButton();
950 else if(gotAction != NULL)
952 QMap<QAction*,QString>::const_iterator iter = actionMap.find(gotAction);
953 if(iter != actionMap.end())
954 ui->enabledBackendList->addItem(iter.value());
955 enableApplyButton();
959 void MainWindow::showDisabledBackendMenu(QPoint pt)
961 QMap<QAction*,QString> actionMap;
963 pt = ui->disabledBackendList->mapToGlobal(pt);
965 QMenu ctxmenu;
966 QAction *removeAction = ctxmenu.addAction(QIcon::fromTheme("list-remove"), "Remove");
967 if(ui->disabledBackendList->selectedItems().size() == 0)
968 removeAction->setEnabled(false);
969 ctxmenu.addSeparator();
970 for(size_t i = 0;backendList[i].backend_name[0];i++)
972 QAction *action = ctxmenu.addAction(QString("Add ")+backendList[i].full_string);
973 actionMap[action] = backendList[i].backend_name;
974 if(ui->disabledBackendList->findItems(backendList[i].backend_name, Qt::MatchFixedString).size() != 0 ||
975 ui->enabledBackendList->findItems(backendList[i].backend_name, Qt::MatchFixedString).size() != 0)
976 action->setEnabled(false);
979 QAction *gotAction = ctxmenu.exec(pt);
980 if(gotAction == removeAction)
982 QList<QListWidgetItem*> selected = ui->disabledBackendList->selectedItems();
983 foreach(QListWidgetItem *item, selected)
984 delete item;
985 enableApplyButton();
987 else if(gotAction != NULL)
989 QMap<QAction*,QString>::const_iterator iter = actionMap.find(gotAction);
990 if(iter != actionMap.end())
991 ui->disabledBackendList->addItem(iter.value());
992 enableApplyButton();