From 8266f54d7674ec7fdbe263efea163481c8b33571 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 8 Apr 2015 00:32:29 -0700 Subject: [PATCH] Volume control --- CHANGES | 1 + src/gba/audio.c | 4 +- src/gba/audio.h | 2 + src/gba/supervisor/config.c | 6 ++ src/gba/supervisor/config.h | 3 + src/gba/supervisor/thread.c | 11 ++++ src/gba/supervisor/thread.h | 2 + src/platform/qt/ConfigController.cpp | 1 + src/platform/qt/GameController.cpp | 20 ++++++ src/platform/qt/GameController.h | 2 + src/platform/qt/SettingsView.cpp | 13 ++++ src/platform/qt/SettingsView.h | 2 + src/platform/qt/SettingsView.ui | 98 +++++++++++++++++++--------- src/platform/qt/Window.cpp | 11 +++- 14 files changed, 140 insertions(+), 36 deletions(-) diff --git a/CHANGES b/CHANGES index 9bcdc3106..05bfca0f0 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,7 @@ Features: - Ability to hide individual background layers, or OBJs - Ability to mute individual audio channels - Palette viewer + - Volume control Bugfixes: - GBA: Fix timers not updating timing when writing to only the reload register - All: Fix sanitize-deb script not cleaning up after itself diff --git a/src/gba/audio.c b/src/gba/audio.c index f2f49da32..f0e06c117 100644 --- a/src/gba/audio.c +++ b/src/gba/audio.c @@ -14,6 +14,7 @@ const unsigned GBA_AUDIO_SAMPLES = 2048; const unsigned BLIP_BUFFER_SIZE = 0x4000; const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t); +const int GBA_AUDIO_VOLUME_MAX = 0x100; #define SWEEP_CYCLES (GBA_ARM7TDMI_FREQUENCY / 128) static bool _writeEnvelope(struct GBAAudioEnvelope* envelope, uint16_t value); @@ -48,6 +49,7 @@ void GBAAudioInit(struct GBAAudio* audio, size_t samples) { audio->forceDisableCh[3] = false; audio->forceDisableChA = false; audio->forceDisableChB = false; + audio->masterVolume = GBA_AUDIO_VOLUME_MAX; } void GBAAudioReset(struct GBAAudio* audio) { @@ -726,7 +728,7 @@ static int _applyBias(struct GBAAudio* audio, int sample) { } else if (sample < 0) { sample = 0; } - return (sample - GBARegisterSOUNDBIASGetBias(audio->soundbias)) << 5; + return ((sample - GBARegisterSOUNDBIASGetBias(audio->soundbias)) * audio->masterVolume) >> 3; } static void _sample(struct GBAAudio* audio) { diff --git a/src/gba/audio.h b/src/gba/audio.h index 45d60c3ee..dc16d4631 100644 --- a/src/gba/audio.h +++ b/src/gba/audio.h @@ -21,6 +21,7 @@ struct GBADMA; extern const unsigned GBA_AUDIO_SAMPLES; +extern const int GBA_AUDIO_VOLUME_MAX; DECL_BITFIELD(GBAAudioRegisterEnvelope, uint16_t); DECL_BITS(GBAAudioRegisterEnvelope, Length, 0, 6); @@ -240,6 +241,7 @@ struct GBAAudio { bool forceDisableCh[4]; bool forceDisableChA; bool forceDisableChB; + int masterVolume; }; struct GBAStereoSample { diff --git a/src/gba/supervisor/config.c b/src/gba/supervisor/config.c index 1f71c5851..437f0e104 100644 --- a/src/gba/supervisor/config.c +++ b/src/gba/supervisor/config.c @@ -179,6 +179,7 @@ void GBAConfigMap(const struct GBAConfig* config, struct GBAOptions* opts) { _lookupCharValue(config, "bios", &opts->bios); _lookupIntValue(config, "logLevel", &opts->logLevel); _lookupIntValue(config, "frameskip", &opts->frameskip); + _lookupIntValue(config, "volume", &opts->volume); _lookupIntValue(config, "rewindBufferCapacity", &opts->rewindBufferCapacity); _lookupIntValue(config, "rewindBufferInterval", &opts->rewindBufferInterval); _lookupFloatValue(config, "fpsTarget", &opts->fpsTarget); @@ -203,6 +204,9 @@ void GBAConfigMap(const struct GBAConfig* config, struct GBAOptions* opts) { if (_lookupIntValue(config, "resampleVideo", &fakeBool)) { opts->resampleVideo = fakeBool; } + if (_lookupIntValue(config, "mute", &fakeBool)) { + opts->mute = fakeBool; + } if (_lookupIntValue(config, "skipBios", &fakeBool)) { opts->skipBios = fakeBool; } @@ -243,6 +247,8 @@ void GBAConfigLoadDefaults(struct GBAConfig* config, const struct GBAOptions* op ConfigurationSetIntValue(&config->defaultsTable, 0, "fullscreen", opts->fullscreen); ConfigurationSetIntValue(&config->defaultsTable, 0, "width", opts->width); ConfigurationSetIntValue(&config->defaultsTable, 0, "height", opts->height); + ConfigurationSetIntValue(&config->defaultsTable, 0, "volume", opts->volume); + ConfigurationSetIntValue(&config->defaultsTable, 0, "mute", opts->mute); ConfigurationSetIntValue(&config->defaultsTable, 0, "lockAspectRatio", opts->lockAspectRatio); ConfigurationSetIntValue(&config->defaultsTable, 0, "resampleVideo", opts->resampleVideo); diff --git a/src/gba/supervisor/config.h b/src/gba/supervisor/config.h index 369bdbd29..fd3eaba82 100644 --- a/src/gba/supervisor/config.h +++ b/src/gba/supervisor/config.h @@ -36,6 +36,9 @@ struct GBAOptions { bool lockAspectRatio; bool resampleVideo; + int volume; + bool mute; + bool videoSync; bool audioSync; diff --git a/src/gba/supervisor/thread.c b/src/gba/supervisor/thread.c index c595d21d1..75da09eff 100644 --- a/src/gba/supervisor/thread.c +++ b/src/gba/supervisor/thread.c @@ -233,6 +233,15 @@ static THREAD_ENTRY _GBAThreadRun(void* context) { GBASIOSetDriverSet(&gba.sio, &threadContext->sioDrivers); + if (threadContext->volume == 0) { + threadContext->volume = GBA_AUDIO_VOLUME_MAX; + } + if (threadContext->mute) { + gba.audio.volume = 0; + } else { + gba.audio.volume = threadContext->volume; + } + gba.keySource = &threadContext->activeKeys; if (threadContext->startCallback) { @@ -316,6 +325,8 @@ void GBAMapOptionsToContext(const struct GBAOptions* opts, struct GBAThread* thr threadContext->bios = 0; } threadContext->frameskip = opts->frameskip; + threadContext->volume = opts->volume; + threadContext->mute = opts->mute; threadContext->logLevel = opts->logLevel; if (opts->rewindEnable) { threadContext->rewindBufferCapacity = opts->rewindBufferCapacity; diff --git a/src/gba/supervisor/thread.h b/src/gba/supervisor/thread.h index 7a2a3778b..caa160bea 100644 --- a/src/gba/supervisor/thread.h +++ b/src/gba/supervisor/thread.h @@ -80,6 +80,8 @@ struct GBAThread { float fpsTarget; size_t audioBuffers; bool skipBios; + int volume; + bool mute; // Threading state Thread thread; diff --git a/src/platform/qt/ConfigController.cpp b/src/platform/qt/ConfigController.cpp index ba21ff288..9857727d8 100644 --- a/src/platform/qt/ConfigController.cpp +++ b/src/platform/qt/ConfigController.cpp @@ -108,6 +108,7 @@ ConfigController::ConfigController(QObject* parent) m_opts.videoSync = GameController::VIDEO_SYNC; m_opts.fpsTarget = 60; m_opts.audioBuffers = 2048; + m_opts.volume = GBA_AUDIO_VOLUME_MAX; m_opts.logLevel = GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL; m_opts.rewindEnable = false; m_opts.rewindBufferInterval = 0; diff --git a/src/platform/qt/GameController.cpp b/src/platform/qt/GameController.cpp index 44d9e7ddc..fb8aa8da2 100644 --- a/src/platform/qt/GameController.cpp +++ b/src/platform/qt/GameController.cpp @@ -186,6 +186,8 @@ void GameController::setOptions(const GBAOptions* opts) { setSkipBIOS(opts->skipBios); setUseBIOS(opts->useBios); setRewind(opts->rewindEnable, opts->rewindBufferCapacity, opts->rewindBufferInterval); + setVolume(opts->volume); + setMute(opts->mute); threadInterrupt(); m_threadContext.idleOptimization = opts->idleOptimization; @@ -496,6 +498,24 @@ void GameController::setFrameskip(int skip) { m_threadContext.frameskip = skip; } +void GameController::setVolume(int volume) { + threadInterrupt(); + m_threadContext.volume = volume; + if (m_gameOpen) { + m_threadContext.gba->audio.masterVolume = volume; + } + threadContinue(); +} + +void GameController::setMute(bool mute) { + threadInterrupt(); + m_threadContext.mute = mute; + if (m_gameOpen) { + m_threadContext.gba->audio.masterVolume = mute ? 0 : m_threadContext.volume; + } + threadContinue(); +} + void GameController::setTurbo(bool set, bool forced) { if (m_turboForced && !forced) { return; diff --git a/src/platform/qt/GameController.h b/src/platform/qt/GameController.h index 0869a59a0..3bb54dc7d 100644 --- a/src/platform/qt/GameController.h +++ b/src/platform/qt/GameController.h @@ -114,6 +114,8 @@ public slots: void setVideoSync(bool); void setAudioSync(bool); void setFrameskip(int); + void setVolume(int); + void setMute(bool); void setTurbo(bool, bool forced = true); void setAVStream(GBAAVStream*); void clearAVStream(); diff --git a/src/platform/qt/SettingsView.cpp b/src/platform/qt/SettingsView.cpp index b50ff95a4..44aa13a20 100644 --- a/src/platform/qt/SettingsView.cpp +++ b/src/platform/qt/SettingsView.cpp @@ -27,6 +27,8 @@ SettingsView::SettingsView(ConfigController* controller, QWidget* parent) loadSetting("frameskip", m_ui.frameskip); loadSetting("fpsTarget", m_ui.fpsTarget); loadSetting("lockAspectRatio", m_ui.lockAspectRatio); + loadSetting("volume", m_ui.volume); + loadSetting("mute", m_ui.mute); loadSetting("rewindEnable", m_ui.rewind); loadSetting("rewindBufferInterval", m_ui.rewindInterval); loadSetting("rewindBufferCapacity", m_ui.rewindCapacity); @@ -78,6 +80,8 @@ void SettingsView::updateConfig() { saveSetting("frameskip", m_ui.frameskip); saveSetting("fpsTarget", m_ui.fpsTarget); saveSetting("lockAspectRatio", m_ui.lockAspectRatio); + saveSetting("volume", m_ui.volume); + saveSetting("mute", m_ui.mute); saveSetting("rewindEnable", m_ui.rewind); saveSetting("rewindBufferInterval", m_ui.rewindInterval); saveSetting("rewindBufferCapacity", m_ui.rewindCapacity); @@ -121,6 +125,10 @@ void SettingsView::saveSetting(const char* key, const QLineEdit* field) { saveSetting(key, field->text()); } +void SettingsView::saveSetting(const char* key, const QSlider* field) { + saveSetting(key, QString::number(field->value())); +} + void SettingsView::saveSetting(const char* key, const QSpinBox* field) { saveSetting(key, field->cleanText()); } @@ -144,6 +152,11 @@ void SettingsView::loadSetting(const char* key, QLineEdit* field) { field->setText(option); } +void SettingsView::loadSetting(const char* key, QSlider* field) { + QString option = loadSetting(key); + field->setValue(option.toInt()); +} + void SettingsView::loadSetting(const char* key, QSpinBox* field) { QString option = loadSetting(key); field->setValue(option.toInt()); diff --git a/src/platform/qt/SettingsView.h b/src/platform/qt/SettingsView.h index 73694facd..0b0d4f211 100644 --- a/src/platform/qt/SettingsView.h +++ b/src/platform/qt/SettingsView.h @@ -36,12 +36,14 @@ private: void saveSetting(const char* key, const QAbstractButton*); void saveSetting(const char* key, const QComboBox*); void saveSetting(const char* key, const QLineEdit*); + void saveSetting(const char* key, const QSlider*); void saveSetting(const char* key, const QSpinBox*); void saveSetting(const char* key, const QString&); void loadSetting(const char* key, QAbstractButton*); void loadSetting(const char* key, QComboBox*); void loadSetting(const char* key, QLineEdit*); + void loadSetting(const char* key, QSlider*); void loadSetting(const char* key, QSpinBox*); QString loadSetting(const char* key); }; diff --git a/src/platform/qt/SettingsView.ui b/src/platform/qt/SettingsView.ui index c9fc145f8..b7e371dea 100644 --- a/src/platform/qt/SettingsView.ui +++ b/src/platform/qt/SettingsView.ui @@ -6,8 +6,8 @@ 0 0 - 360 - 569 + 374 + 608 @@ -146,13 +146,54 @@ + + + Volume: + + + + + + + + + 256 + + + 16 + + + 256 + + + Qt::Horizontal + + + + + + + Mute + + + + + + + + + Qt::Horizontal + + + + Sync: - + @@ -170,14 +211,14 @@ - + Frameskip: - + @@ -198,14 +239,14 @@ - + FPS target: - + @@ -226,49 +267,42 @@ - - - - Qt::Horizontal - - - - + Lock aspect ratio - + Resample video - + Qt::Horizontal - + Enable rewind - + Rewind interval: - + @@ -289,14 +323,14 @@ - + Rewind length: - + @@ -310,21 +344,28 @@ - + + + + Allow opposing input directions + + + + Qt::Horizontal - + Idle loops - + @@ -343,13 +384,6 @@ - - - - Allow opposing input directions - - - diff --git a/src/platform/qt/Window.cpp b/src/platform/qt/Window.cpp index 3076593fb..fecd59a1d 100644 --- a/src/platform/qt/Window.cpp +++ b/src/platform/qt/Window.cpp @@ -891,9 +891,14 @@ void Window::setupMenu(QMenuBar* menubar) { m_controller->setSkipBIOS(value.toBool()); }, this); - ConfigOption* useBios = m_config->addOption("useBios"); - useBios->connect([this](const QVariant& value) { - m_controller->setUseBIOS(value.toBool()); + ConfigOption* volume = m_config->addOption("volume"); + volume->connect([this](const QVariant& value) { + m_controller->setVolume(value.toInt()); + }, this); + + ConfigOption* mute = m_config->addOption("mute"); + mute->connect([this](const QVariant& value) { + m_controller->setMute(value.toBool()); }, this); ConfigOption* rewindEnable = m_config->addOption("rewindEnable");