aboutsummaryrefslogtreecommitdiff
path: root/audio/fmopl.cpp
diff options
context:
space:
mode:
authorMatthew Hoops2015-05-14 21:07:46 -0400
committerMatthew Hoops2015-07-07 20:19:47 -0400
commit4d5658511228328a9e56d32448f9b598ecda696c (patch)
tree164d68f9ca5a6bed5e7c0b4526045067a0bd8c5e /audio/fmopl.cpp
parentbed9da8b9dbbaa19d317f71663e42875c1717fda (diff)
downloadscummvm-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.cpp58
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),