diff options
author | Matthew Hoops | 2015-05-14 21:07:46 -0400 |
---|---|---|
committer | Matthew Hoops | 2015-07-07 20:19:47 -0400 |
commit | 4d5658511228328a9e56d32448f9b598ecda696c (patch) | |
tree | 164d68f9ca5a6bed5e7c0b4526045067a0bd8c5e /audio/fmopl.cpp | |
parent | bed9da8b9dbbaa19d317f71663e42875c1717fda (diff) | |
download | scummvm-rg350-4d5658511228328a9e56d32448f9b598ecda696c.tar.gz scummvm-rg350-4d5658511228328a9e56d32448f9b598ecda696c.tar.bz2 scummvm-rg350-4d5658511228328a9e56d32448f9b598ecda696c.zip |
AUDIO: Add a class representing a real OPL
Diffstat (limited to 'audio/fmopl.cpp')
-rw-r--r-- | audio/fmopl.cpp | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/audio/fmopl.cpp b/audio/fmopl.cpp index 4bc902eba0..b0b3273e82 100644 --- a/audio/fmopl.cpp +++ b/audio/fmopl.cpp @@ -29,6 +29,7 @@ #include "common/config-manager.h" #include "common/system.h" #include "common/textconsole.h" +#include "common/timer.h" #include "common/translation.h" namespace OPL { @@ -185,6 +186,63 @@ void OPL::stop() { bool OPL::_hasInstance = false; +RealOPL::RealOPL() : _baseFreq(0), _remainingTicks(0) { +} + +RealOPL::~RealOPL() { + // Stop callbacks, just in case. If it's still playing at this + // point, there's probably a bigger issue, though. The subclass + // needs to call stop() or the pointer can still use be used in + // the mixer thread at the same time. + stop(); +} + +void RealOPL::setCallbackFrequency(int timerFrequency) { + stopCallbacks(); + startCallbacks(timerFrequency); +} + +void RealOPL::startCallbacks(int timerFrequency) { + _baseFreq = timerFrequency; + assert(_baseFreq > 0); + + // We can't request more a timer faster than 100Hz. We'll handle this by calling + // the proc multiple times in onTimer() later on. + if (timerFrequency > kMaxFreq) + timerFrequency = kMaxFreq; + + _remainingTicks = 0; + g_system->getTimerManager()->installTimerProc(timerProc, 1000000 / timerFrequency, this, "RealOPL"); +} + +void RealOPL::stopCallbacks() { + g_system->getTimerManager()->removeTimerProc(timerProc); + _baseFreq = 0; + _remainingTicks = 0; +} + +void RealOPL::timerProc(void *refCon) { + static_cast<RealOPL *>(refCon)->onTimer(); +} + +void RealOPL::onTimer() { + uint callbacks = 1; + + if (_baseFreq > kMaxFreq) { + // We run faster than our max, so run the callback multiple + // times to approximate the actual timer callback frequency. + uint totalTicks = _baseFreq + _remainingTicks; + callbacks = totalTicks / kMaxFreq; + _remainingTicks = totalTicks % kMaxFreq; + } + + // Call the callback multiple times. The if is on the inside of the + // loop in case the callback removes itself. + for (uint i = 0; i < callbacks; i++) + if (_callback && _callback->isValid()) + (*_callback)(); +} + EmulatedOPL::EmulatedOPL() : _nextTick(0), _samplesPerTick(0), |