diff options
Diffstat (limited to 'engines/gob')
| -rw-r--r-- | engines/gob/gob.cpp | 3 | ||||
| -rw-r--r-- | engines/gob/sound/adlib.cpp | 133 | ||||
| -rw-r--r-- | engines/gob/sound/adlib.h | 32 | ||||
| -rw-r--r-- | engines/gob/sound/adlplayer.cpp | 11 | ||||
| -rw-r--r-- | engines/gob/sound/adlplayer.h | 4 | ||||
| -rw-r--r-- | engines/gob/sound/musplayer.cpp | 22 | ||||
| -rw-r--r-- | engines/gob/sound/musplayer.h | 3 | ||||
| -rw-r--r-- | engines/gob/sound/sound.cpp | 18 | ||||
| -rw-r--r-- | engines/gob/sound/sound.h | 1 | ||||
| -rw-r--r-- | engines/gob/surface.cpp | 7 | ||||
| -rw-r--r-- | engines/gob/surface.h | 2 |
11 files changed, 129 insertions, 107 deletions
diff --git a/engines/gob/gob.cpp b/engines/gob/gob.cpp index 5ab3271a8f..24bdb858d8 100644 --- a/engines/gob/gob.cpp +++ b/engines/gob/gob.cpp @@ -389,6 +389,9 @@ void GobEngine::syncSoundSettings() { Engine::syncSoundSettings(); _init->updateConfig(); + + if (_sound) + _sound->adlibSyncVolume(); } void GobEngine::pauseGame() { diff --git a/engines/gob/sound/adlib.cpp b/engines/gob/sound/adlib.cpp index 65b43cae7a..1e024d5a50 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); @@ -442,6 +431,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 +635,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 diff --git a/engines/gob/sound/adlib.h b/engines/gob/sound/adlib.h index 8071249374..d60458295c 100644 --- a/engines/gob/sound/adlib.h +++ b/engines/gob/sound/adlib.h @@ -35,9 +35,9 @@ namespace OPL { namespace Gob { /** Base class for a player of an AdLib music format. */ -class AdLib : public Audio::AudioStream { +class AdLib { public: - AdLib(Audio::Mixer &mixer); + AdLib(int callbackFrequency); virtual ~AdLib(); bool isPlaying() const; ///< Are we currently playing? @@ -53,13 +53,7 @@ public: void startPlay(); void stopPlay(); - -// AudioStream API - int readBuffer(int16 *buffer, const int numSamples); - bool isStereo() const; - bool endOfData() const; - bool endOfStream() const; - int getRate() const; + void syncVolume(); protected: enum kVoice { @@ -120,8 +114,6 @@ protected: static const int kOPLMidC = 48; ///< A mid C for the OPL. - /** Return the number of samples per second. */ - uint32 getSamplesPerSecond() const; /** Write a value into an OPL register. */ void writeOPL(byte reg, byte val); @@ -135,7 +127,7 @@ protected: /** The callback function that's called for polling more AdLib commands. * * @param first Is this the first poll since the start of the song? - * @return The number of samples until the next poll. + * @return The number of ticks until the next poll. */ virtual uint32 pollMusic(bool first) = 0; @@ -207,7 +199,14 @@ protected: /** Switch a voice off. */ void noteOff(uint8 voice); + /** + * Set the OPL timer frequency + */ + void setTimerFrequency(int timerFrequency); + private: + static const uint8 kVolumeTable[Audio::Mixer::kMaxMixerVolume + 1]; + static const uint8 kOperatorType [kOperatorCount]; static const uint8 kOperatorOffset[kOperatorCount]; static const uint8 kOperatorVoice [kOperatorCount]; @@ -226,13 +225,11 @@ private: static const uint16 kHihatParams [kParamCount]; - Audio::Mixer *_mixer; - Audio::SoundHandle _handle; OPL::OPL *_opl; Common::Mutex _mutex; - uint32 _rate; + int _volume; uint32 _toPoll; @@ -300,6 +297,11 @@ private: void changePitch(uint8 voice, uint16 pitchBend); void setFreq(uint8 voice, uint16 note, bool on); + + /** + * Callback function for OPL + */ + void onTimer(); }; } // End of namespace Gob diff --git a/engines/gob/sound/adlplayer.cpp b/engines/gob/sound/adlplayer.cpp index 384a928360..6354d8c37f 100644 --- a/engines/gob/sound/adlplayer.cpp +++ b/engines/gob/sound/adlplayer.cpp @@ -28,7 +28,7 @@ namespace Gob { -ADLPlayer::ADLPlayer(Audio::Mixer &mixer) : AdLib(mixer), +ADLPlayer::ADLPlayer() : AdLib(1000), _songData(0), _songDataSize(0), _playPos(0) { } @@ -135,14 +135,7 @@ uint32 ADLPlayer::pollMusic(bool first) { if (delay & 0x80) delay = ((delay & 3) << 8) | *_playPos++; - return getSampleDelay(delay); -} - -uint32 ADLPlayer::getSampleDelay(uint16 delay) const { - if (delay == 0) - return 0; - - return ((uint32)delay * getSamplesPerSecond()) / 1000; + return delay; } void ADLPlayer::rewind() { diff --git a/engines/gob/sound/adlplayer.h b/engines/gob/sound/adlplayer.h index 3edd238343..50e1db5b70 100644 --- a/engines/gob/sound/adlplayer.h +++ b/engines/gob/sound/adlplayer.h @@ -36,7 +36,7 @@ namespace Gob { /** A player for Coktel Vision's ADL music format. */ class ADLPlayer : public AdLib { public: - ADLPlayer(Audio::Mixer &mixer); + ADLPlayer(); ~ADLPlayer(); bool load(Common::SeekableReadStream &adl); @@ -76,8 +76,6 @@ private: bool readHeader (Common::SeekableReadStream &adl, int &timbreCount); bool readTimbres (Common::SeekableReadStream &adl, int timbreCount); bool readSongData(Common::SeekableReadStream &adl); - - uint32 getSampleDelay(uint16 delay) const; }; } // End of namespace Gob diff --git a/engines/gob/sound/musplayer.cpp b/engines/gob/sound/musplayer.cpp index 7001a5724b..dcbb712b56 100644 --- a/engines/gob/sound/musplayer.cpp +++ b/engines/gob/sound/musplayer.cpp @@ -27,7 +27,7 @@ namespace Gob { -MUSPlayer::MUSPlayer(Audio::Mixer &mixer) : AdLib(mixer), +MUSPlayer::MUSPlayer() : AdLib(60), _songData(0), _songDataSize(0), _playPos(0), _songID(0) { } @@ -43,15 +43,6 @@ void MUSPlayer::unload() { unloadMUS(); } -uint32 MUSPlayer::getSampleDelay(uint16 delay) const { - if (delay == 0) - return 0; - - uint32 freq = (_ticksPerBeat * _tempo) / 60; - - return ((uint32)delay * getSamplesPerSecond()) / freq; -} - void MUSPlayer::skipToTiming() { while (*_playPos < 0x80) _playPos++; @@ -66,8 +57,12 @@ uint32 MUSPlayer::pollMusic(bool first) { return 0; } - if (first) - return getSampleDelay(*_playPos++); + if (first) { + // Set the timer frequency on first run. + // Do not set it in rewind() for thread safety reasons. + setTimerFrequency((_ticksPerBeat * _tempo) / 60); + return *_playPos++; + } uint16 delay = 0; while (delay == 0) { @@ -100,6 +95,7 @@ uint32 MUSPlayer::pollMusic(bool first) { uint32 denom = *_playPos++; _tempo = _baseTempo * num + ((_baseTempo * denom) >> 7); + setTimerFrequency((_ticksPerBeat * _tempo) / 60); _playPos++; } else { @@ -182,7 +178,7 @@ uint32 MUSPlayer::pollMusic(bool first) { delay += *_playPos++; } - return getSampleDelay(delay); + return delay; } void MUSPlayer::rewind() { diff --git a/engines/gob/sound/musplayer.h b/engines/gob/sound/musplayer.h index c76c5aab38..973192ffd9 100644 --- a/engines/gob/sound/musplayer.h +++ b/engines/gob/sound/musplayer.h @@ -40,7 +40,7 @@ namespace Gob { */ class MUSPlayer : public AdLib { public: - MUSPlayer(Audio::Mixer &mixer); + MUSPlayer(); ~MUSPlayer(); /** Load the instruments (.SND or .TBR) */ @@ -97,7 +97,6 @@ private: bool readMUSHeader(Common::SeekableReadStream &mus); bool readMUSSong (Common::SeekableReadStream &mus); - uint32 getSampleDelay(uint16 delay) const; void setInstrument(uint8 voice, uint8 instrument); void skipToTiming(); diff --git a/engines/gob/sound/sound.cpp b/engines/gob/sound/sound.cpp index d2b2d3d6e8..22dfe9d3c3 100644 --- a/engines/gob/sound/sound.cpp +++ b/engines/gob/sound/sound.cpp @@ -234,7 +234,7 @@ bool Sound::adlibLoadADL(const char *fileName) { return false; if (!_adlPlayer) - _adlPlayer = new ADLPlayer(*_vm->_mixer); + _adlPlayer = new ADLPlayer(); debugC(1, kDebugSound, "AdLib: Loading ADL data (\"%s\")", fileName); @@ -256,7 +256,7 @@ bool Sound::adlibLoadADL(byte *data, uint32 size, int index) { return false; if (!_adlPlayer) - _adlPlayer = new ADLPlayer(*_vm->_mixer); + _adlPlayer = new ADLPlayer(); debugC(1, kDebugSound, "AdLib: Loading ADL data (%d)", index); @@ -425,6 +425,16 @@ int32 Sound::adlibGetRepeating() const { return false; } +void Sound::adlibSyncVolume() { + if (!_hasAdLib) + return; + + if (_adlPlayer) + _adlPlayer->syncVolume(); + if (_mdyPlayer) + _mdyPlayer->syncVolume(); +} + void Sound::adlibSetRepeating(int32 repCount) { if (!_hasAdLib) return; @@ -739,7 +749,7 @@ void Sound::createMDYPlayer() { delete _adlPlayer; _adlPlayer = 0; - _mdyPlayer = new MUSPlayer(*_vm->_mixer); + _mdyPlayer = new MUSPlayer(); } void Sound::createADLPlayer() { @@ -749,7 +759,7 @@ void Sound::createADLPlayer() { delete _mdyPlayer; _mdyPlayer= 0; - _adlPlayer = new ADLPlayer(*_vm->_mixer); + _adlPlayer = new ADLPlayer(); } } // End of namespace Gob diff --git a/engines/gob/sound/sound.h b/engines/gob/sound/sound.h index c959959755..6ebc323b18 100644 --- a/engines/gob/sound/sound.h +++ b/engines/gob/sound/sound.h @@ -96,6 +96,7 @@ public: int32 adlibGetRepeating() const; void adlibSetRepeating(int32 repCount); + void adlibSyncVolume(); // Infogrames diff --git a/engines/gob/surface.cpp b/engines/gob/surface.cpp index 42ac2b0d74..ed83e8255c 100644 --- a/engines/gob/surface.cpp +++ b/engines/gob/surface.cpp @@ -470,7 +470,7 @@ void Surface::blitScaled(const Surface &from, Common::Rational scale, int32 tran blitScaled(from, 0, 0, from._width - 1, from._height - 1, 0, 0, scale, transp); } -void Surface::fillRect(uint16 left, uint16 top, uint16 right, uint16 bottom, uint32 color) { +void Surface::fillRect(int16 left, int16 top, int16 right, int16 bottom, uint32 color) { // Just in case those are swapped if (left > right) SWAP(left, right); @@ -481,6 +481,11 @@ void Surface::fillRect(uint16 left, uint16 top, uint16 right, uint16 bottom, uin // Nothing to do return; + left = CLIP<int32>(left , 0, _width - 1); + top = CLIP<int32>(top , 0, _height - 1); + right = CLIP<int32>(right , 0, _width - 1); + bottom = CLIP<int32>(bottom, 0, _height - 1); + // Area to actually fill uint16 width = CLIP<int32>(right - left + 1, 0, _width - left); uint16 height = CLIP<int32>(bottom - top + 1, 0, _height - top); diff --git a/engines/gob/surface.h b/engines/gob/surface.h index c931731908..eb0a5bf1a4 100644 --- a/engines/gob/surface.h +++ b/engines/gob/surface.h @@ -121,7 +121,7 @@ public: void blitScaled(const Surface &from, int16 x, int16 y, Common::Rational scale, int32 transp = -1); void blitScaled(const Surface &from, Common::Rational scale, int32 transp = -1); - void fillRect(uint16 left, uint16 top, uint16 right, uint16 bottom, uint32 color); + void fillRect(int16 left, int16 top, int16 right, int16 bottom, uint32 color); void fill(uint32 color); void clear(); |
