[Scummvm-git-logs] scummvm master -> b5887b2464d9db2c3b6e420939cd8ab54c9e210d

bluegr noreply at scummvm.org
Fri Jul 26 21:55:00 UTC 2024


This automated email contains information about 2 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
e3b16b832d AUDIO: Change the EmulatedCMS API to match EmulatedOPL
b5887b2464 AUDIO: Share code between OPL and CMS implementations


Commit: e3b16b832d12a77aa684206605cd500dedf4d159
    https://github.com/scummvm/scummvm/commit/e3b16b832d12a77aa684206605cd500dedf4d159
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2024-07-27T00:54:57+03:00

Commit Message:
AUDIO: Change the EmulatedCMS API to match EmulatedOPL

Changed paths:
    audio/cms.cpp
    audio/cms.h
    audio/softsynth/cms.cpp
    audio/softsynth/cms.h


diff --git a/audio/cms.cpp b/audio/cms.cpp
index 89ba55d8145..68112e31962 100644
--- a/audio/cms.cpp
+++ b/audio/cms.cpp
@@ -68,7 +68,8 @@ EmulatedCMS::~EmulatedCMS() {
 }
 
 int EmulatedCMS::readBuffer(int16 *buffer, const int numSamples) {
-	int len = numSamples / 2;
+	const int stereoFactor = isStereo() ? 2 : 1;
+	int len = numSamples / stereoFactor;
 	int step;
 
 	do {
@@ -76,7 +77,7 @@ int EmulatedCMS::readBuffer(int16 *buffer, const int numSamples) {
 		if (step > (_nextTick >> FIXP_SHIFT))
 			step = (_nextTick >> FIXP_SHIFT);
 
-		generateSamples(buffer, step);
+		generateSamples(buffer, step * stereoFactor);
 
 		_nextTick -= step << FIXP_SHIFT;
 		if (!(_nextTick >> FIXP_SHIFT)) {
@@ -86,7 +87,7 @@ int EmulatedCMS::readBuffer(int16 *buffer, const int numSamples) {
 			_nextTick += _samplesPerTick;
 		}
 
-		buffer += step * 2;
+		buffer += step * stereoFactor;
 		len -= step;
 	} while (len);
 
@@ -97,14 +98,6 @@ int EmulatedCMS::getRate() const {
 	return g_system->getMixer()->getOutputRate();
 }
 
-bool EmulatedCMS::endOfData() const {
-	return false;
-}
-
-bool EmulatedCMS::isStereo() const {
-	return true;
-}
-
 void EmulatedCMS::startCallbacks(int timerFrequency) {
 	setCallbackFrequency(timerFrequency);
 	g_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, _handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
diff --git a/audio/cms.h b/audio/cms.h
index 63857e3f354..e26cd765461 100644
--- a/audio/cms.h
+++ b/audio/cms.h
@@ -140,8 +140,7 @@ public:
 	// AudioStream API
 	int readBuffer(int16 *buffer, const int numSamples) override;
 	int getRate() const override;
-	bool endOfData() const override;
-	bool isStereo() const override;
+	bool endOfData() const override { return false; }
 
 protected:
 	// CMS API
@@ -151,11 +150,12 @@ protected:
 	/**
 	 * Read up to 'length' samples.
 	 *
-	 * Data will be in native endianess, 16 bit per sample, signed. buffer will
-	 * be filled with interleaved left and right channel samples, starting with
-	 * a left sample. The requested number of samples is stereo samples, so if
-	 * you request 2 samples, you will get a total of two left channel and two
-	 * right channel samples.
+	 * Data will be in native endianess, 16 bit per sample, signed.
+	 * For stereo OPL, buffer will be filled with interleaved
+	 * left and right channel samples, starting with a left sample.
+	 * Furthermore, the samples in the left and right are summed up.
+	 * So if you request 4 samples from a stereo OPL, you will get
+	 * a total of two left channel and two right channel samples.
 	 */
 	virtual void generateSamples(int16 *buffer, int numSamples) = 0;
 
diff --git a/audio/softsynth/cms.cpp b/audio/softsynth/cms.cpp
index 99123485c70..b0183a82f7a 100644
--- a/audio/softsynth/cms.cpp
+++ b/audio/softsynth/cms.cpp
@@ -172,7 +172,7 @@ void DOSBoxCMS::update(int chip, int16 *buffer, int length) {
 	int j, ch;
 
 	if (chip == 0) {
-		memset(buffer, 0, sizeof(int16)*length*2);
+		memset(buffer, 0, sizeof(int16)*length);
 	}
 
 	/* if the channels are disabled we're done */
@@ -193,7 +193,7 @@ void DOSBoxCMS::update(int chip, int16 *buffer, int length) {
 	rate = getRate() * FRAC_ONE_CMS;
 
 	/* fill all data needed */
-	for (j = 0; j < length; ++j) {
+	for (j = 0; j < length / 2; ++j) {
 		int output_l = 0, output_r = 0;
 
 		/* for each channel */
diff --git a/audio/softsynth/cms.h b/audio/softsynth/cms.h
index fcd9b13045d..29f7fce9029 100644
--- a/audio/softsynth/cms.h
+++ b/audio/softsynth/cms.h
@@ -78,6 +78,8 @@ public:
 	void write(int a, int v) override;
 	void writeReg(int r, int v) override;
 
+	bool isStereo() const { return true; }
+
 protected:
 	void generateSamples(int16 *buffer, int numSamples) override;
 


Commit: b5887b2464d9db2c3b6e420939cd8ab54c9e210d
    https://github.com/scummvm/scummvm/commit/b5887b2464d9db2c3b6e420939cd8ab54c9e210d
Author: Cameron Cawley (ccawley2011 at gmail.com)
Date: 2024-07-27T00:54:57+03:00

Commit Message:
AUDIO: Share code between OPL and CMS implementations

Changed paths:
  A audio/chip.cpp
  A audio/chip.h
    audio/alsa_opl.cpp
    audio/cms.cpp
    audio/cms.h
    audio/fmopl.cpp
    audio/fmopl.h
    audio/module.mk
    audio/opl2lpt.cpp
    audio/rwopl3.cpp
    audio/rwopl3.h
    audio/softsynth/cms.h
    audio/softsynth/opl/dosbox.h
    audio/softsynth/opl/mame.h
    audio/softsynth/opl/nuked.h


diff --git a/audio/alsa_opl.cpp b/audio/alsa_opl.cpp
index 1adc2e47742..24c79c80f7a 100644
--- a/audio/alsa_opl.cpp
+++ b/audio/alsa_opl.cpp
@@ -43,7 +43,7 @@
 namespace OPL {
 namespace ALSA {
 
-class OPL : public ::OPL::RealOPL {
+class OPL : public ::OPL::OPL, public Audio::RealChip {
 private:
 	enum {
 		kOpl2Voices = 9,
diff --git a/audio/chip.cpp b/audio/chip.cpp
new file mode 100644
index 00000000000..68bc36133e1
--- /dev/null
+++ b/audio/chip.cpp
@@ -0,0 +1,165 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "audio/chip.h"
+#include "audio/mixer.h"
+
+#include "common/timer.h"
+
+namespace Audio {
+
+void Chip::start(TimerCallback *callback, int timerFrequency) {
+	_callback.reset(callback);
+	startCallbacks(timerFrequency);
+}
+
+void Chip::stop() {
+	stopCallbacks();
+	_callback.reset();
+}
+
+RealChip::RealChip() : _baseFreq(0), _remainingTicks(0) {
+}
+
+RealChip::~RealChip() {
+	// 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 RealChip::setCallbackFrequency(int timerFrequency) {
+	stopCallbacks();
+	startCallbacks(timerFrequency);
+}
+
+void RealChip::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, "RealChip");
+}
+
+void RealChip::stopCallbacks() {
+	g_system->getTimerManager()->removeTimerProc(timerProc);
+	_baseFreq = 0;
+	_remainingTicks = 0;
+}
+
+void RealChip::timerProc(void *refCon) {
+	static_cast<RealChip *>(refCon)->onTimer();
+}
+
+void RealChip::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)();
+}
+
+EmulatedChip::EmulatedChip() :
+	_nextTick(0),
+	_samplesPerTick(0),
+	_baseFreq(0),
+	_handle(new Audio::SoundHandle()) { }
+
+EmulatedChip::~EmulatedChip() {
+	// 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();
+
+	delete _handle;
+}
+
+int EmulatedChip::readBuffer(int16 *buffer, const int numSamples) {
+	const int stereoFactor = isStereo() ? 2 : 1;
+	int len = numSamples / stereoFactor;
+	int step;
+
+	do {
+		step = len;
+		if (step > (_nextTick >> FIXP_SHIFT))
+			step = (_nextTick >> FIXP_SHIFT);
+
+		generateSamples(buffer, step * stereoFactor);
+
+		_nextTick -= step << FIXP_SHIFT;
+		if (!(_nextTick >> FIXP_SHIFT)) {
+			if (_callback && _callback->isValid())
+				(*_callback)();
+
+			_nextTick += _samplesPerTick;
+		}
+
+		buffer += step * stereoFactor;
+		len -= step;
+	} while (len);
+
+	return numSamples;
+}
+
+int EmulatedChip::getRate() const {
+	return g_system->getMixer()->getOutputRate();
+}
+
+void EmulatedChip::startCallbacks(int timerFrequency) {
+	setCallbackFrequency(timerFrequency);
+	g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+}
+
+void EmulatedChip::stopCallbacks() {
+	g_system->getMixer()->stopHandle(*_handle);
+}
+
+void EmulatedChip::setCallbackFrequency(int timerFrequency) {
+	_baseFreq = timerFrequency;
+	assert(_baseFreq != 0);
+
+	int d = getRate() / _baseFreq;
+	int r = getRate() % _baseFreq;
+
+	// This is equivalent to (getRate() << FIXP_SHIFT) / BASE_FREQ
+	// but less prone to arithmetic overflow.
+
+	_samplesPerTick = (d << FIXP_SHIFT) + (r << FIXP_SHIFT) / _baseFreq;
+}
+
+} // End of namespace Audio
diff --git a/audio/chip.h b/audio/chip.h
new file mode 100644
index 00000000000..94b6397f994
--- /dev/null
+++ b/audio/chip.h
@@ -0,0 +1,156 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef AUDIO_CHIP_H
+#define AUDIO_CHIP_H
+
+#include "common/func.h"
+#include "common/ptr.h"
+
+#include "audio/audiostream.h"
+
+namespace Audio {
+class SoundHandle;
+
+class Chip {
+public:
+	virtual ~Chip() {}
+
+	/**
+	 * The type of the timer callback functor.
+	 */
+	typedef Common::Functor0<void> TimerCallback;
+
+	/**
+	 * Start the sound chip with callbacks.
+	 */
+	void start(TimerCallback *callback, int timerFrequency);
+
+	/**
+	 * Stop the sound chip
+	 */
+	void stop();
+
+	/**
+	 * Change the callback frequency. This must only be called from a
+	 * timer proc.
+	 */
+	virtual void setCallbackFrequency(int timerFrequency) = 0;
+
+protected:
+	/**
+	 * Start the callbacks.
+	 */
+	virtual void startCallbacks(int timerFrequency) = 0;
+
+	/**
+	 * Stop the callbacks.
+	 */
+	virtual void stopCallbacks() = 0;
+
+	/**
+	 * The functor for callbacks.
+	 */
+	Common::ScopedPtr<TimerCallback> _callback;
+};
+
+/**
+ * A Chip that represents a real sound chip, as opposed to an emulated one.
+ *
+ * This will use an actual timer instead of using one calculated from
+ * the number of samples in an AudioStream::readBuffer call.
+ */
+class RealChip : virtual public Chip {
+public:
+	RealChip();
+	virtual ~RealChip();
+
+	// Chip API
+	void setCallbackFrequency(int timerFrequency);
+
+protected:
+	// Chip API
+	void startCallbacks(int timerFrequency);
+	void stopCallbacks();
+	virtual void onTimer();
+
+private:
+	static void timerProc(void *refCon);
+
+	uint _baseFreq;
+	uint _remainingTicks;
+
+	enum {
+		kMaxFreq = 100
+	};
+};
+
+/**
+ * A Chip that represents an emulated sound chip.
+ *
+ * This will send callbacks based on the number of samples
+ * decoded in readBuffer().
+ */
+class EmulatedChip : virtual public Chip, protected Audio::AudioStream {
+protected:
+	static const int FIXP_SHIFT = 16;
+
+public:
+	EmulatedChip();
+	virtual ~EmulatedChip();
+
+	// Chip API
+	void setCallbackFrequency(int timerFrequency) override;
+
+	// AudioStream API
+	int readBuffer(int16 *buffer, const int numSamples) override;
+	int getRate() const override;
+	bool endOfData() const override { return false; }
+
+protected:
+	// Chip API
+	void startCallbacks(int timerFrequency) override final;
+	void stopCallbacks() override final;
+
+	/**
+	 * Read up to 'length' samples.
+	 *
+	 * Data will be in native endianess, 16 bit per sample, signed.
+	 * For stereo chips, buffer will be filled with interleaved
+	 * left and right channel samples, starting with a left sample.
+	 * Furthermore, the samples in the left and right are summed up.
+	 * So if you request 4 samples from a stereo chip, you will get
+	 * a total of two left channel and two right channel samples.
+	 */
+	virtual void generateSamples(int16 *buffer, int numSamples) = 0;
+
+private:
+	int _baseFreq;
+
+	int _nextTick;
+	int _samplesPerTick;
+
+	Audio::SoundHandle *_handle;
+};
+
+} // End of namespace Audio
+
+#endif
diff --git a/audio/cms.cpp b/audio/cms.cpp
index 68112e31962..a3215aee452 100644
--- a/audio/cms.cpp
+++ b/audio/cms.cpp
@@ -22,6 +22,8 @@
 #include "audio/cms.h"
 #include "audio/softsynth/cms.h"
 
+#include "common/textconsole.h"
+
 namespace CMS {
 
 CMS *Config::create() {
@@ -41,83 +43,4 @@ CMS::~CMS() {
 	_hasInstance = false;
 }
 
-void CMS::start(TimerCallback *callback, int timerFrequency) {
-	_callback.reset(callback);
-	startCallbacks(timerFrequency);
-}
-
-void CMS::stop() {
-	stopCallbacks();
-	_callback.reset();
-}
-
-EmulatedCMS::EmulatedCMS() :
-	_nextTick(0),
-	_samplesPerTick(0),
-	_baseFreq(0),
-	_handle(new Audio::SoundHandle()) { }
-
-EmulatedCMS::~EmulatedCMS() {
-	// 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();
-
-	delete _handle;
-}
-
-int EmulatedCMS::readBuffer(int16 *buffer, const int numSamples) {
-	const int stereoFactor = isStereo() ? 2 : 1;
-	int len = numSamples / stereoFactor;
-	int step;
-
-	do {
-		step = len;
-		if (step > (_nextTick >> FIXP_SHIFT))
-			step = (_nextTick >> FIXP_SHIFT);
-
-		generateSamples(buffer, step * stereoFactor);
-
-		_nextTick -= step << FIXP_SHIFT;
-		if (!(_nextTick >> FIXP_SHIFT)) {
-			if (_callback && _callback->isValid())
-				(*_callback)();
-
-			_nextTick += _samplesPerTick;
-		}
-
-		buffer += step * stereoFactor;
-		len -= step;
-	} while (len);
-
-	return numSamples;
-}
-
-int EmulatedCMS::getRate() const {
-	return g_system->getMixer()->getOutputRate();
-}
-
-void EmulatedCMS::startCallbacks(int timerFrequency) {
-	setCallbackFrequency(timerFrequency);
-	g_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, _handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-}
-
-void EmulatedCMS::stopCallbacks() {
-	g_system->getMixer()->stopHandle(*_handle);
-}
-
-void EmulatedCMS::setCallbackFrequency(int timerFrequency) {
-	_baseFreq = timerFrequency;
-	assert(_baseFreq != 0);
-
-	int d = getRate() / _baseFreq;
-	int r = getRate() % _baseFreq;
-
-	// This is equivalent to (getRate() << FIXP_SHIFT) / BASE_FREQ
-	// but less prone to arithmetic overflow.
-
-	_samplesPerTick = (d << FIXP_SHIFT) + (r << FIXP_SHIFT) / _baseFreq;
-}
-
 } // End of namespace CMS
diff --git a/audio/cms.h b/audio/cms.h
index e26cd765461..1145c3dec3a 100644
--- a/audio/cms.h
+++ b/audio/cms.h
@@ -22,11 +22,7 @@
 #ifndef AUDIO_CMS_H
 #define AUDIO_CMS_H
 
-#include "common/func.h"
-#include "common/ptr.h"
-
-#include "audio/audiostream.h"
-#include "audio/mixer.h"
+#include "audio/chip.h"
 
 namespace CMS {
 
@@ -40,12 +36,7 @@ public:
 	static CMS *create();
 };
 
-/**
- * The type of the CMS timer callback functor.
- */
-typedef Common::Functor0<void> TimerCallback;
-
-class CMS {
+class CMS : virtual public Audio::Chip {
 private:
 	static bool _hasInstance;
 
@@ -87,85 +78,8 @@ public:
 	 */
 	virtual void writeReg(int r, int v) = 0;
 
-	/**
-	 * Start the CMS with callbacks.
-	 */
-	void start(TimerCallback *callback, int timerFrequency = DEFAULT_CALLBACK_FREQUENCY);
-
-	/**
-	 * Stop the CMS
-	 */
-	void stop();
-
-	/**
-	 * Change the callback frequency. This must only be called from a
-	 * timer proc.
-	 */
-	virtual void setCallbackFrequency(int timerFrequency) = 0;
-
-protected:
-	/**
-	 * Start the callbacks.
-	 */
-	virtual void startCallbacks(int timerFrequency) = 0;
-
-	/**
-	 * Stop the callbacks.
-	 */
-	virtual void stopCallbacks() = 0;
-
-	/**
-	 * The functor for callbacks.
-	 */
-	Common::ScopedPtr<TimerCallback> _callback;
-};
-
-/**
- * A CMS that represents an emulated CMS.
- *
- * This will send callbacks based on the number of samples
- * decoded in readBuffer().
- */
-class EmulatedCMS : public CMS, protected Audio::AudioStream {
-protected:
-	static const int FIXP_SHIFT = 16;
-
-public:
-	EmulatedCMS();
-	virtual ~EmulatedCMS();
-
-	// CMS API
-	void setCallbackFrequency(int timerFrequency) override;
-
-	// AudioStream API
-	int readBuffer(int16 *buffer, const int numSamples) override;
-	int getRate() const override;
-	bool endOfData() const override { return false; }
-
-protected:
-	// CMS API
-	void startCallbacks(int timerFrequency) override;
-	void stopCallbacks() override;
-
-	/**
-	 * Read up to 'length' samples.
-	 *
-	 * Data will be in native endianess, 16 bit per sample, signed.
-	 * For stereo OPL, buffer will be filled with interleaved
-	 * left and right channel samples, starting with a left sample.
-	 * Furthermore, the samples in the left and right are summed up.
-	 * So if you request 4 samples from a stereo OPL, you will get
-	 * a total of two left channel and two right channel samples.
-	 */
-	virtual void generateSamples(int16 *buffer, int numSamples) = 0;
-
-private:
-	int _baseFreq;
-
-	int _nextTick;
-	int _samplesPerTick;
-
-	Audio::SoundHandle *_handle;
+	using Audio::Chip::start;
+	void start(TimerCallback *callback) { start(callback, DEFAULT_CALLBACK_FREQUENCY); }
 };
 
 } // End of namespace CMS
diff --git a/audio/fmopl.cpp b/audio/fmopl.cpp
index ec7c5a4b167..5e7ca91a46c 100644
--- a/audio/fmopl.cpp
+++ b/audio/fmopl.cpp
@@ -21,7 +21,6 @@
 
 #include "audio/fmopl.h"
 
-#include "audio/mixer.h"
 #ifdef USE_RETROWAVE
 #include "audio/rwopl3.h"
 #endif
@@ -30,9 +29,7 @@
 #include "audio/softsynth/opl/nuked.h"
 
 #include "common/config-manager.h"
-#include "common/system.h"
 #include "common/textconsole.h"
-#include "common/timer.h"
 #include "common/translation.h"
 
 namespace OPL {
@@ -249,16 +246,6 @@ OPL *Config::create(DriverId driver, OplType type) {
 	}
 }
 
-void OPL::start(TimerCallback *callback, int timerFrequency) {
-	_callback.reset(callback);
-	startCallbacks(timerFrequency);
-}
-
-void OPL::stop() {
-	stopCallbacks();
-	_callback.reset();
-}
-
 void OPL::initDualOpl2OnOpl3(Config::OplType oplType) {
 	if (oplType != Config::OplType::kDualOpl2)
 		return;
@@ -345,131 +332,4 @@ bool OPL::emulateDualOpl2OnOpl3(int r, int v, Config::OplType oplType) {
 
 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),
-	_baseFreq(0),
-	_handle(new Audio::SoundHandle()) {
-}
-
-EmulatedOPL::~EmulatedOPL() {
-	// 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();
-
-	delete _handle;
-}
-
-int EmulatedOPL::readBuffer(int16 *buffer, const int numSamples) {
-	const int stereoFactor = isStereo() ? 2 : 1;
-	int len = numSamples / stereoFactor;
-	int step;
-
-	do {
-		step = len;
-		if (step > (_nextTick >> FIXP_SHIFT))
-			step = (_nextTick >> FIXP_SHIFT);
-
-		generateSamples(buffer, step * stereoFactor);
-
-		_nextTick -= step << FIXP_SHIFT;
-		if (!(_nextTick >> FIXP_SHIFT)) {
-			if (_callback && _callback->isValid())
-				(*_callback)();
-
-			_nextTick += _samplesPerTick;
-		}
-
-		buffer += step * stereoFactor;
-		len -= step;
-	} while (len);
-
-	return numSamples;
-}
-
-int EmulatedOPL::getRate() const {
-	return g_system->getMixer()->getOutputRate();
-}
-
-void EmulatedOPL::startCallbacks(int timerFrequency) {
-	setCallbackFrequency(timerFrequency);
-	g_system->getMixer()->playStream(Audio::Mixer::kPlainSoundType, _handle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
-}
-
-void EmulatedOPL::stopCallbacks() {
-	g_system->getMixer()->stopHandle(*_handle);
-}
-
-void EmulatedOPL::setCallbackFrequency(int timerFrequency) {
-	_baseFreq = timerFrequency;
-	assert(_baseFreq != 0);
-
-	int d = getRate() / _baseFreq;
-	int r = getRate() % _baseFreq;
-
-	// This is equivalent to (getRate() << FIXP_SHIFT) / BASE_FREQ
-	// but less prone to arithmetic overflow.
-
-	_samplesPerTick = (d << FIXP_SHIFT) + (r << FIXP_SHIFT) / _baseFreq;
-}
-
 } // End of namespace OPL
diff --git a/audio/fmopl.h b/audio/fmopl.h
index a50aff9e23e..52435fc6f1f 100644
--- a/audio/fmopl.h
+++ b/audio/fmopl.h
@@ -22,11 +22,7 @@
 #ifndef AUDIO_FMOPL_H
 #define AUDIO_FMOPL_H
 
-#include "audio/audiostream.h"
-
-#include "common/func.h"
-#include "common/ptr.h"
-#include "common/scummsys.h"
+#include "audio/chip.h"
 
 namespace Audio {
 class SoundHandle;
@@ -113,15 +109,10 @@ private:
 	static const EmulatorDescription _drivers[];
 };
 
-/**
- * The type of the OPL timer callback functor.
- */
-typedef Common::Functor0<void> TimerCallback;
-
 /**
  * A representation of a Yamaha OPL chip.
  */
-class OPL {
+class OPL : virtual public Audio::Chip {
 private:
 	static bool _hasInstance;
 public:
@@ -167,21 +158,8 @@ public:
 	 */
 	virtual void writeReg(int r, int v) = 0;
 
-	/**
-	 * Start the OPL with callbacks.
-	 */
-	void start(TimerCallback *callback, int timerFrequency = kDefaultCallbackFrequency);
-
-	/**
-	 * Stop the OPL
-	 */
-	void stop();
-
-	/**
-	 * Change the callback frequency. This must only be called from a
-	 * timer proc.
-	 */
-	virtual void setCallbackFrequency(int timerFrequency) = 0;
+	using Audio::Chip::start;
+	void start(TimerCallback *callback) { start(callback, kDefaultCallbackFrequency); }
 
 	enum {
 		/**
@@ -213,104 +191,10 @@ protected:
 	*/
 	bool emulateDualOpl2OnOpl3(int r, int v, Config::OplType oplType);
 
-	/**
-	 * Start the callbacks.
-	 */
-	virtual void startCallbacks(int timerFrequency) = 0;
-
-	/**
-	 * Stop the callbacks.
-	 */
-	virtual void stopCallbacks() = 0;
-
-	/**
-	 * The functor for callbacks.
-	 */
-	Common::ScopedPtr<TimerCallback> _callback;
-
 	bool _rhythmMode;
 	int _connectionFeedbackValues[3];
 };
 
-/**
- * An OPL that represents a real OPL, as opposed to an emulated one.
- *
- * This will use an actual timer instead of using one calculated from
- * the number of samples in an AudioStream::readBuffer call.
- */
-class RealOPL : public OPL {
-public:
-	RealOPL();
-	virtual ~RealOPL();
-
-	// OPL API
-	void setCallbackFrequency(int timerFrequency);
-
-protected:
-	// OPL API
-	void startCallbacks(int timerFrequency);
-	void stopCallbacks();
-	virtual void onTimer();
-
-private:
-	static void timerProc(void *refCon);
-
-	uint _baseFreq;
-	uint _remainingTicks;
-
-	enum {
-		kMaxFreq = 100
-	};
-};
-
-/**
- * An OPL that represents an emulated OPL.
- *
- * This will send callbacks based on the number of samples
- * decoded in readBuffer().
- */
-class EmulatedOPL : public OPL, protected Audio::AudioStream {
-public:
-	EmulatedOPL();
-	virtual ~EmulatedOPL();
-
-	// OPL API
-	void setCallbackFrequency(int timerFrequency);
-
-	// AudioStream API
-	int readBuffer(int16 *buffer, const int numSamples);
-	int getRate() const;
-	bool endOfData() const { return false; }
-
-protected:
-	// OPL API
-	void startCallbacks(int timerFrequency);
-	void stopCallbacks();
-
-	/**
-	 * Read up to 'length' samples.
-	 *
-	 * Data will be in native endianess, 16 bit per sample, signed.
-	 * For stereo OPL, buffer will be filled with interleaved
-	 * left and right channel samples, starting with a left sample.
-	 * Furthermore, the samples in the left and right are summed up.
-	 * So if you request 4 samples from a stereo OPL, you will get
-	 * a total of two left channel and two right channel samples.
-	 */
-	virtual void generateSamples(int16 *buffer, int numSamples) = 0;
-
-private:
-	int _baseFreq;
-
-	enum {
-		FIXP_SHIFT = 16
-	};
-
-	int _nextTick;
-	int _samplesPerTick;
-
-	Audio::SoundHandle *_handle;
-};
 /** @} */
 } // End of namespace OPL
 
diff --git a/audio/module.mk b/audio/module.mk
index 309433766b1..186a536830b 100644
--- a/audio/module.mk
+++ b/audio/module.mk
@@ -5,6 +5,7 @@ MODULE_OBJS := \
 	adlib_ms.o \
 	audiostream.o \
 	casio.o \
+	chip.o \
 	cms.o \
 	fmopl.o \
 	mac_plugin.o \
diff --git a/audio/opl2lpt.cpp b/audio/opl2lpt.cpp
index dc350ff40e5..f097b2629b9 100644
--- a/audio/opl2lpt.cpp
+++ b/audio/opl2lpt.cpp
@@ -55,7 +55,7 @@ static const uint8 OPL2LPTRegisterWrite[] = {
 namespace OPL {
 namespace OPL2LPT {
 
-class OPL : public ::OPL::RealOPL {
+class OPL : public ::OPL::OPL, public Audio::RealChip {
 private:
 	struct parport *_pport;
 	Config::OplType _type;
diff --git a/audio/rwopl3.cpp b/audio/rwopl3.cpp
index 2b613cf5a0d..49bbcf8cc95 100644
--- a/audio/rwopl3.cpp
+++ b/audio/rwopl3.cpp
@@ -229,7 +229,7 @@ void OPL::onTimer() {
 		_rwMutex->unlock();
 	}
 
-	RealOPL::onTimer();
+	Audio::RealChip::onTimer();
 }
 
 OPL *create(Config::OplType type) {
diff --git a/audio/rwopl3.h b/audio/rwopl3.h
index ca09d4d32fd..63ab838396b 100644
--- a/audio/rwopl3.h
+++ b/audio/rwopl3.h
@@ -34,7 +34,7 @@
 namespace OPL {
 namespace RetroWaveOPL3 {
 
-class OPL : public ::OPL::RealOPL {
+class OPL : public ::OPL::OPL, public Audio::RealChip {
 private:
 	enum RWConnType {
 		RWCONNTYPE_POSIX_SERIAL,
diff --git a/audio/softsynth/cms.h b/audio/softsynth/cms.h
index 29f7fce9029..652e40dd2c9 100644
--- a/audio/softsynth/cms.h
+++ b/audio/softsynth/cms.h
@@ -64,7 +64,7 @@ struct SAA1099 {
 	struct saa1099_noise noise[2];		/* noise generators */
 };
 
-class DOSBoxCMS : public ::CMS::EmulatedCMS {
+class DOSBoxCMS : public ::CMS::CMS, public Audio::EmulatedChip {
 public:
 	DOSBoxCMS(uint32 basePort = 0x220) {
 		memset(_saa1099, 0, sizeof(SAA1099)*2);
diff --git a/audio/softsynth/opl/dosbox.h b/audio/softsynth/opl/dosbox.h
index 7cc12f571b5..b30892b335d 100644
--- a/audio/softsynth/opl/dosbox.h
+++ b/audio/softsynth/opl/dosbox.h
@@ -68,13 +68,13 @@ namespace DBOPL {
 struct Chip;
 } // end of namespace DBOPL
 
-class OPL : public ::OPL::EmulatedOPL {
+class OPL : public ::OPL::OPL, public Audio::EmulatedChip {
 private:
 	Config::OplType _type;
 	uint _rate;
 
 	DBOPL::Chip *_emulator;
-	Chip _chip[2];
+	::OPL::DOSBox::Chip _chip[2];
 	union {
 		uint16 normal;
 		uint8 dual[2];
diff --git a/audio/softsynth/opl/mame.h b/audio/softsynth/opl/mame.h
index 7b28778877a..217399a60b3 100644
--- a/audio/softsynth/opl/mame.h
+++ b/audio/softsynth/opl/mame.h
@@ -173,7 +173,7 @@ void YM3812UpdateOne(FM_OPL *OPL, int16 *buffer, int length);
 FM_OPL *makeAdLibOPL(int rate);
 
 // OPL API implementation
-class OPL : public ::OPL::EmulatedOPL {
+class OPL : public ::OPL::OPL, public Audio::EmulatedChip {
 private:
 	FM_OPL *_opl;
 public:
diff --git a/audio/softsynth/opl/nuked.h b/audio/softsynth/opl/nuked.h
index 5faa1ee69fd..fe584ec4371 100644
--- a/audio/softsynth/opl/nuked.h
+++ b/audio/softsynth/opl/nuked.h
@@ -163,7 +163,7 @@ void OPL3_Generate4Ch(opl3_chip *chpi, int16_t *buf4);
 void OPL3_Generate4ChResampled(opl3_chip *chip, int16_t *buf4);
 void OPL3_Generate4ChStream(opl3_chip *chip, int16_t *sndptr1, int16_t *sndptr2, uint32_t numsamples);
 
-class OPL : public ::OPL::EmulatedOPL {
+class OPL : public ::OPL::OPL, public Audio::EmulatedChip {
 private:
 	Config::OplType _type;
 	uint _rate;




More information about the Scummvm-git-logs mailing list