Volume control

This commit is contained in:
Jeffrey Pfau 2015-04-08 00:32:29 -07:00
parent 3182b5e35d
commit 8266f54d76
14 changed files with 140 additions and 36 deletions

View File

@ -3,6 +3,7 @@ Features:
- Ability to hide individual background layers, or OBJs - Ability to hide individual background layers, or OBJs
- Ability to mute individual audio channels - Ability to mute individual audio channels
- Palette viewer - Palette viewer
- Volume control
Bugfixes: Bugfixes:
- GBA: Fix timers not updating timing when writing to only the reload register - GBA: Fix timers not updating timing when writing to only the reload register
- All: Fix sanitize-deb script not cleaning up after itself - All: Fix sanitize-deb script not cleaning up after itself

View File

@ -14,6 +14,7 @@
const unsigned GBA_AUDIO_SAMPLES = 2048; const unsigned GBA_AUDIO_SAMPLES = 2048;
const unsigned BLIP_BUFFER_SIZE = 0x4000; const unsigned BLIP_BUFFER_SIZE = 0x4000;
const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t); const unsigned GBA_AUDIO_FIFO_SIZE = 8 * sizeof(int32_t);
const int GBA_AUDIO_VOLUME_MAX = 0x100;
#define SWEEP_CYCLES (GBA_ARM7TDMI_FREQUENCY / 128) #define SWEEP_CYCLES (GBA_ARM7TDMI_FREQUENCY / 128)
static bool _writeEnvelope(struct GBAAudioEnvelope* envelope, uint16_t value); 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->forceDisableCh[3] = false;
audio->forceDisableChA = false; audio->forceDisableChA = false;
audio->forceDisableChB = false; audio->forceDisableChB = false;
audio->masterVolume = GBA_AUDIO_VOLUME_MAX;
} }
void GBAAudioReset(struct GBAAudio* audio) { void GBAAudioReset(struct GBAAudio* audio) {
@ -726,7 +728,7 @@ static int _applyBias(struct GBAAudio* audio, int sample) {
} else if (sample < 0) { } else if (sample < 0) {
sample = 0; sample = 0;
} }
return (sample - GBARegisterSOUNDBIASGetBias(audio->soundbias)) << 5; return ((sample - GBARegisterSOUNDBIASGetBias(audio->soundbias)) * audio->masterVolume) >> 3;
} }
static void _sample(struct GBAAudio* audio) { static void _sample(struct GBAAudio* audio) {

View File

@ -21,6 +21,7 @@
struct GBADMA; struct GBADMA;
extern const unsigned GBA_AUDIO_SAMPLES; extern const unsigned GBA_AUDIO_SAMPLES;
extern const int GBA_AUDIO_VOLUME_MAX;
DECL_BITFIELD(GBAAudioRegisterEnvelope, uint16_t); DECL_BITFIELD(GBAAudioRegisterEnvelope, uint16_t);
DECL_BITS(GBAAudioRegisterEnvelope, Length, 0, 6); DECL_BITS(GBAAudioRegisterEnvelope, Length, 0, 6);
@ -240,6 +241,7 @@ struct GBAAudio {
bool forceDisableCh[4]; bool forceDisableCh[4];
bool forceDisableChA; bool forceDisableChA;
bool forceDisableChB; bool forceDisableChB;
int masterVolume;
}; };
struct GBAStereoSample { struct GBAStereoSample {

View File

@ -179,6 +179,7 @@ void GBAConfigMap(const struct GBAConfig* config, struct GBAOptions* opts) {
_lookupCharValue(config, "bios", &opts->bios); _lookupCharValue(config, "bios", &opts->bios);
_lookupIntValue(config, "logLevel", &opts->logLevel); _lookupIntValue(config, "logLevel", &opts->logLevel);
_lookupIntValue(config, "frameskip", &opts->frameskip); _lookupIntValue(config, "frameskip", &opts->frameskip);
_lookupIntValue(config, "volume", &opts->volume);
_lookupIntValue(config, "rewindBufferCapacity", &opts->rewindBufferCapacity); _lookupIntValue(config, "rewindBufferCapacity", &opts->rewindBufferCapacity);
_lookupIntValue(config, "rewindBufferInterval", &opts->rewindBufferInterval); _lookupIntValue(config, "rewindBufferInterval", &opts->rewindBufferInterval);
_lookupFloatValue(config, "fpsTarget", &opts->fpsTarget); _lookupFloatValue(config, "fpsTarget", &opts->fpsTarget);
@ -203,6 +204,9 @@ void GBAConfigMap(const struct GBAConfig* config, struct GBAOptions* opts) {
if (_lookupIntValue(config, "resampleVideo", &fakeBool)) { if (_lookupIntValue(config, "resampleVideo", &fakeBool)) {
opts->resampleVideo = fakeBool; opts->resampleVideo = fakeBool;
} }
if (_lookupIntValue(config, "mute", &fakeBool)) {
opts->mute = fakeBool;
}
if (_lookupIntValue(config, "skipBios", &fakeBool)) { if (_lookupIntValue(config, "skipBios", &fakeBool)) {
opts->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, "fullscreen", opts->fullscreen);
ConfigurationSetIntValue(&config->defaultsTable, 0, "width", opts->width); ConfigurationSetIntValue(&config->defaultsTable, 0, "width", opts->width);
ConfigurationSetIntValue(&config->defaultsTable, 0, "height", opts->height); 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, "lockAspectRatio", opts->lockAspectRatio);
ConfigurationSetIntValue(&config->defaultsTable, 0, "resampleVideo", opts->resampleVideo); ConfigurationSetIntValue(&config->defaultsTable, 0, "resampleVideo", opts->resampleVideo);

View File

@ -36,6 +36,9 @@ struct GBAOptions {
bool lockAspectRatio; bool lockAspectRatio;
bool resampleVideo; bool resampleVideo;
int volume;
bool mute;
bool videoSync; bool videoSync;
bool audioSync; bool audioSync;

View File

@ -233,6 +233,15 @@ static THREAD_ENTRY _GBAThreadRun(void* context) {
GBASIOSetDriverSet(&gba.sio, &threadContext->sioDrivers); 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; gba.keySource = &threadContext->activeKeys;
if (threadContext->startCallback) { if (threadContext->startCallback) {
@ -316,6 +325,8 @@ void GBAMapOptionsToContext(const struct GBAOptions* opts, struct GBAThread* thr
threadContext->bios = 0; threadContext->bios = 0;
} }
threadContext->frameskip = opts->frameskip; threadContext->frameskip = opts->frameskip;
threadContext->volume = opts->volume;
threadContext->mute = opts->mute;
threadContext->logLevel = opts->logLevel; threadContext->logLevel = opts->logLevel;
if (opts->rewindEnable) { if (opts->rewindEnable) {
threadContext->rewindBufferCapacity = opts->rewindBufferCapacity; threadContext->rewindBufferCapacity = opts->rewindBufferCapacity;

View File

@ -80,6 +80,8 @@ struct GBAThread {
float fpsTarget; float fpsTarget;
size_t audioBuffers; size_t audioBuffers;
bool skipBios; bool skipBios;
int volume;
bool mute;
// Threading state // Threading state
Thread thread; Thread thread;

View File

@ -108,6 +108,7 @@ ConfigController::ConfigController(QObject* parent)
m_opts.videoSync = GameController::VIDEO_SYNC; m_opts.videoSync = GameController::VIDEO_SYNC;
m_opts.fpsTarget = 60; m_opts.fpsTarget = 60;
m_opts.audioBuffers = 2048; 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.logLevel = GBA_LOG_WARN | GBA_LOG_ERROR | GBA_LOG_FATAL;
m_opts.rewindEnable = false; m_opts.rewindEnable = false;
m_opts.rewindBufferInterval = 0; m_opts.rewindBufferInterval = 0;

View File

@ -186,6 +186,8 @@ void GameController::setOptions(const GBAOptions* opts) {
setSkipBIOS(opts->skipBios); setSkipBIOS(opts->skipBios);
setUseBIOS(opts->useBios); setUseBIOS(opts->useBios);
setRewind(opts->rewindEnable, opts->rewindBufferCapacity, opts->rewindBufferInterval); setRewind(opts->rewindEnable, opts->rewindBufferCapacity, opts->rewindBufferInterval);
setVolume(opts->volume);
setMute(opts->mute);
threadInterrupt(); threadInterrupt();
m_threadContext.idleOptimization = opts->idleOptimization; m_threadContext.idleOptimization = opts->idleOptimization;
@ -496,6 +498,24 @@ void GameController::setFrameskip(int skip) {
m_threadContext.frameskip = 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) { void GameController::setTurbo(bool set, bool forced) {
if (m_turboForced && !forced) { if (m_turboForced && !forced) {
return; return;

View File

@ -114,6 +114,8 @@ public slots:
void setVideoSync(bool); void setVideoSync(bool);
void setAudioSync(bool); void setAudioSync(bool);
void setFrameskip(int); void setFrameskip(int);
void setVolume(int);
void setMute(bool);
void setTurbo(bool, bool forced = true); void setTurbo(bool, bool forced = true);
void setAVStream(GBAAVStream*); void setAVStream(GBAAVStream*);
void clearAVStream(); void clearAVStream();

View File

@ -27,6 +27,8 @@ SettingsView::SettingsView(ConfigController* controller, QWidget* parent)
loadSetting("frameskip", m_ui.frameskip); loadSetting("frameskip", m_ui.frameskip);
loadSetting("fpsTarget", m_ui.fpsTarget); loadSetting("fpsTarget", m_ui.fpsTarget);
loadSetting("lockAspectRatio", m_ui.lockAspectRatio); loadSetting("lockAspectRatio", m_ui.lockAspectRatio);
loadSetting("volume", m_ui.volume);
loadSetting("mute", m_ui.mute);
loadSetting("rewindEnable", m_ui.rewind); loadSetting("rewindEnable", m_ui.rewind);
loadSetting("rewindBufferInterval", m_ui.rewindInterval); loadSetting("rewindBufferInterval", m_ui.rewindInterval);
loadSetting("rewindBufferCapacity", m_ui.rewindCapacity); loadSetting("rewindBufferCapacity", m_ui.rewindCapacity);
@ -78,6 +80,8 @@ void SettingsView::updateConfig() {
saveSetting("frameskip", m_ui.frameskip); saveSetting("frameskip", m_ui.frameskip);
saveSetting("fpsTarget", m_ui.fpsTarget); saveSetting("fpsTarget", m_ui.fpsTarget);
saveSetting("lockAspectRatio", m_ui.lockAspectRatio); saveSetting("lockAspectRatio", m_ui.lockAspectRatio);
saveSetting("volume", m_ui.volume);
saveSetting("mute", m_ui.mute);
saveSetting("rewindEnable", m_ui.rewind); saveSetting("rewindEnable", m_ui.rewind);
saveSetting("rewindBufferInterval", m_ui.rewindInterval); saveSetting("rewindBufferInterval", m_ui.rewindInterval);
saveSetting("rewindBufferCapacity", m_ui.rewindCapacity); saveSetting("rewindBufferCapacity", m_ui.rewindCapacity);
@ -121,6 +125,10 @@ void SettingsView::saveSetting(const char* key, const QLineEdit* field) {
saveSetting(key, field->text()); 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) { void SettingsView::saveSetting(const char* key, const QSpinBox* field) {
saveSetting(key, field->cleanText()); saveSetting(key, field->cleanText());
} }
@ -144,6 +152,11 @@ void SettingsView::loadSetting(const char* key, QLineEdit* field) {
field->setText(option); 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) { void SettingsView::loadSetting(const char* key, QSpinBox* field) {
QString option = loadSetting(key); QString option = loadSetting(key);
field->setValue(option.toInt()); field->setValue(option.toInt());

View File

@ -36,12 +36,14 @@ private:
void saveSetting(const char* key, const QAbstractButton*); void saveSetting(const char* key, const QAbstractButton*);
void saveSetting(const char* key, const QComboBox*); void saveSetting(const char* key, const QComboBox*);
void saveSetting(const char* key, const QLineEdit*); 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 QSpinBox*);
void saveSetting(const char* key, const QString&); void saveSetting(const char* key, const QString&);
void loadSetting(const char* key, QAbstractButton*); void loadSetting(const char* key, QAbstractButton*);
void loadSetting(const char* key, QComboBox*); void loadSetting(const char* key, QComboBox*);
void loadSetting(const char* key, QLineEdit*); void loadSetting(const char* key, QLineEdit*);
void loadSetting(const char* key, QSlider*);
void loadSetting(const char* key, QSpinBox*); void loadSetting(const char* key, QSpinBox*);
QString loadSetting(const char* key); QString loadSetting(const char* key);
}; };

View File

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>360</width> <width>374</width>
<height>569</height> <height>608</height>
</rect> </rect>
</property> </property>
<property name="sizePolicy"> <property name="sizePolicy">
@ -146,13 +146,54 @@
</layout> </layout>
</item> </item>
<item row="6" column="0"> <item row="6" column="0">
<widget class="QLabel" name="label_16">
<property name="text">
<string>Volume:</string>
</property>
</widget>
</item>
<item row="6" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QSlider" name="volume">
<property name="maximum">
<number>256</number>
</property>
<property name="pageStep">
<number>16</number>
</property>
<property name="value">
<number>256</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="mute">
<property name="text">
<string>Mute</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="7" column="0" colspan="2">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_2"> <widget class="QLabel" name="label_2">
<property name="text"> <property name="text">
<string>Sync:</string> <string>Sync:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="1"> <item row="8" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_10"> <layout class="QHBoxLayout" name="horizontalLayout_10">
<item> <item>
<widget class="QCheckBox" name="videoSync"> <widget class="QCheckBox" name="videoSync">
@ -170,14 +211,14 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="7" column="0"> <item row="9" column="0">
<widget class="QLabel" name="label_9"> <widget class="QLabel" name="label_9">
<property name="text"> <property name="text">
<string>Frameskip:</string> <string>Frameskip:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="1"> <item row="9" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_16"> <layout class="QHBoxLayout" name="horizontalLayout_16">
<item> <item>
<widget class="QLabel" name="label_12"> <widget class="QLabel" name="label_12">
@ -198,14 +239,14 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="8" column="0"> <item row="10" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">
<property name="text"> <property name="text">
<string>FPS target:</string> <string>FPS target:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="1"> <item row="10" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_2"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<item> <item>
<widget class="QSpinBox" name="fpsTarget"> <widget class="QSpinBox" name="fpsTarget">
@ -226,49 +267,42 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="9" column="0" colspan="2"> <item row="11" column="1">
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QCheckBox" name="lockAspectRatio"> <widget class="QCheckBox" name="lockAspectRatio">
<property name="text"> <property name="text">
<string>Lock aspect ratio</string> <string>Lock aspect ratio</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="11" column="1"> <item row="12" column="1">
<widget class="QCheckBox" name="resampleVideo"> <widget class="QCheckBox" name="resampleVideo">
<property name="text"> <property name="text">
<string>Resample video</string> <string>Resample video</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="12" column="0" colspan="2"> <item row="13" column="0" colspan="2">
<widget class="Line" name="line_3"> <widget class="Line" name="line_3">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item row="13" column="1"> <item row="14" column="1">
<widget class="QCheckBox" name="rewind"> <widget class="QCheckBox" name="rewind">
<property name="text"> <property name="text">
<string>Enable rewind</string> <string>Enable rewind</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="14" column="0"> <item row="15" column="0">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_4">
<property name="text"> <property name="text">
<string>Rewind interval:</string> <string>Rewind interval:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="14" column="1"> <item row="15" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_12"> <layout class="QHBoxLayout" name="horizontalLayout_12">
<item> <item>
<widget class="QLabel" name="label_5"> <widget class="QLabel" name="label_5">
@ -289,14 +323,14 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="15" column="0"> <item row="16" column="0">
<widget class="QLabel" name="label_8"> <widget class="QLabel" name="label_8">
<property name="text"> <property name="text">
<string>Rewind length:</string> <string>Rewind length:</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="15" column="1"> <item row="16" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_13"> <layout class="QHBoxLayout" name="horizontalLayout_13">
<item> <item>
<widget class="QSpinBox" name="rewindCapacity"/> <widget class="QSpinBox" name="rewindCapacity"/>
@ -310,21 +344,28 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="17" column="0" colspan="2"> <item row="17" column="1">
<widget class="QCheckBox" name="allowOpposingDirections">
<property name="text">
<string>Allow opposing input directions</string>
</property>
</widget>
</item>
<item row="18" column="0" colspan="2">
<widget class="Line" name="line_4"> <widget class="Line" name="line_4">
<property name="orientation"> <property name="orientation">
<enum>Qt::Horizontal</enum> <enum>Qt::Horizontal</enum>
</property> </property>
</widget> </widget>
</item> </item>
<item row="18" column="0"> <item row="19" column="0">
<widget class="QLabel" name="label_15"> <widget class="QLabel" name="label_15">
<property name="text"> <property name="text">
<string>Idle loops</string> <string>Idle loops</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="18" column="1"> <item row="19" column="1">
<widget class="QComboBox" name="idleOptimization"> <widget class="QComboBox" name="idleOptimization">
<item> <item>
<property name="text"> <property name="text">
@ -343,13 +384,6 @@
</item> </item>
</widget> </widget>
</item> </item>
<item row="16" column="1">
<widget class="QCheckBox" name="allowOpposingDirections">
<property name="text">
<string>Allow opposing input directions</string>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
<item> <item>

View File

@ -891,9 +891,14 @@ void Window::setupMenu(QMenuBar* menubar) {
m_controller->setSkipBIOS(value.toBool()); m_controller->setSkipBIOS(value.toBool());
}, this); }, this);
ConfigOption* useBios = m_config->addOption("useBios"); ConfigOption* volume = m_config->addOption("volume");
useBios->connect([this](const QVariant& value) { volume->connect([this](const QVariant& value) {
m_controller->setUseBIOS(value.toBool()); m_controller->setVolume(value.toInt());
}, this);
ConfigOption* mute = m_config->addOption("mute");
mute->connect([this](const QVariant& value) {
m_controller->setMute(value.toBool());
}, this); }, this);
ConfigOption* rewindEnable = m_config->addOption("rewindEnable"); ConfigOption* rewindEnable = m_config->addOption("rewindEnable");