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

dreammaster dreammaster at scummvm.org
Sat Jun 30 19:20:23 CEST 2018


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

Summary:
eb829a33c9 XEEN: Split the Adlib sound driver into it's own file


Commit: eb829a33c91496c516cb7245286c8e1029fd145a
    https://github.com/scummvm/scummvm/commit/eb829a33c91496c516cb7245286c8e1029fd145a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2018-06-30T10:20:15-07:00

Commit Message:
XEEN: Split the Adlib sound driver into it's own file

Changed paths:
  A engines/xeen/sound_driver_adlib.cpp
  A engines/xeen/sound_driver_adlib.h
    engines/xeen/module.mk
    engines/xeen/sound.cpp
    engines/xeen/sound_driver.cpp
    engines/xeen/sound_driver.h


diff --git a/engines/xeen/module.mk b/engines/xeen/module.mk
index 5b3f697..4b8272d 100644
--- a/engines/xeen/module.mk
+++ b/engines/xeen/module.mk
@@ -53,6 +53,7 @@ MODULE_OBJS := \
 	scripts.o \
 	sound.o \
 	sound_driver.o \
+	sound_driver_adlib.o \
 	spells.o \
 	sprites.o \
 	subtitles.o \
diff --git a/engines/xeen/sound.cpp b/engines/xeen/sound.cpp
index ae70c1f..5148a00 100644
--- a/engines/xeen/sound.cpp
+++ b/engines/xeen/sound.cpp
@@ -24,6 +24,7 @@
 #include "audio/decoders/voc.h"
 #include "common/config-manager.h"
 #include "xeen/sound.h"
+#include "xeen/sound_driver_adlib.h"
 #include "xeen/xeen.h"
 
 namespace Xeen {
@@ -31,7 +32,7 @@ namespace Xeen {
 Sound::Sound(Audio::Mixer *mixer) : _mixer(mixer), _fxOn(true), _musicOn(true), _subtitles(false),
 		_songData(nullptr), _effectsData(nullptr), _musicSide(0), _musicPercent(100),
 		_musicVolume(0), _sfxVolume(0) {
-	_SoundDriver = new AdlibSoundDriver();
+	_SoundDriver = new SoundDriverAdlib();
 }
 
 Sound::~Sound() {
diff --git a/engines/xeen/sound_driver.cpp b/engines/xeen/sound_driver.cpp
index 967f53a..108eba2 100644
--- a/engines/xeen/sound_driver.cpp
+++ b/engines/xeen/sound_driver.cpp
@@ -28,10 +28,6 @@
 
 namespace Xeen {
 
-#define CALLBACKS_PER_SECOND 73
-
-/*------------------------------------------------------------------------*/
-
 SoundDriver::SoundDriver() : _musicPlaying(false), _fxPlaying(false),
 		_musCountdownTimer(0), _fxCountdownTimer(0), _musDataPtr(nullptr),
 		_fxDataPtr(nullptr), _fxStartPtr(nullptr), _musStartPtr(nullptr),
@@ -259,400 +255,4 @@ const CommandFn SoundDriver::FX_COMMANDS[16] = {
 	&SoundDriver::cmdChangeFrequency,  &SoundDriver::fxEndSubroutine
 };
 
-/*------------------------------------------------------------------------*/
-
-AdlibSoundDriver::AdlibSoundDriver() : _field180(0), _field181(0), _field182(0),
-		_musicVolume(0), _sfxVolume(0) {
-	Common::fill(&_musInstrumentPtrs[0], &_musInstrumentPtrs[16], (const byte *)nullptr);
-	Common::fill(&_fxInstrumentPtrs[0], &_fxInstrumentPtrs[16], (const byte *)nullptr);
-
-	_opl = OPL::Config::create();
-	_opl->init();
-	_opl->start(new Common::Functor0Mem<void, AdlibSoundDriver>(this, &AdlibSoundDriver::onTimer), CALLBACKS_PER_SECOND);
-	initialize();
-}
-
-AdlibSoundDriver::~AdlibSoundDriver() {
-	_opl->stop();
-	delete _opl;
-}
-
-void AdlibSoundDriver::onTimer() {
-	Common::StackLock slock(_driverMutex);
-	execute();
-	flush();
-}
-
-void AdlibSoundDriver::initialize() {
-	write(1, 0x20);
-	write(8, 0);
-	write(0xBD, 0);
-
-	resetFrequencies();
-	AdlibSoundDriver::resetFX();
-}
-
-void AdlibSoundDriver::playFX(uint effectId, const byte *data) {
-	Common::StackLock slock(_driverMutex);
-	SoundDriver::playFX(effectId, data);
-}
-
-void AdlibSoundDriver::playSong(const byte *data) {
-	Common::StackLock slock(_driverMutex);
-	SoundDriver::playSong(data);
-	_field180 = 0;
-	resetFrequencies();
-}
-
-int AdlibSoundDriver::songCommand(uint commandId, byte musicVolume, byte sfxVolume) {
-	Common::StackLock slock(_driverMutex);
-	SoundDriver::songCommand(commandId, musicVolume, sfxVolume);
-
-	if (commandId == STOP_SONG) {
-		_field180 = 0;
-		resetFrequencies();
-	} else if (commandId == RESTART_SONG) {
-		_field180 = 0;
-		_musicPlaying = true;
-	} else if (commandId < 0x100) {
-		if (_musicPlaying) {
-			_field180 = commandId;
-			_field182 = 63;
-		}
-	} else if (commandId == SET_VOLUME) {
-		_musicVolume = musicVolume;
-		_sfxVolume = sfxVolume;
-	} else if (commandId == GET_STATUS) {
-		return _field180;
-	}
-
-	return 0;
-}
-
-void AdlibSoundDriver::write(int reg, int val) {
-	_queue.push(RegisterValue(reg, val));
-	debugC(9, kDebugSound, "%.2x %.2x", reg, val);
-}
-
-void AdlibSoundDriver::flush() {
-	Common::StackLock slock(_driverMutex);
-
-	while (!_queue.empty()) {
-		RegisterValue v = _queue.pop();
-		_opl->writeReg(v._regNum, v._value);
-	}
-}
-
-void AdlibSoundDriver::pausePostProcess() {
-	if (_field180 && ((_field181 += _field180) < 0)) {
-		if (--_field182 < 0) {
-			_musicPlaying = false;
-			_field180 = 0;
-			resetFrequencies();
-		} else {
-			for (int channelNum = 6; channelNum >= 0; --channelNum) {
-				if (_channels[channelNum]._volume < 63)
-					setOutputLevel(channelNum, ++_channels[channelNum]._volume);
-			}
-		}
-	}
-
-	for (int channelNum = 8; channelNum > (_exclude7 ? 7 : 6); --channelNum) {
-		Channel &chan = _channels[channelNum];
-		if (!chan._changeFrequency || (chan._freqCtr += chan._freqCtrChange) >= 0)
-			continue;
-
-		uint freq = chan._frequency & 0x3FF;
-		uint val = chan._frequency >> 8;
-		byte val1 = val & 0x20;
-		byte val2 = val & 0x1C;
-
-		freq += chan._freqChange;
-		if (chan._freqChange < 0) {
-			if (freq <= 388) {
-				freq <<= 1;
-				if (!(freq & 0x3FF))
-					--freq;
-			}
-
-			val2 = (val2 - 4) & 0x1C;
-		} else {
-			if (freq >= 734) {
-				freq >>= 1;
-				if (!(freq & 0x3FF))
-					++freq;
-			}
-
-			val2 = (val2 + 4) & 0x1C;
-		}
-
-		freq &= 0x3FF;
-		freq |= (val2 << 8);
-		freq |= val1;
-		chan._frequency = freq;
-		setFrequency(channelNum, freq);
-	}
-}
-
-void AdlibSoundDriver::resetFX() {
-	if (!_exclude7) {
-		_channels[7]._frequency = 0;
-		setFrequency(7, 0);
-		_channels[7]._volume = 63;
-		setOutputLevel(7, 63);
-	}
-
-	_channels[8]._frequency = 0;
-	setFrequency(8, 0);
-	_channels[8]._volume = 63;
-	setOutputLevel(8, 63);
-}
-
-void AdlibSoundDriver::resetFrequencies() {
-	for (int opNum = 6; opNum >= 0; --opNum) {
-		_channels[opNum]._frequency = 0;
-		setFrequency(opNum, 0);
-	}
-}
-
-void AdlibSoundDriver::setFrequency(byte operatorNum, uint frequency) {
-	write(0xA0 + operatorNum, frequency & 0xff);
-	write(0xB0 + operatorNum, (frequency >> 8));
-}
-
-uint AdlibSoundDriver::calcFrequency(byte note) {
-	return WAVEFORMS[note & 0x1F] + ((note & 0xE0) << 5);
-}
-
-void AdlibSoundDriver::setOutputLevel(byte channelNum, uint level) {
-	write(0x40 + OPERATOR2_INDEXES[channelNum], level |
-		(_channels[channelNum]._scalingValue & 0xC0));
-}
-
-void AdlibSoundDriver::playInstrument(byte channelNum, const byte *data, byte volume) {
-	byte op1 = OPERATOR1_INDEXES[channelNum];
-	byte op2 = OPERATOR2_INDEXES[channelNum];
-	debugC(2, kDebugSound, "---START-playInstrument - %d", channelNum);
-	write(0x20 + op1, *data++);
-	write(0x40 + op1, *data++);
-	write(0x60 + op1, *data++);
-	write(0x80 + op1, *data++);
-	write(0xE0 + op1, *data++);
-	write(0x20 + op2, *data++);
-
-	int scalingVal = *data++;
-	_channels[channelNum]._scalingValue = scalingVal;
-	scalingVal += (127 - volume) / 2;
-
-	if (scalingVal > 63) {
-		scalingVal = 63;
-		if (_field180)
-			scalingVal = (scalingVal & 0xC0) | _field182;
-	}
-	write(0x40 + op2, scalingVal);
-
-	write(0x60 + op2, *data++);
-	write(0x80 + op2, *data++);
-	write(0xE0 + op2, *data++);
-	write(0xC0 + channelNum, *data++);
-
-	debugC(2, kDebugSound, "---END-playInstrument");
-}
-
-bool AdlibSoundDriver::musSetInstrument(const byte *&srcP, byte param) {
-	debugC(3, kDebugSound, "musSetInstrument %d", param);
-	_musInstrumentPtrs[param] = srcP;
-	srcP += 26;
-
-	return false;
-}
-
-bool AdlibSoundDriver::musSetPitchWheel(const byte *&srcP, byte param) {
-	// Adlib does not support this
-	debugC(3, kDebugSound, "musSetPitchWheel");
-	srcP += 2;
-	return false;
-}
-
-bool AdlibSoundDriver::musSetPanning(const byte *&srcP, byte param) {
-	// Adlib does not support this
-	debugC(3, kDebugSound, "musSetPanning");
-	++srcP;
-	return false;
-}
-
-bool AdlibSoundDriver::musFade(const byte *&srcP, byte param) {
-	++srcP;
-	if (param < 7)
-		setFrequency(param, _channels[param]._frequency);
-	debugC(3, kDebugSound, "musFade");
-
-	return false;
-}
-
-bool AdlibSoundDriver::musStartNote(const byte *&srcP, byte param) {
-	if (param < 7) {
-		byte note = *srcP++;
-		++srcP;		// Second byte is fade, which is unused by Adlib
-		uint freq = calcFrequency(note);
-		debugC(3, kDebugSound, "musStartNote %x -> %x", note, freq);
-
-		setFrequency(param, freq);
-		freq |= 0x2000;
-		_channels[param]._frequency = freq;
-		setFrequency(param, freq);
-	} else {
-		srcP += 2;
-		debugC(3, kDebugSound, "musStartNote skipped");
-	}
-
-	return false;
-}
-
-bool AdlibSoundDriver::musSetVolume(const byte *&srcP, byte param) {
-	debugC(3, kDebugSound, "musSetVolume %d", (int)*srcP);
-
-	if (*srcP++ == 5 && !_field180) {
-		_channels[param]._volume = *srcP;
-		setOutputLevel(param, *srcP);
-	}
-
-	++srcP;
-	return false;
-}
-
-bool AdlibSoundDriver::musInjectMidi(const byte *&srcP, byte param) {
-	// Adlib does not support MIDI. So simply keep skipping over bytes
-	// until an 'F7' byte is found that flags the end of the MIDI data
-	debugC(3, kDebugSound, "musInjectMidi");
-	while (*srcP++ != 0xF7)
-		;
-
-	return false;
-}
-
-bool AdlibSoundDriver::musPlayInstrument(const byte *&srcP, byte param) {
-	byte instrument = *srcP++;
-	debugC(3, kDebugSound, "musPlayInstrument %d, %d", param, instrument);
-
-	if (param < 7)
-		playInstrument(param, _musInstrumentPtrs[instrument], _musicVolume);
-
-	return false;
-}
-
-bool AdlibSoundDriver::fxSetInstrument(const byte *&srcP, byte param) {
-	debugC(3, kDebugSound, "fxSetInstrument %d", param);
-	_fxInstrumentPtrs[param] = srcP;
-	srcP += 11;
-
-	return false;
-}
-
-bool AdlibSoundDriver::fxSetVolume(const byte *&srcP, byte param) {
-	debugC(3, kDebugSound, "fxSetVolume %d", (int)*srcP);
-
-	if (!_field180 && (!_exclude7 || param != 7)) {
-		_channels[param]._volume = *srcP;
-		setOutputLevel(param, *srcP);
-	}
-
-	++srcP;
-	return false;
-}
-
-bool AdlibSoundDriver::fxMidiReset(const byte *&srcP, byte param) {
-	debugC(3, kDebugSound, "fxMidiReset");
-	return false;
-}
-
-bool AdlibSoundDriver::fxMidiDword(const byte *&srcP, byte param) {
-	debugC(3, kDebugSound, "fxMidiDword");
-	return false;
-}
-
-bool AdlibSoundDriver::fxSetPanning(const byte *&srcP, byte param) {
-	byte note = *srcP++;
-	debugC(3, kDebugSound, "fxSetPanning - %x", note);
-
-	if (!_exclude7 || param != 7) {
-		uint freq = calcFrequency(note);
-		setFrequency(param, freq);
-		_channels[param]._frequency = freq;
-	}
-
-	return false;
-}
-
-bool AdlibSoundDriver::fxChannelOff(const byte *&srcP, byte param) {
-	debugC(3, kDebugSound, "fxChannelOff %d", param);
-	_channels[param]._frequency &= ~0x2000;
-	write(0xB0 + param, _channels[param]._frequency);
-	return false;
-}
-
-bool AdlibSoundDriver::fxFade(const byte *&srcP, byte param) {
-	uint freq = calcFrequency(*srcP++);
-	debugC(3, kDebugSound, "fxFade %d %x", param, freq);
-
-	if (!_exclude7 || param != 7) {
-		_channels[param]._frequency = freq;
-		setFrequency(param, freq);
-	}
-
-	return false;
-}
-
-bool AdlibSoundDriver::fxStartNote(const byte *&srcP, byte param) {
-	if (!_exclude7 || param != 7) {
-		byte note = *srcP++;
-		uint freq = calcFrequency(note);
-		debugC(3, kDebugSound, "fxStartNote %x -> %x", note, freq);
-
-		setFrequency(param, freq);
-		freq |= 0x2000;
-		_channels[param]._frequency = freq;
-		setFrequency(param, freq);
-	} else {
-		++srcP;
-		debugC(3, kDebugSound, "fxStartNote skipped");
-	}
-
-	return false;
-}
-
-bool AdlibSoundDriver::fxInjectMidi(const byte *&srcP, byte param) {
-	// Surpringly, unlike the musInjectMidi, this version doesn't have
-	// any logic to skip over following MIDI data. Which must mean the opcode
-	// and/or it's data aren't present in the admus driver file
-	debugC(3, kDebugSound, "fxInjectMidi");
-	return false;
-}
-
-bool AdlibSoundDriver::fxPlayInstrument(const byte *&srcP, byte param) {
-	byte instrument = *srcP++;
-	debugC(3, kDebugSound, "fxPlayInstrument %d, %d", param, instrument);
-
-	if (!_exclude7 || param != 7)
-		playInstrument(param, _fxInstrumentPtrs[instrument], _sfxVolume);
-
-	return false;
-}
-
-/*------------------------------------------------------------------------*/
-
-const byte AdlibSoundDriver::OPERATOR1_INDEXES[CHANNEL_COUNT] = {
-	0, 1, 2, 8, 9, 0xA, 0x10, 0x11, 0x12
-};
-
-const byte AdlibSoundDriver::OPERATOR2_INDEXES[CHANNEL_COUNT] = {
-	3, 4, 5, 0xB, 0xC, 0xD, 0x13, 0x14, 0x15
-};
-
-const uint AdlibSoundDriver::WAVEFORMS[24] = {
-	0, 347, 388, 436, 462, 519, 582, 646,
-	0, 362, 406, 455, 484, 542, 607, 680,
-	0, 327, 367, 412, 436, 489, 549, 618
-};
-
 } // End of namespace Xeen
diff --git a/engines/xeen/sound_driver.h b/engines/xeen/sound_driver.h
index d4edd49..bad357b 100644
--- a/engines/xeen/sound_driver.h
+++ b/engines/xeen/sound_driver.h
@@ -177,132 +177,6 @@ public:
 	bool isPlaying() const { return _musicPlaying; }
 };
 
-class AdlibSoundDriver : public SoundDriver {
-	struct RegisterValue {
-		uint8 _regNum;
-		uint8 _value;
-
-		RegisterValue(int regNum, int value) {
-			_regNum = regNum; _value = value;
-		}
-	};
-private:
-	static const byte OPERATOR1_INDEXES[CHANNEL_COUNT];
-	static const byte OPERATOR2_INDEXES[CHANNEL_COUNT];
-	static const uint WAVEFORMS[24];
-private:
-	OPL::OPL *_opl;
-	Common::Queue<RegisterValue> _queue;
-	Common::Mutex _driverMutex;
-	const byte *_musInstrumentPtrs[16];
-	const byte *_fxInstrumentPtrs[16];
-	int _field180;
-	int _field181;
-	int _field182;
-	int _musicVolume, _sfxVolume;
-private:
-	/**
-	 * Initializes the state of the Adlib OPL driver
-	 */
-	void initialize();
-
-	/**
-	 * Adds a register write to the pending queue that will be flushed
-	 * out to the OPL on the next timer call
-	 */
-	void write(int reg, int val);
-
-	/**
-	 * Timer function for OPL
-	 */
-	void onTimer();
-
-	/**
-	 * Flushes any pending writes to the OPL
-	 */
-	void flush();
-
-	/**
-	 * Resets all the output frequencies
-	 */
-	void resetFrequencies();
-
-	/**
-	 * Sets the frequency for an operator
-	 */
-	void setFrequency(byte operatorNum, uint frequency);
-
-	/**
-	 * Calculates the frequency for a note
-	 */
-	uint calcFrequency(byte note);
-
-	/**
-	 * Sets the output level for a channel
-	 */
-	void setOutputLevel(byte channelNum, uint level);
-
-	/**
-	 * Starts playing an instrument
-	 */
-	void playInstrument(byte channelNum, const byte *data, byte volume);
-protected:
-	virtual bool musSetInstrument(const byte *&srcP, byte param);
-	virtual bool musSetPitchWheel(const byte *&srcP, byte param);
-	virtual bool musSetPanning(const byte *&srcP, byte param);
-	virtual bool musFade(const byte *&srcP, byte param);
-	virtual bool musStartNote(const byte *&srcP, byte param);
-	virtual bool musSetVolume(const byte *&srcP, byte param);
-	virtual bool musInjectMidi(const byte *&srcP, byte param);
-	virtual bool musPlayInstrument(const byte *&srcP, byte param);
-
-	virtual bool fxSetInstrument(const byte *&srcP, byte param);
-	virtual bool fxSetVolume(const byte *&srcP, byte param);
-	virtual bool fxMidiReset(const byte *&srcP, byte param);
-	virtual bool fxMidiDword(const byte *&srcP, byte param);
-	virtual bool fxSetPanning(const byte *&srcP, byte param);
-	virtual bool fxChannelOff(const byte *&srcP, byte param);
-	virtual bool fxFade(const byte *&srcP, byte param);
-	virtual bool fxStartNote(const byte *&srcP, byte param);
-	virtual bool fxInjectMidi(const byte *&srcP, byte param);
-	virtual bool fxPlayInstrument(const byte *&srcP, byte param);
-
-	/**
-	 * Post-processing done when a pause countdown starts or is in progress
-	 */
-	virtual void pausePostProcess();
-
-	/**
-	 * Does a reset of any sound effect
-	 */
-	virtual void resetFX();
-public:
-	/**
-	 * Constructor
-	 */
-	AdlibSoundDriver();
-
-	/**
-	 * Destructor
-	 */
-	virtual ~AdlibSoundDriver();
-
-	/**
-	 * Starts an special effect playing
-	 */
-	virtual void playFX(uint effectId, const byte *data);
-
-	/**
-	 * Plays a song
-	 */
-	virtual void playSong(const byte *data);
-
-	/**
-	 * Executes special music command
-	 */
-	virtual int songCommand(uint commandId, byte musicVolume = 0, byte sfxVolume = 0);
-};
-
 } // End of namespace Xeen
 
 #endif /* XEEN_SOUND_DRIVER_H */
diff --git a/engines/xeen/sound_driver_adlib.cpp b/engines/xeen/sound_driver_adlib.cpp
new file mode 100644
index 0000000..a1a13fa
--- /dev/null
+++ b/engines/xeen/sound_driver_adlib.cpp
@@ -0,0 +1,424 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "xeen/sound_driver_adlib.h"
+#include "xeen/xeen.h"
+
+namespace Xeen {
+
+#define CALLBACKS_PER_SECOND 73
+	
+const byte SoundDriverAdlib::OPERATOR1_INDEXES[CHANNEL_COUNT] = {
+	0, 1, 2, 8, 9, 0xA, 0x10, 0x11, 0x12
+};
+
+const byte SoundDriverAdlib::OPERATOR2_INDEXES[CHANNEL_COUNT] = {
+	3, 4, 5, 0xB, 0xC, 0xD, 0x13, 0x14, 0x15
+};
+
+const uint SoundDriverAdlib::WAVEFORMS[24] = {
+	0, 347, 388, 436, 462, 519, 582, 646,
+	0, 362, 406, 455, 484, 542, 607, 680,
+	0, 327, 367, 412, 436, 489, 549, 618
+};
+
+/*------------------------------------------------------------------------*/
+
+SoundDriverAdlib::SoundDriverAdlib() : _field180(0), _field181(0), _field182(0),
+		_musicVolume(0), _sfxVolume(0) {
+	Common::fill(&_musInstrumentPtrs[0], &_musInstrumentPtrs[16], (const byte *)nullptr);
+	Common::fill(&_fxInstrumentPtrs[0], &_fxInstrumentPtrs[16], (const byte *)nullptr);
+
+	_opl = OPL::Config::create();
+	_opl->init();
+	_opl->start(new Common::Functor0Mem<void, SoundDriverAdlib>(this, &SoundDriverAdlib::onTimer), CALLBACKS_PER_SECOND);
+	initialize();
+}
+
+SoundDriverAdlib::~SoundDriverAdlib() {
+	_opl->stop();
+	delete _opl;
+}
+
+void SoundDriverAdlib::onTimer() {
+	Common::StackLock slock(_driverMutex);
+	execute();
+	flush();
+}
+
+void SoundDriverAdlib::initialize() {
+	write(1, 0x20);
+	write(8, 0);
+	write(0xBD, 0);
+
+	resetFrequencies();
+	SoundDriverAdlib::resetFX();
+}
+
+void SoundDriverAdlib::playFX(uint effectId, const byte *data) {
+	Common::StackLock slock(_driverMutex);
+	SoundDriver::playFX(effectId, data);
+}
+
+void SoundDriverAdlib::playSong(const byte *data) {
+	Common::StackLock slock(_driverMutex);
+	SoundDriver::playSong(data);
+	_field180 = 0;
+	resetFrequencies();
+}
+
+int SoundDriverAdlib::songCommand(uint commandId, byte musicVolume, byte sfxVolume) {
+	Common::StackLock slock(_driverMutex);
+	SoundDriver::songCommand(commandId, musicVolume, sfxVolume);
+
+	if (commandId == STOP_SONG) {
+		_field180 = 0;
+		resetFrequencies();
+	} else if (commandId == RESTART_SONG) {
+		_field180 = 0;
+		_musicPlaying = true;
+	} else if (commandId < 0x100) {
+		if (_musicPlaying) {
+			_field180 = commandId;
+			_field182 = 63;
+		}
+	} else if (commandId == SET_VOLUME) {
+		_musicVolume = musicVolume;
+		_sfxVolume = sfxVolume;
+	} else if (commandId == GET_STATUS) {
+		return _field180;
+	}
+
+	return 0;
+}
+
+void SoundDriverAdlib::write(int reg, int val) {
+	_queue.push(RegisterValue(reg, val));
+	debugC(9, kDebugSound, "%.2x %.2x", reg, val);
+}
+
+void SoundDriverAdlib::flush() {
+	Common::StackLock slock(_driverMutex);
+
+	while (!_queue.empty()) {
+		RegisterValue v = _queue.pop();
+		_opl->writeReg(v._regNum, v._value);
+	}
+}
+
+void SoundDriverAdlib::pausePostProcess() {
+	if (_field180 && ((_field181 += _field180) < 0)) {
+		if (--_field182 < 0) {
+			_musicPlaying = false;
+			_field180 = 0;
+			resetFrequencies();
+		} else {
+			for (int channelNum = 6; channelNum >= 0; --channelNum) {
+				if (_channels[channelNum]._volume < 63)
+					setOutputLevel(channelNum, ++_channels[channelNum]._volume);
+			}
+		}
+	}
+
+	for (int channelNum = 8; channelNum > (_exclude7 ? 7 : 6); --channelNum) {
+		Channel &chan = _channels[channelNum];
+		if (!chan._changeFrequency || (chan._freqCtr += chan._freqCtrChange) >= 0)
+			continue;
+
+		uint freq = chan._frequency & 0x3FF;
+		uint val = chan._frequency >> 8;
+		byte val1 = val & 0x20;
+		byte val2 = val & 0x1C;
+
+		freq += chan._freqChange;
+		if (chan._freqChange < 0) {
+			if (freq <= 388) {
+				freq <<= 1;
+				if (!(freq & 0x3FF))
+					--freq;
+			}
+
+			val2 = (val2 - 4) & 0x1C;
+		} else {
+			if (freq >= 734) {
+				freq >>= 1;
+				if (!(freq & 0x3FF))
+					++freq;
+			}
+
+			val2 = (val2 + 4) & 0x1C;
+		}
+
+		freq &= 0x3FF;
+		freq |= (val2 << 8);
+		freq |= val1;
+		chan._frequency = freq;
+		setFrequency(channelNum, freq);
+	}
+}
+
+void SoundDriverAdlib::resetFX() {
+	if (!_exclude7) {
+		_channels[7]._frequency = 0;
+		setFrequency(7, 0);
+		_channels[7]._volume = 63;
+		setOutputLevel(7, 63);
+	}
+
+	_channels[8]._frequency = 0;
+	setFrequency(8, 0);
+	_channels[8]._volume = 63;
+	setOutputLevel(8, 63);
+}
+
+void SoundDriverAdlib::resetFrequencies() {
+	for (int opNum = 6; opNum >= 0; --opNum) {
+		_channels[opNum]._frequency = 0;
+		setFrequency(opNum, 0);
+	}
+}
+
+void SoundDriverAdlib::setFrequency(byte operatorNum, uint frequency) {
+	write(0xA0 + operatorNum, frequency & 0xff);
+	write(0xB0 + operatorNum, (frequency >> 8));
+}
+
+uint SoundDriverAdlib::calcFrequency(byte note) {
+	return WAVEFORMS[note & 0x1F] + ((note & 0xE0) << 5);
+}
+
+void SoundDriverAdlib::setOutputLevel(byte channelNum, uint level) {
+	write(0x40 + OPERATOR2_INDEXES[channelNum], level |
+		(_channels[channelNum]._scalingValue & 0xC0));
+}
+
+void SoundDriverAdlib::playInstrument(byte channelNum, const byte *data, byte volume) {
+	byte op1 = OPERATOR1_INDEXES[channelNum];
+	byte op2 = OPERATOR2_INDEXES[channelNum];
+	debugC(2, kDebugSound, "---START-playInstrument - %d", channelNum);
+	write(0x20 + op1, *data++);
+	write(0x40 + op1, *data++);
+	write(0x60 + op1, *data++);
+	write(0x80 + op1, *data++);
+	write(0xE0 + op1, *data++);
+	write(0x20 + op2, *data++);
+
+	int scalingVal = *data++;
+	_channels[channelNum]._scalingValue = scalingVal;
+	scalingVal += (127 - volume) / 2;
+
+	if (scalingVal > 63) {
+		scalingVal = 63;
+		if (_field180)
+			scalingVal = (scalingVal & 0xC0) | _field182;
+	}
+	write(0x40 + op2, scalingVal);
+
+	write(0x60 + op2, *data++);
+	write(0x80 + op2, *data++);
+	write(0xE0 + op2, *data++);
+	write(0xC0 + channelNum, *data++);
+
+	debugC(2, kDebugSound, "---END-playInstrument");
+}
+
+bool SoundDriverAdlib::musSetInstrument(const byte *&srcP, byte param) {
+	debugC(3, kDebugSound, "musSetInstrument %d", param);
+	_musInstrumentPtrs[param] = srcP;
+	srcP += 26;
+
+	return false;
+}
+
+bool SoundDriverAdlib::musSetPitchWheel(const byte *&srcP, byte param) {
+	// Adlib does not support this
+	debugC(3, kDebugSound, "musSetPitchWheel");
+	srcP += 2;
+	return false;
+}
+
+bool SoundDriverAdlib::musSetPanning(const byte *&srcP, byte param) {
+	// Adlib does not support this
+	debugC(3, kDebugSound, "musSetPanning");
+	++srcP;
+	return false;
+}
+
+bool SoundDriverAdlib::musFade(const byte *&srcP, byte param) {
+	++srcP;
+	if (param < 7)
+		setFrequency(param, _channels[param]._frequency);
+	debugC(3, kDebugSound, "musFade");
+
+	return false;
+}
+
+bool SoundDriverAdlib::musStartNote(const byte *&srcP, byte param) {
+	if (param < 7) {
+		byte note = *srcP++;
+		++srcP;		// Second byte is fade, which is unused by Adlib
+		uint freq = calcFrequency(note);
+		debugC(3, kDebugSound, "musStartNote %x -> %x", note, freq);
+
+		setFrequency(param, freq);
+		freq |= 0x2000;
+		_channels[param]._frequency = freq;
+		setFrequency(param, freq);
+	} else {
+		srcP += 2;
+		debugC(3, kDebugSound, "musStartNote skipped");
+	}
+
+	return false;
+}
+
+bool SoundDriverAdlib::musSetVolume(const byte *&srcP, byte param) {
+	debugC(3, kDebugSound, "musSetVolume %d", (int)*srcP);
+
+	if (*srcP++ == 5 && !_field180) {
+		_channels[param]._volume = *srcP;
+		setOutputLevel(param, *srcP);
+	}
+
+	++srcP;
+	return false;
+}
+
+bool SoundDriverAdlib::musInjectMidi(const byte *&srcP, byte param) {
+	// Adlib does not support MIDI. So simply keep skipping over bytes
+	// until an 'F7' byte is found that flags the end of the MIDI data
+	debugC(3, kDebugSound, "musInjectMidi");
+	while (*srcP++ != 0xF7)
+		;
+
+	return false;
+}
+
+bool SoundDriverAdlib::musPlayInstrument(const byte *&srcP, byte param) {
+	byte instrument = *srcP++;
+	debugC(3, kDebugSound, "musPlayInstrument %d, %d", param, instrument);
+
+	if (param < 7)
+		playInstrument(param, _musInstrumentPtrs[instrument], _musicVolume);
+
+	return false;
+}
+
+bool SoundDriverAdlib::fxSetInstrument(const byte *&srcP, byte param) {
+	debugC(3, kDebugSound, "fxSetInstrument %d", param);
+	_fxInstrumentPtrs[param] = srcP;
+	srcP += 11;
+
+	return false;
+}
+
+bool SoundDriverAdlib::fxSetVolume(const byte *&srcP, byte param) {
+	debugC(3, kDebugSound, "fxSetVolume %d", (int)*srcP);
+
+	if (!_field180 && (!_exclude7 || param != 7)) {
+		_channels[param]._volume = *srcP;
+		setOutputLevel(param, *srcP);
+	}
+
+	++srcP;
+	return false;
+}
+
+bool SoundDriverAdlib::fxMidiReset(const byte *&srcP, byte param) {
+	debugC(3, kDebugSound, "fxMidiReset");
+	return false;
+}
+
+bool SoundDriverAdlib::fxMidiDword(const byte *&srcP, byte param) {
+	debugC(3, kDebugSound, "fxMidiDword");
+	return false;
+}
+
+bool SoundDriverAdlib::fxSetPanning(const byte *&srcP, byte param) {
+	byte note = *srcP++;
+	debugC(3, kDebugSound, "fxSetPanning - %x", note);
+
+	if (!_exclude7 || param != 7) {
+		uint freq = calcFrequency(note);
+		setFrequency(param, freq);
+		_channels[param]._frequency = freq;
+	}
+
+	return false;
+}
+
+bool SoundDriverAdlib::fxChannelOff(const byte *&srcP, byte param) {
+	debugC(3, kDebugSound, "fxChannelOff %d", param);
+	_channels[param]._frequency &= ~0x2000;
+	write(0xB0 + param, _channels[param]._frequency);
+	return false;
+}
+
+bool SoundDriverAdlib::fxFade(const byte *&srcP, byte param) {
+	uint freq = calcFrequency(*srcP++);
+	debugC(3, kDebugSound, "fxFade %d %x", param, freq);
+
+	if (!_exclude7 || param != 7) {
+		_channels[param]._frequency = freq;
+		setFrequency(param, freq);
+	}
+
+	return false;
+}
+
+bool SoundDriverAdlib::fxStartNote(const byte *&srcP, byte param) {
+	if (!_exclude7 || param != 7) {
+		byte note = *srcP++;
+		uint freq = calcFrequency(note);
+		debugC(3, kDebugSound, "fxStartNote %x -> %x", note, freq);
+
+		setFrequency(param, freq);
+		freq |= 0x2000;
+		_channels[param]._frequency = freq;
+		setFrequency(param, freq);
+	} else {
+		++srcP;
+		debugC(3, kDebugSound, "fxStartNote skipped");
+	}
+
+	return false;
+}
+
+bool SoundDriverAdlib::fxInjectMidi(const byte *&srcP, byte param) {
+	// Surpringly, unlike the musInjectMidi, this version doesn't have
+	// any logic to skip over following MIDI data. Which must mean the opcode
+	// and/or it's data aren't present in the admus driver file
+	debugC(3, kDebugSound, "fxInjectMidi");
+	return false;
+}
+
+bool SoundDriverAdlib::fxPlayInstrument(const byte *&srcP, byte param) {
+	byte instrument = *srcP++;
+	debugC(3, kDebugSound, "fxPlayInstrument %d, %d", param, instrument);
+
+	if (!_exclude7 || param != 7)
+		playInstrument(param, _fxInstrumentPtrs[instrument], _sfxVolume);
+
+	return false;
+}
+
+} // End of namespace Xeen
diff --git a/engines/xeen/sound_driver_adlib.h b/engines/xeen/sound_driver_adlib.h
new file mode 100644
index 0000000..def2557
--- /dev/null
+++ b/engines/xeen/sound_driver_adlib.h
@@ -0,0 +1,162 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef XEEN_SOUND_DRIVER_ADLIB_H
+#define XEEN_SOUND_DRIVER_ADLIB_H
+
+#include "xeen/sound_driver.h"
+
+namespace OPL {
+	class OPL;
+}
+
+namespace Xeen {
+
+class SoundDriverAdlib : public SoundDriver {
+	struct RegisterValue {
+		uint8 _regNum;
+		uint8 _value;
+
+		RegisterValue(int regNum, int value) {
+			_regNum = regNum; _value = value;
+		}
+	};
+private:
+	static const byte OPERATOR1_INDEXES[CHANNEL_COUNT];
+	static const byte OPERATOR2_INDEXES[CHANNEL_COUNT];
+	static const uint WAVEFORMS[24];
+private:
+	OPL::OPL *_opl;
+	Common::Queue<RegisterValue> _queue;
+	Common::Mutex _driverMutex;
+	const byte *_musInstrumentPtrs[16];
+	const byte *_fxInstrumentPtrs[16];
+	int _field180;
+	int _field181;
+	int _field182;
+	int _musicVolume, _sfxVolume;
+private:
+	/**
+	 * Initializes the state of the Adlib OPL driver
+	 */
+	void initialize();
+
+	/**
+	 * Adds a register write to the pending queue that will be flushed
+	 * out to the OPL on the next timer call
+	 */
+	void write(int reg, int val);
+
+	/**
+	 * Timer function for OPL
+	 */
+	void onTimer();
+
+	/**
+	 * Flushes any pending writes to the OPL
+	 */
+	void flush();
+
+	/**
+	 * Resets all the output frequencies
+	 */
+	void resetFrequencies();
+
+	/**
+	 * Sets the frequency for an operator
+	 */
+	void setFrequency(byte operatorNum, uint frequency);
+
+	/**
+	 * Calculates the frequency for a note
+	 */
+	uint calcFrequency(byte note);
+
+	/**
+	 * Sets the output level for a channel
+	 */
+	void setOutputLevel(byte channelNum, uint level);
+
+	/**
+	 * Starts playing an instrument
+	 */
+	void playInstrument(byte channelNum, const byte *data, byte volume);
+protected:
+	virtual bool musSetInstrument(const byte *&srcP, byte param);
+	virtual bool musSetPitchWheel(const byte *&srcP, byte param);
+	virtual bool musSetPanning(const byte *&srcP, byte param);
+	virtual bool musFade(const byte *&srcP, byte param);
+	virtual bool musStartNote(const byte *&srcP, byte param);
+	virtual bool musSetVolume(const byte *&srcP, byte param);
+	virtual bool musInjectMidi(const byte *&srcP, byte param);
+	virtual bool musPlayInstrument(const byte *&srcP, byte param);
+
+	virtual bool fxSetInstrument(const byte *&srcP, byte param);
+	virtual bool fxSetVolume(const byte *&srcP, byte param);
+	virtual bool fxMidiReset(const byte *&srcP, byte param);
+	virtual bool fxMidiDword(const byte *&srcP, byte param);
+	virtual bool fxSetPanning(const byte *&srcP, byte param);
+	virtual bool fxChannelOff(const byte *&srcP, byte param);
+	virtual bool fxFade(const byte *&srcP, byte param);
+	virtual bool fxStartNote(const byte *&srcP, byte param);
+	virtual bool fxInjectMidi(const byte *&srcP, byte param);
+	virtual bool fxPlayInstrument(const byte *&srcP, byte param);
+
+	/**
+	 * Post-processing done when a pause countdown starts or is in progress
+	 */
+	virtual void pausePostProcess();
+
+	/**
+	 * Does a reset of any sound effect
+	 */
+	virtual void resetFX();
+public:
+	/**
+	 * Constructor
+	 */
+	SoundDriverAdlib();
+
+	/**
+	 * Destructor
+	 */
+	virtual ~SoundDriverAdlib();
+
+	/**
+	 * Starts an special effect playing
+	 */
+	virtual void playFX(uint effectId, const byte *data);
+
+	/**
+	 * Plays a song
+	 */
+	virtual void playSong(const byte *data);
+
+	/**
+	 * Executes special music command
+	 */
+	virtual int songCommand(uint commandId, byte musicVolume = 0, byte sfxVolume = 0);
+};
+
+} // End of namespace Xeen
+
+#endif /* XEEN_SOUND_DRIVER_H */





More information about the Scummvm-git-logs mailing list