aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Schickel2011-10-29 00:07:30 +0200
committerJohannes Schickel2011-10-29 01:00:18 +0200
commitd0bc84d5b7fd9fea384ee25f22720b68ee78a83b (patch)
treeb32cc35e9f48be87b77f388f44e11561b1856ce8
parentd186fcf3434a2c25a7dcde147df9859e76fdc364 (diff)
downloadscummvm-rg350-d0bc84d5b7fd9fea384ee25f22720b68ee78a83b.tar.gz
scummvm-rg350-d0bc84d5b7fd9fea384ee25f22720b68ee78a83b.tar.bz2
scummvm-rg350-d0bc84d5b7fd9fea384ee25f22720b68ee78a83b.zip
KYRA: Implemented LoL style volume control in AdLib output.
-rw-r--r--engines/kyra/sound_adlib.cpp129
-rw-r--r--engines/kyra/sound_adlib.h2
2 files changed, 121 insertions, 10 deletions
diff --git a/engines/kyra/sound_adlib.cpp b/engines/kyra/sound_adlib.cpp
index 8976eba99c..5bbfd024a5 100644
--- a/engines/kyra/sound_adlib.cpp
+++ b/engines/kyra/sound_adlib.cpp
@@ -42,6 +42,7 @@
#include "common/system.h"
#include "common/mutex.h"
+#include "common/config-manager.h"
#include "audio/mixer.h"
#include "audio/fmopl.h"
@@ -92,6 +93,9 @@ public:
void setSyncJumpMask(uint16 mask) { _syncJumpMask = mask; }
+ void setMusicVolume(uint8 volume);
+ void setSfxVolume(uint8 volume);
+
private:
struct OpcodeEntry {
typedef int (AdLibDriver::*DriverOpcode)(va_list &list);
@@ -195,6 +199,7 @@ private:
uint8 tempoReset;
uint8 rawNote;
int8 unk16;
+ uint8 volumeModifier;
};
void primaryEffect1(Channel &channel);
@@ -406,6 +411,8 @@ private:
Audio::Mixer *_mixer;
Audio::SoundHandle _soundHandle;
+ uint8 _musicVolume, _sfxVolume;
+
bool _v2;
};
@@ -441,14 +448,7 @@ AdLibDriver::AdLibDriver(Audio::Mixer *mixer, bool v2) {
_tablePtr1 = _tablePtr2 = 0;
- // HACK: We use MusicSoundType here for now so we can adjust the volume in the launcher dialog.
- // This affects SFX too, but if we want to support different volumes for SFX and music we would
- // have to change our player implementation, currently we setup the volume for an AdLib channel
- // in AdLibDriver::adjustVolume, so if that would be called, we would have to know if the channel
- // is used by SFX or music, and then adjust the volume accordingly. Since Kyrandia 2 supports
- // different volumes for SFX and music, looking at the disasm and checking how the original does it
- // would be a good idea.
- _mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+ _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
_samplesPerCallback = getRate() / CALLBACKS_PER_SECOND;
_samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND;
@@ -456,6 +456,9 @@ AdLibDriver::AdLibDriver(Audio::Mixer *mixer, bool v2) {
_samplesTillCallbackRemainder = 0;
_syncJumpMask = 0;
+
+ _musicVolume = 0;
+ _sfxVolume = 0;
}
AdLibDriver::~AdLibDriver() {
@@ -464,6 +467,60 @@ AdLibDriver::~AdLibDriver() {
_adlib = 0;
}
+void AdLibDriver::setMusicVolume(uint8 volume) {
+ Common::StackLock lock(_mutex);
+
+ _musicVolume = volume;
+
+ for (uint i = 0; i < 6; ++i) {
+ Channel &chan = _channels[i];
+ chan.volumeModifier = volume;
+
+ const uint8 regOffset = _regOffset[i];
+
+ // Level Key Scaling / Total Level
+ writeOPL(0x40 + regOffset, calculateOpLevel1(chan));
+ writeOPL(0x43 + regOffset, calculateOpLevel2(chan));
+ }
+
+ // For now we use the music volume for both sfx and music in Kyra1.
+ if (!_v2) {
+ _sfxVolume = volume;
+
+ for (uint i = 6; i < 9; ++i) {
+ Channel &chan = _channels[i];
+ chan.volumeModifier = volume;
+
+ const uint8 regOffset = _regOffset[i];
+
+ // Level Key Scaling / Total Level
+ writeOPL(0x40 + regOffset, calculateOpLevel1(chan));
+ writeOPL(0x43 + regOffset, calculateOpLevel2(chan));
+ }
+ }
+}
+
+void AdLibDriver::setSfxVolume(uint8 volume) {
+ // We only support sfx volume in v2 games.
+ if (!_v2)
+ return;
+
+ Common::StackLock lock(_mutex);
+
+ _sfxVolume = volume;
+
+ for (uint i = 6; i < 9; ++i) {
+ Channel &chan = _channels[i];
+ chan.volumeModifier = volume;
+
+ const uint8 regOffset = _regOffset[i];
+
+ // Level Key Scaling / Total Level
+ writeOPL(0x40 + regOffset, calculateOpLevel1(chan));
+ writeOPL(0x43 + regOffset, calculateOpLevel2(chan));
+ }
+}
+
int AdLibDriver::callback(int opcode, ...) {
Common::StackLock lock(_mutex);
if (opcode >= _opcodesEntries || opcode < 0) {
@@ -662,6 +719,12 @@ void AdLibDriver::setupPrograms() {
channel.tempo = 0xFF;
channel.position = 0xFF;
channel.duration = 1;
+
+ if (chan <= 5)
+ channel.volumeModifier = _musicVolume;
+ else
+ channel.volumeModifier = _sfxVolume;
+
unkOutput2(chan);
}
@@ -1273,9 +1336,21 @@ uint8 AdLibDriver::calculateOpLevel1(Channel &channel) {
if (channel.twoChan) {
value += channel.opExtraLevel1;
value += channel.opExtraLevel2;
- value += channel.opExtraLevel3;
+
+ uint16 level3 = (channel.opExtraLevel3 ^ 0x3F) * channel.volumeModifier;
+ if (level3) {
+ level3 += 0x3F;
+ level3 >>= 8;
+ }
+
+ value += level3 ^ 0x3F;
}
+ value = CLIP<int8>(value, 0, 0x3F);
+
+ if (!channel.volumeModifier)
+ value = 0x3F;
+
// Preserve the scaling level bits from opLevel1
return checkValue(value) | (channel.opLevel1 & 0xC0);
@@ -1286,7 +1361,19 @@ uint8 AdLibDriver::calculateOpLevel2(Channel &channel) {
value += channel.opExtraLevel1;
value += channel.opExtraLevel2;
- value += channel.opExtraLevel3;
+
+ uint16 level3 = (channel.opExtraLevel3 ^ 0x3F) * channel.volumeModifier;
+ if (level3) {
+ level3 += 0x3F;
+ level3 >>= 8;
+ }
+
+ value += level3 ^ 0x3F;
+
+ value = CLIP<int8>(value, 0, 0x3F);
+
+ if (!channel.volumeModifier)
+ value = 0x3F;
// Preserve the scaling level bits from opLevel2
@@ -1331,6 +1418,12 @@ int AdLibDriver::update_setupProgram(uint8 *&dataptr, Channel &channel, uint8 va
channel2.tempo = 0xFF;
channel2.position = 0xFF;
channel2.duration = 1;
+
+ if (chan <= 5)
+ channel2.volumeModifier = _musicVolume;
+ else
+ channel2.volumeModifier = _sfxVolume;
+
unkOutput2(chan);
}
@@ -2285,6 +2378,22 @@ void SoundAdLibPC::process() {
}
}
+void SoundAdLibPC::updateVolumeSettings() {
+ bool mute = false;
+ if (ConfMan.hasKey("mute"))
+ mute = ConfMan.getBool("mute");
+
+ int newMusicVolume = mute ? 0 : ConfMan.getInt("music_volume");
+ //newMusicVolume = (newMusicVolume * 145) / Audio::Mixer::kMaxMixerVolume + 110;
+ newMusicVolume = CLIP(newMusicVolume, 0, 255);
+ int newSfxVolume = mute ? 0 : ConfMan.getInt("sfx_volume");
+ //newSfxVolume = (newSfxVolume * 200) / Audio::Mixer::kMaxMixerVolume + 55;
+ newSfxVolume = CLIP(newSfxVolume, 0, 255);
+
+ _driver->setMusicVolume(newMusicVolume);
+ _driver->setSfxVolume(newSfxVolume);
+}
+
void SoundAdLibPC::playTrack(uint8 track) {
if (_musicEnabled) {
// WORKAROUND: There is a bug in the Kyra 1 "Pool of Sorrow"
diff --git a/engines/kyra/sound_adlib.h b/engines/kyra/sound_adlib.h
index c09fec997e..0cad8e32bd 100644
--- a/engines/kyra/sound_adlib.h
+++ b/engines/kyra/sound_adlib.h
@@ -67,6 +67,8 @@ public:
bool init();
void process();
+ virtual void updateVolumeSettings();
+
void loadSoundFile(uint file);
void loadSoundFile(Common::String file);
void loadSoundFile(const uint8 *soundData, int dataSize) {}