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 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

View File

@ -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) {

View File

@ -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 {

View File

@ -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);

View File

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

View File

@ -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;

View File

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

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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());

View File

@ -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);
};

View File

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

View File

@ -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");