chatgui: add sound playback via miniaudio (MP3 notification sounds)

- SoundManager singleton wraps ma_engine + ma_sound (non-blocking, background thread)
- MP3 files embedded in QRC, decoded to PCM at startup with MA_SOUND_FLAG_DECODE
- miniaudio.h (MIT) in lib/, IMPLEMENTATION in separate miniaudio_impl.c
- Sound settings page in SettingsDialog: enable/disable, volume slider (0-100%)
- Config keys [gui] sound_enabled, sound_volume
- Incoming messages trigger msg_incoming.mp3 sound
This commit is contained in:
Evgeny committed 2026-07-19 14:46:21 +03:00
1 parent f6f7e12192
commit c2ad2e78c3
25 files changed
+101647 -2

No files matched your search

+120
View File
@@ -0,0 +1,120 @@
#include "soundsettingspage.h"
#include "sound_manager.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QCheckBox>
#include <QSlider>
#include <QLabel>
#include <QFile>
#include <QTextStream>
#include <QDebug>
SoundSettingsPage::SoundSettingsPage(QWidget* parent)
: QWidget(parent)
{
auto* layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 12, 0, 0);
layout->setSpacing(14);
m_enabledCheck = new QCheckBox("Enable sounds", this);
m_enabledCheck->setStyleSheet("font-size: 13px;");
layout->addWidget(m_enabledCheck);
auto* volLayout = new QHBoxLayout();
auto* volLabel = new QLabel("Volume:", this);
volLabel->setStyleSheet("font-size: 13px;");
volLayout->addWidget(volLabel);
m_volumeSlider = new QSlider(Qt::Horizontal, this);
m_volumeSlider->setRange(0, 100);
m_volumeSlider->setFixedWidth(200);
m_volumeSlider->setStyleSheet("QSlider::groove:horizontal { height: 6px; border-radius: 3px; background: palette(mid); }"
"QSlider::handle:horizontal { width: 14px; height: 14px; margin: -4px 0; border-radius: 7px; background: #3390EC; }");
volLayout->addWidget(m_volumeSlider);
m_volumeLabel = new QLabel("80%", this);
m_volumeLabel->setFixedWidth(36);
m_volumeLabel->setStyleSheet("font-size: 13px;");
volLayout->addWidget(m_volumeLabel);
volLayout->addStretch();
layout->addLayout(volLayout);
layout->addStretch();
connect(m_enabledCheck, &QCheckBox::stateChanged, this, &SoundSettingsPage::onEnabledChanged);
connect(m_volumeSlider, &QSlider::valueChanged, this, [this](int val) {
m_volumeLabel->setText(QString::number(val) + "%");
});
}
void SoundSettingsPage::onEnabledChanged(int state) {
m_volumeSlider->setEnabled(state == Qt::Checked);
m_volumeLabel->setEnabled(state == Qt::Checked);
}
void SoundSettingsPage::loadFromConfig(const QString& path) {
QFile f(path);
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) return;
bool enabled = true;
int volume = 80;
bool inGui = false;
QTextStream in(&f);
while (!in.atEnd()) {
QString line = in.readLine().trimmed();
if (line == "[gui]") { inGui = true; continue; }
if (line.startsWith("[") && line.endsWith("]")) inGui = false;
if (!inGui) continue;
if (line.startsWith("sound_enabled="))
enabled = line.mid(QString("sound_enabled=").size()).trimmed() != "0";
else if (line.startsWith("sound_volume="))
volume = line.mid(QString("sound_volume=").size()).trimmed().toInt();
}
f.close();
m_enabledCheck->setChecked(enabled);
m_volumeSlider->setValue(volume);
m_volumeSlider->setEnabled(enabled);
m_volumeLabel->setEnabled(enabled);
m_volumeLabel->setText(QString::number(volume) + "%");
}
void SoundSettingsPage::saveToConfig(const QString& path) const {
QFile f(path);
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) return;
QString content = f.readAll();
f.close();
QStringList lines = content.split('\n');
bool inGui = false;
bool foundEnabled = false, foundVolume = false;
for (int i = 0; i < lines.size(); i++) {
QString line = lines[i].trimmed();
if (line == "[gui]") { inGui = true; continue; }
if (line.startsWith("[") && line.endsWith("]")) inGui = false;
if (!inGui) continue;
if (line.startsWith("sound_enabled=")) {
lines[i] = QString("sound_enabled=%1").arg(m_enabledCheck->isChecked() ? 1 : 0);
foundEnabled = true;
} else if (line.startsWith("sound_volume=")) {
lines[i] = QString("sound_volume=%1").arg(m_volumeSlider->value());
foundVolume = true;
}
}
if (!foundEnabled || !foundVolume) {
for (int i = 0; i < lines.size(); i++) {
if (lines[i].trimmed() == "[gui]") {
if (!foundEnabled) lines.insert(i + 1, QString("sound_enabled=%1").arg(m_enabledCheck->isChecked() ? 1 : 0));
if (!foundVolume) lines.insert(i + 1, QString("sound_volume=%1").arg(m_volumeSlider->value()));
break;
}
}
}
f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
f.write(lines.join('\n').toUtf8());
f.close();
}