diff options
Diffstat (limited to 'engines/gob/sound/adlib.cpp')
-rw-r--r-- | engines/gob/sound/adlib.cpp | 140 |
1 files changed, 80 insertions, 60 deletions
diff --git a/engines/gob/sound/adlib.cpp b/engines/gob/sound/adlib.cpp index 65b43cae7a..2a9a716058 100644 --- a/engines/gob/sound/adlib.cpp +++ b/engines/gob/sound/adlib.cpp @@ -37,6 +37,28 @@ static const int kPitchTomToSnare = 7; static const int kPitchSnareDrum = kPitchTom + kPitchTomToSnare; +// Attenuation map for GUI volume slider +// Note: no volume control in the original engine +const uint8 AdLib::kVolumeTable[Audio::Mixer::kMaxMixerVolume + 1] = { + 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 62, 61, 59, 57, 56, 55, + 53, 52, 51, 50, 49, 48, 47, 46, 46, 45, 44, 43, 43, 42, 41, 41, + 40, 39, 39, 38, 38, 37, 37, 36, 36, 35, 35, 34, 34, 33, 33, 33, + 32, 32, 31, 31, 31, 30, 30, 30, 29, 29, 29, 28, 28, 28, 27, 27, + 27, 26, 26, 26, 26, 25, 25, 25, 24, 24, 24, 24, 23, 23, 23, 23, + 22, 22, 22, 22, 21, 21, 21, 21, 21, 20, 20, 20, 20, 19, 19, 19, + 19, 19, 18, 18, 18, 18, 18, 18, 17, 17, 17, 17, 17, 16, 16, 16, + 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 13, + 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, + 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, + 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0 +}; + // Is the operator a modulator (0) or a carrier (1)? const uint8 AdLib::kOperatorType[kOperatorCount] = { 0, 0, 0, 1, 1, 1, @@ -93,23 +115,20 @@ const uint16 AdLib::kHihatParams [kParamCount] = { 0, 1, 0, 15, 11, 0, 7, 5, 0, 0, 0, 0, 0, 0 }; -AdLib::AdLib(Audio::Mixer &mixer) : _mixer(&mixer), _opl(0), - _toPoll(0), _repCount(0), _first(true), _playing(false), _ended(true) { - - _rate = _mixer->getOutputRate(); +AdLib::AdLib(int callbackFreq) : _opl(0), + _toPoll(0), _repCount(0), _first(true), _playing(false), _ended(true), _volume(0) { initFreqs(); createOPL(); initOPL(); - _mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle, - this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + syncVolume(); + + _opl->start(new Common::Functor0Mem<void, AdLib>(this, &AdLib::onTimer), callbackFreq); } AdLib::~AdLib() { - _mixer->stopHandle(_handle); - delete _opl; } @@ -136,46 +155,38 @@ void AdLib::createOPL() { } _opl = OPL::Config::create(OPL::Config::parse(oplDriver), OPL::Config::kOpl2); - if (!_opl || !_opl->init(_rate)) { + if (!_opl || !_opl->init()) { delete _opl; error("Could not create an AdLib emulator"); } } -int AdLib::readBuffer(int16 *buffer, const int numSamples) { +void AdLib::onTimer() { Common::StackLock slock(_mutex); - // Nothing to do, fill with silence - if (!_playing) { - memset(buffer, 0, numSamples * sizeof(int16)); - return numSamples; + // Nothing to do + if (!_playing) + return; + + // Check if there's anything to do on this step + // If not, decrease the poll number and move on + if (_toPoll > 0) { + _toPoll--; + return; } - // Read samples from the OPL, polling in more music when necessary - uint32 samples = numSamples; - while (samples && _playing) { - if (_toPoll) { - const uint32 render = MIN(samples, _toPoll); - - _opl->readBuffer(buffer, render); - - buffer += render; - samples -= render; - _toPoll -= render; - - } else { - // Song ended, fill the rest with silence - if (_ended) { - memset(buffer, 0, samples * sizeof(int16)); - samples = 0; - break; - } - - // Poll more music - _toPoll = pollMusic(_first); - _first = false; + // Poll until we have to delay until the next poll + while (_toPoll == 0 && _playing) { + // Song ended, break out + if (_ended) { + _toPoll = 0; + break; } + + // Poll more music + _toPoll = pollMusic(_first); + _first = false; } // Song ended, loop if requested @@ -195,24 +206,6 @@ int AdLib::readBuffer(int16 *buffer, const int numSamples) { } else _playing = false; } - - return numSamples; -} - -bool AdLib::isStereo() const { - return _opl->isStereo(); -} - -bool AdLib::endOfData() const { - return !_playing; -} - -bool AdLib::endOfStream() const { - return false; -} - -int AdLib::getRate() const { - return _rate; } bool AdLib::isPlaying() const { @@ -231,10 +224,6 @@ void AdLib::setRepeating(int32 repCount) { _repCount = repCount; } -uint32 AdLib::getSamplesPerSecond() const { - return _rate * (isStereo() ? 2 : 1); -} - void AdLib::startPlay() { Common::StackLock slock(_mutex); @@ -294,7 +283,12 @@ void AdLib::initOPL() { _voiceOn [i] = 0; } - _opl->reset(); + /* NOTE: We used to completely reset the OPL here, via _opl->reset(). However, + * with the OPL timer change in 73e8ac2a, reset() must not be called while + * the callback is still active. With the Gob AdLib rewrite in 03ef6689, + * this reset shouldn't be necessary anymore either, since this function + * here cleans everything properly anyway. If suddenly a certain piece of + * music in a Gob game sounds weird, we need to re-examine that. */ initOperatorVolumes(); resetFreqs(); @@ -442,6 +436,13 @@ void AdLib::writeKeyScaleLevelVolume(uint8 oper) { volume = (63 - (_operatorParams[oper][kParamLevel] & 0x3F)) * _operatorVolume[oper]; volume = 63 - ((2 * volume + kMaxVolume) / (2 * kMaxVolume)); + // Adjust carriers for GUI volume slider + if (kOperatorType[oper] == 1) { + volume += kVolumeTable[_volume]; + if (volume > 63) + volume = 63; + } + uint8 keyScale = _operatorParams[oper][kParamKeyScaleLevel] << 6; writeOPL(0x40 + kOperatorOffset[oper], volume | keyScale); @@ -639,4 +640,23 @@ void AdLib::setFreq(uint8 voice, uint16 note, bool on) { writeOPL(0xB0 + voice, value); } +void AdLib::setTimerFrequency(int timerFrequency) { + _opl->setCallbackFrequency(timerFrequency); +} + +void AdLib::syncVolume() { + Common::StackLock slock(_mutex); + + bool mute = false; + if (ConfMan.hasKey("mute")) + mute = ConfMan.getBool("mute"); + + _volume = (mute ? 0 : ConfMan.getInt("music_volume")); + + if (_playing) { + for(int i = 0; i < kOperatorCount; i++) + writeKeyScaleLevelVolume(i); + } +} + } // End of namespace Gob |