11 setWindowTitle(
"Audio Settings");
15 audioPassThroughCheckBox->setToolTip(
"Play live microphone input or the selected audio source through the output device.");
18 QLabel *recordVolumeLabel =
new QLabel(
"Recording Volume:",
this);
22 QLabel *recordVolumeValueLabel =
new QLabel(
"100%",
this);
23 connect(
recordVolumeSlider, &QSlider::valueChanged,
this, [recordVolumeValueLabel](
int value) { recordVolumeValueLabel->setText(QString::number(value) +
"%"); });
25 QLabel *channelLabel =
new QLabel(
"Number of Channels:",
this);
30 QLabel *sensitivityLabel =
new QLabel(
"Sensitivity:",
this);
35 QLabel *sensitivityValueLabel =
new QLabel(
"1.0",
this);
36 connect(
sensitivitySlider, &QSlider::valueChanged,
this, [
this, sensitivityValueLabel](
int value) {
37 double floatValue = value / 10.0;
38 sensitivityValueLabel->setText(QString::number(floatValue,
'f', 1));
43 QLabel *inputDeviceLabel =
new QLabel(
"Input Device:",
this);
46 QLabel *outputDeviceLabel =
new QLabel(
"Output Device:",
this);
54 okButton =
new QPushButton(
"OK",
this);
57 audioFileCheckBox =
new QCheckBox(
"Use Audio File for Reactivity (instead of mic)",
this);
64 audioPlaylistCheckBox->setToolTip(
"Use the tracks in an M3U playlist instead of the selected audio file.");
74 audioRepeatCheckBox->setToolTip(
"Restart the audio file, or the full playlist, when it reaches the end.");
87 audioWarmRateSpinBox->setToolTip(
"Audio startup warmup rate (1/sec). 0.5 is about a 2 second fade-in; 0 disables warmup.");
113 QSettings appSettings(
"LostSideDead");
114 QString lastDir = appSettings.value(
"lastAudioFileDir",
"").toString();
115 QString fileName = QFileDialog::getOpenFileName(
this,
"Select Audio File", lastDir,
"Audio Files (*.wav *.mp3 *.flac *.aac *.ogg *.m4a *.wma *.mp4 *.mkv *.mov *.avi)");
116 if (!fileName.isEmpty()) {
117 appSettings.setValue(
"lastAudioFileDir", QFileInfo(fileName).absolutePath());
123 QSettings appSettings(
"LostSideDead");
124 QString lastDir = appSettings.value(
"lastAudioPlaylistDir",
"").toString();
125 QString fileName = QFileDialog::getOpenFileName(
this,
"Select M3U Audio Playlist", lastDir,
"M3U Playlists (*.m3u *.m3u8)");
126 if (!fileName.isEmpty()) {
127 appSettings.setValue(
"lastAudioPlaylistDir", QFileInfo(fileName).absolutePath());
134 if (editor.exec() != QDialog::Accepted || editor.
playlistPath().isEmpty())
140 connect(
okButton, &QPushButton::clicked,
this, [
this]() {
144 connect(
cancelButton, &QPushButton::clicked,
this, [
this]() {
149 QVBoxLayout *mainLayout =
new QVBoxLayout(
this);
154 QHBoxLayout *recordVolumeLayout =
new QHBoxLayout();
155 recordVolumeLayout->addWidget(recordVolumeLabel);
157 recordVolumeLayout->addWidget(recordVolumeValueLabel);
158 mainLayout->addLayout(recordVolumeLayout);
160 QHBoxLayout *channelLayout =
new QHBoxLayout();
161 channelLayout->addWidget(channelLabel);
163 mainLayout->addLayout(channelLayout);
165 QHBoxLayout *sensitivityLayout =
new QHBoxLayout();
166 sensitivityLayout->addWidget(sensitivityLabel);
168 sensitivityLayout->addWidget(sensitivityValueLabel);
169 mainLayout->addLayout(sensitivityLayout);
171 QHBoxLayout *inputDeviceLayout =
new QHBoxLayout();
172 inputDeviceLayout->addWidget(inputDeviceLabel);
174 mainLayout->addLayout(inputDeviceLayout);
176 QHBoxLayout *outputDeviceLayout =
new QHBoxLayout();
177 outputDeviceLayout->addWidget(outputDeviceLabel);
179 mainLayout->addLayout(outputDeviceLayout);
181 QHBoxLayout *audioFileLayout =
new QHBoxLayout();
185 mainLayout->addLayout(audioFileLayout);
186 QHBoxLayout *audioPlaylistLayout =
new QHBoxLayout();
191 mainLayout->addLayout(audioPlaylistLayout);
195 QHBoxLayout *audioBuffersLayout =
new QHBoxLayout();
197 audioBuffersLayout->addWidget(
new QLabel(
"Frames:",
this));
199 audioBuffersLayout->addStretch();
200 mainLayout->addLayout(audioBuffersLayout);
202 QHBoxLayout *audioWarmLayout =
new QHBoxLayout();
203 audioWarmLayout->addWidget(
new QLabel(
"Audio Warm Rate:",
this));
205 audioWarmLayout->addWidget(
new QLabel(
"(1/sec)",
this));
206 audioWarmLayout->addStretch();
207 mainLayout->addLayout(audioWarmLayout);
209 QHBoxLayout *buttonLayout =
new QHBoxLayout();
212 mainLayout->addLayout(buttonLayout);
214 setLayout(mainLayout);
219 QSettings appSettings(
"LostSideDead",
"acmx2");
225 channelSpinBox->setValue(appSettings.value(
"audio/channels", 2).toInt());
228 int inputId = appSettings.value(
"audio/input_device", -1).toInt();
229 int outputId = appSettings.value(
"audio/output_device", -1).toInt();
235 if (outputIdx >= 0) {
239 audioFileCheckBox->setChecked(appSettings.value(
"audio/file_enabled",
false).toBool());
243 audioTruncCheckBox->setChecked(appSettings.value(
"audio/file_trunc",
false).toBool());
296 process.start(
"acmx2", QStringList() <<
"--list-devices");
297 process.waitForFinished(5000);
299 QString output = process.readAllStandardOutput();
300 if (output.isEmpty() || process.exitCode() != 0) {
308 QRegularExpression deviceRegex(R
"(^\s*Device\s+(\d+):\s*(.+?)\s*$)");
309 QRegularExpression inputChRegex(R"(^\s*Input channels:\s*(\d+))");
310 QRegularExpression outputChRegex(R"(^\s*Output channels:\s*(\d+))");
312 QStringList lines = output.split('\n');
315 bool isDefaultInput =
false;
316 bool isDefaultOutput =
false;
318 auto flushDevice = [&]() {
326 for (
int i = 0; i < lines.size(); ++i) {
327 const QString &line = lines[i];
328 QRegularExpressionMatch devMatch = deviceRegex.match(line);
330 if (devMatch.hasMatch()) {
332 if (currentId >= 0) {
334 QString label = currentName +
" (" + QString::number(inputCh) +
" ch)";
336 label +=
" [Default]";
340 QString label = currentName +
" (" + QString::number(outputCh) +
" ch)";
342 label +=
" [Default]";
347 currentId = devMatch.captured(1).toInt();
348 currentName = devMatch.captured(2).trimmed();
349 isDefaultInput = currentName.contains(
"[DEFAULT INPUT]");
350 isDefaultOutput = currentName.contains(
"[DEFAULT OUTPUT]");
352 currentName.remove(
"[DEFAULT INPUT]");
353 currentName.remove(
"[DEFAULT OUTPUT]");
354 currentName = currentName.trimmed();
360 QRegularExpressionMatch inMatch = inputChRegex.match(line);
361 if (inMatch.hasMatch()) {
362 inputCh = inMatch.captured(1).toInt();
366 QRegularExpressionMatch outMatch = outputChRegex.match(line);
367 if (outMatch.hasMatch()) {
368 outputCh = outMatch.captured(1).toInt();
374 if (currentId >= 0) {
376 QString label = currentName +
" (" + QString::number(inputCh) +
" ch)";
378 label +=
" [Default]";
382 QString label = currentName +
" (" + QString::number(outputCh) +
" ch)";
384 label +=
" [Default]";