From ece3e9a2200052cc65f60e0295b674095d7a6a66 Mon Sep 17 00:00:00 2001 From: Paul Gilbert Date: Sun, 16 Feb 2014 23:04:02 -0500 Subject: MADS: Booyah! Copy protection failure air escaping sound playing --- engines/mads/mads.cpp | 8 ------ engines/mads/sound_nebular.cpp | 61 +++++++++++++++++++++++++++++++++++++----- engines/mads/sound_nebular.h | 51 ++++++++++++++++++++++++++++++++--- 3 files changed, 102 insertions(+), 18 deletions(-) diff --git a/engines/mads/mads.cpp b/engines/mads/mads.cpp index 39ef195cd6..25730fa9e4 100644 --- a/engines/mads/mads.cpp +++ b/engines/mads/mads.cpp @@ -45,8 +45,6 @@ void MADSEngine::initialise() { _soundManager.setVm(this, _mixer); } -static uint32 lastSoundFrame = 0; - Common::Error MADSEngine::run() { initGraphics(320, 200, false); initialise(); @@ -56,12 +54,6 @@ Common::Error MADSEngine::run() { while (!shouldQuit()) { g_system->getEventManager()->pollEvent(e); g_system->delayMillis(10); - - uint32 milli = g_system->getMillis(); - if (milli > (lastSoundFrame + 50)) { - lastSoundFrame = milli; - _soundManager.poll(); - } } return Common::kNoError; diff --git a/engines/mads/sound_nebular.cpp b/engines/mads/sound_nebular.cpp index a1116932d1..146a620261 100644 --- a/engines/mads/sound_nebular.cpp +++ b/engines/mads/sound_nebular.cpp @@ -148,12 +148,6 @@ ASound::ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffs if (!_soundFile.open(filename)) error("Could not open file - %s", filename.c_str()); - _dataOffset = dataOffset; - _mixer = mixer; - _opl = OPL::Config::create(); - assert(_opl); - _opl->init(11025); - // Initialise fields _activeChannelPtr = nullptr; _samplePtr = nullptr; @@ -179,6 +173,21 @@ ASound::ASound(Audio::Mixer *mixer, const Common::String &filename, int dataOffs _randomSeed = 1234; _amDep = _vibDep = _splitPoint = true; + _samplesTillCallback = 0; + _samplesTillCallbackRemainder = 0; + _samplesPerCallback = getRate() / CALLBACKS_PER_SECOND; + _samplesPerCallbackRemainder = getRate() % CALLBACKS_PER_SECOND; + + // Store passed parameters, and setup OPL + _dataOffset = dataOffset; + _mixer = mixer; + _opl = OPL::Config::create(); + assert(_opl); + + _opl->init(getRate()); + _mixer->playStream(Audio::Mixer::kPlainSoundType, &_soundHandle, this, -1, + Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true); + // Initialise the Adlib adlibInit(); @@ -191,6 +200,7 @@ ASound::~ASound() { for (i = _dataCache.begin(); i != _dataCache.end(); ++i) delete[] (*i)._data; + _mixer->stopHandle(_soundHandle); delete _opl; } @@ -233,7 +243,7 @@ void ASound::noise() { } void ASound::write(int reg, int val) { - _opl->write(reg, val); + _queue.push(RegisterValue(reg, val)); } int ASound::write2(int state, int reg, int val) { @@ -243,6 +253,15 @@ int ASound::write2(int state, int reg, int val) { return state; } +void ASound::flush() { + Common::StackLock slock(_driverMutex); + + while (!_queue.empty()) { + RegisterValue v = _queue.pop(); + _opl->writeReg(v._regNum, v._value); + } +} + void ASound::channelOn(int reg, int volume) { write2(8, reg, (_ports[reg] & 0xC0) | (volume & 0x3F)); } @@ -754,6 +773,34 @@ void ASound::updateFNumber() { write2(8, hiReg, val2); } +int ASound::readBuffer(int16 *buffer, const int numSamples) { + Common::StackLock slock(_driverMutex); + + int32 samplesLeft = numSamples; + memset(buffer, 0, sizeof(int16) * numSamples); + while (samplesLeft) { + if (!_samplesTillCallback) { + poll(); + flush(); + + _samplesTillCallback = _samplesPerCallback; + _samplesTillCallbackRemainder += _samplesPerCallbackRemainder; + if (_samplesTillCallbackRemainder >= CALLBACKS_PER_SECOND) { + _samplesTillCallback++; + _samplesTillCallbackRemainder -= CALLBACKS_PER_SECOND; + } + } + + int32 render = MIN(samplesLeft, _samplesTillCallback); + samplesLeft -= render; + _samplesTillCallback -= render; + + _opl->readBuffer(buffer, render); + buffer += render; + } + return numSamples; +} + int ASound::command0() { bool isDisabled = _isDisabled; _isDisabled = true; diff --git a/engines/mads/sound_nebular.h b/engines/mads/sound_nebular.h index e2367a5bd8..f9251c9329 100644 --- a/engines/mads/sound_nebular.h +++ b/engines/mads/sound_nebular.h @@ -25,6 +25,8 @@ #include "common/scummsys.h" #include "common/file.h" +#include "common/mutex.h" +#include "common/queue.h" #include "audio/audiostream.h" #include "audio/fmopl.h" #include "audio/mixer.h" @@ -108,13 +110,23 @@ public: AdlibSample(Common::SeekableReadStream &s); }; +struct RegisterValue { + uint8 _regNum; + uint8 _value; + + RegisterValue(int regNum, int value) { + _regNum = regNum; _value = value; + } +}; + #define ADLIB_CHANNEL_COUNT 9 #define ADLIB_CHANNEL_MIDWAY 5 +#define CALLBACKS_PER_SECOND 60 /** * Base class for the sound player resource files */ -class ASound { +class ASound: public Audio::AudioStream { private: struct CachedDataEntry { int _offset; @@ -169,15 +181,20 @@ private: void updateFNumber(); protected: /** - * Write a byte to an Adlib register + * Queue a byte for an Adlib register */ void write(int reg, int val); /** - * Write a byte to an Adlib register, and store it in the _ports array + * Queue a byte for an Adlib register, and store it in the _ports array */ int write2(int state, int reg, int val); + /** + * Flush any pending Adlib register values to the OPL driver + */ + void flush(); + /** * Turn a channel on */ @@ -239,12 +256,15 @@ protected: public: Audio::Mixer *_mixer; FM_OPL *_opl; + Audio::SoundHandle _soundHandle; AdlibChannel _channels[ADLIB_CHANNEL_COUNT]; AdlibChannel *_activeChannelPtr; AdlibChannelData _channelData[11]; Common::Array _samples; AdlibSample *_samplePtr; Common::File _soundFile; + Common::Queue _queue; + Common::Mutex _driverMutex; int _dataOffset; int _frameCounter; bool _isDisabled; @@ -268,6 +288,10 @@ public: int _activeChannelReg; int _v11; bool _amDep, _vibDep, _splitPoint; + int _samplesPerCallback; + int _samplesPerCallbackRemainder; + int _samplesTillCallback; + int _samplesTillCallbackRemainder; public: /** * Constructor @@ -306,6 +330,27 @@ public: * Return the current frame counter */ int getFrameCounter() { return _frameCounter; } + + // AudioStream interface + /** + * Main buffer read + */ + virtual int readBuffer(int16 *buffer, const int numSamples); + + /** + * Mono sound only + */ + virtual bool isStereo() const { return false; } + + /** + * Data is continuously pushed, so definitive end + */ + virtual bool endOfData() const { return false; } + + /** + * Return sample rate + */ + virtual int getRate() const { return 11025; } }; class ASound1: public ASound { -- cgit v1.2.3