[Scummvm-git-logs] scummvm master -> 80f163b0fc7fc033aa99b829f626784804bf5176

athrxx athrxx at scummvm.org
Fri Jun 21 14:20:37 CEST 2019


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:
80f163b0fc ALL: revert accidental commits


Commit: 80f163b0fc7fc033aa99b829f626784804bf5176
    https://github.com/scummvm/scummvm/commit/80f163b0fc7fc033aa99b829f626784804bf5176
Author: athrxx (athrxx at scummvm.org)
Date: 2019-06-21T14:19:42+02:00

Commit Message:
ALL: revert accidental commits

Changed paths:
    engines/cine/script_fw.cpp
    engines/kyra/sound/drivers/audiomaster2.cpp
    engines/sci/engine/kscripts.cpp
    engines/sci/engine/script_patches.cpp
    engines/sci/sound/drivers/cms.cpp
    engines/sci/sound/drivers/pc9801.cpp
    engines/sci/sound/music.cpp


diff --git a/engines/cine/script_fw.cpp b/engines/cine/script_fw.cpp
index 9692c54..86eb709 100644
--- a/engines/cine/script_fw.cpp
+++ b/engines/cine/script_fw.cpp
@@ -707,29 +707,7 @@ int FWScript::execute() {
 
 	if (_script._size) {
 		while (!ret) {
-
-			if (g_cine->getGameType() == Cine::GType_OS) {
-				if (_pos == 0x0f9a) {
-					if (!scumm_stricmp(currentPrcName, "AUTO00.PRC"))
-						g_cine->_globalVars[200] = g_cine->_objectTable[235].costume;
-				}
-			} else {
-				if (_pos == 0x2c) {
-					if (g_cine->_objectTable[1].x == 0x0131) {
-						if (!scumm_stricmp(currentPrcName, "TOTO.PRC"))
-							g_cine->_objectTable[2].x = 0x02;
-					}
-				} /*else if (!scumm_stricmp(currentPrcName, "CODE2.PRC")) {
-					if (_pos == 1) {
-						//globalVars[0] = objectTable[scriptElement->scriptPtr[6]].frame;
-					} else if (_pos == 504) {
-						//_currentScriptElement->localVars[1] = _currentScriptElement->localVars[2] = 0;
-						//globalVars[251] = 0;
-						g_cine->_globalVars[251] = g_cine->_globalVars[251];
-					}
-				}*/
-			} 
-
+			_line = _pos;
 			byte opcode = getNextByte();
 			OpFunc handler = _info->opcodeHandler(opcode);
 
diff --git a/engines/kyra/sound/drivers/audiomaster2.cpp b/engines/kyra/sound/drivers/audiomaster2.cpp
index c22f873..d50d519 100644
--- a/engines/kyra/sound/drivers/audiomaster2.cpp
+++ b/engines/kyra/sound/drivers/audiomaster2.cpp
@@ -892,8 +892,6 @@ void AudioMaster2ResourceManager::initResource(SoundResource *resource) {
 	if (!resource)
 		return;
 
-	Common::StackLock lock(_mutex);
-
 	SoundResource *res = retrieveFromChain(resource->getName());
 	// The driver does not replace resources with the same name, but disposes the new resource instead.
 	// So these names seem to be considered "globally unique".
@@ -1286,7 +1284,7 @@ void AudioMaster2Internal::fadeOut(int delay) {
 }
 
 bool AudioMaster2Internal::isFading() {
-	return _ready ? _io->isFading() : false;
+	return _io->isFading();
 }
 
 void AudioMaster2Internal::setMusicVolume(int volume) {
@@ -1315,18 +1313,18 @@ void AudioMaster2Internal::resetCounter() {
 }
 
 int AudioMaster2Internal::getPlayDuration() {
-	return _ready ? _durationCounter : 0;
+	return _durationCounter;
 }
 
 void AudioMaster2Internal::sync(SoundResource *res) {
 	if (!_ready || !res)
 		return;
 
-	Common::StackLock lock(_mutex);
-
 	if (res->getType() != 1)
 		return;
 
+	Common::StackLock lock(_mutex);
+
 	SoundResourceSMUS *smus = static_cast<SoundResourceSMUS*>(res);
 	_io->_tempo = smus->getTempo();
 	smus->setSync(_io->_sync);
diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp
index 5bdbb4f..61b0f16 100644
--- a/engines/sci/engine/kscripts.cpp
+++ b/engines/sci/engine/kscripts.cpp
@@ -257,10 +257,6 @@ reg_t kDisposeClone(EngineState *s, int argc, reg_t *argv) {
 // Returns script dispatch address index in the supplied script
 reg_t kScriptID(EngineState *s, int argc, reg_t *argv) {
 	int script = argv[0].toUint16();
-
-	if (Sci::g_sci->getGameId() == GID_KQ4 && script == 701)
-		script--;
-
 	uint16 index = (argc > 1) ? argv[1].toUint16() : 0;
 
 	if (argv[0].getSegment())
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index f1bbb3e..af7003f 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -5255,24 +5255,6 @@ static const uint16 laurabow1PatchLeftStairsLockupFix[] = {
 	PATCH_END
 };
 
-//	Copy Protection
-static const uint16 laurabow1SignatureCp[] = {
-	SIG_MAGICDWORD,
-	0x30, 0x48, 0x00, 0x8f, 0x01, 0x8d, 0x00, 0x35, 0x04, 0x06,
-	0x93, 0x05, 0x1e, 0x30, 0x36, 0x00, 0x8f, 0x02, 0x8d, 0x00,
-	SIG_END
-};
-
-static const uint16 laurabow1PatchCp[] = {
-	0x39, 0x00,	0xab, 0x00,	0x39, 0x00,	0xab, 0x01,	0x39, 0x00,
-	0xab, 0x35,	0x39, 0x27,	0xaf, 0x01,	0x39, 0x27,	0xaf, 0x02,
-	PATCH_GETORIGINALBYTE(0), PATCH_GETORIGINALBYTE(1), PATCH_GETORIGINALBYTE(2),
-	PATCH_GETORIGINALBYTE(3), PATCH_GETORIGINALBYTE(4), PATCH_GETORIGINALBYTE(5),
-	PATCH_GETORIGINALBYTE(6), PATCH_GETORIGINALBYTE(7), PATCH_GETORIGINALBYTE(8),
-	PATCH_GETORIGINALBYTE(9), PATCH_GETORIGINALBYTE(10),
-	PATCH_END
-};
-
 //          script, description,                                signature                                             patch
 static const SciScriptPatcherEntry laurabow1Signatures[] = {
 	{  true,     4, "easter egg view fix",                      1, laurabow1SignatureEasterEggViewFix,                laurabow1PatchEasterEggViewFix },
@@ -5285,7 +5267,6 @@ static const SciScriptPatcherEntry laurabow1Signatures[] = {
 	{  true,    58, "chapel candles persistence",               1, laurabow1SignatureChapelCandlesPersistence,        laurabow1PatchChapelCandlesPersistence },
 	{  true,   236, "tell Lilly about Gertie blocking fix 1/2", 1, laurabow1SignatureTellLillyAboutGerieBlockingFix1, laurabow1PatchTellLillyAboutGertieBlockingFix1 },
 	{  true,   236, "tell Lilly about Gertie blocking fix 2/2", 1, laurabow1SignatureTellLillyAboutGerieBlockingFix2, laurabow1PatchTellLillyAboutGertieBlockingFix2 },
-	{  true,   414, "copy protection",							1, laurabow1SignatureCp,							  laurabow1PatchCp },
 	{  true,   998, "obstacle collision lockups fix",           1, laurabow1SignatureObstacleCollisionLockupsFix,     laurabow1PatchObstacleCollisionLockupsFix },
 	SCI_SIGNATUREENTRY_TERMINATOR
 };
@@ -14024,44 +14005,6 @@ static const SciScriptPatcherEntry torinSignatures[] = {
 
 #endif
 
-
-//	Copy Protection
-static const uint16 pq2EnSignatureCp[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x07, 0x12, 0xa5,
-	SIG_ADDTOOFFSET(67),
-	0x30, 0xcf, 0x00, 0x35,
-	SIG_END
-};
-
-static const uint16 pq2EnPatchCp[] = {
-	0x35, 0x00, 0x12, 0xa5,
-	PATCH_ADDTOOFFSET(67),
-	0x30, 0x00, 0x00, 0x35,
-	PATCH_END
-};
-
-static const uint16 pq2JpSignatureCp[] = {
-	SIG_MAGICDWORD,
-	0x35, 0x07, 0x12, 0xa5,
-	SIG_ADDTOOFFSET(75),
-	0x30, 0xcf, 0x00, 0x35,
-	SIG_END
-};
-
-static const uint16 pq2JpPatchCp[] = {
-	0x35, 0x00, 0x12, 0xa5,
-	PATCH_ADDTOOFFSET(75),
-	0x30, 0x00, 0x00, 0x35,
-	PATCH_END
-};
-
-static const SciScriptPatcherEntry pq2Signatures[] = {
-	{  true, 701, "copy protection", 1, pq2EnSignatureCp, pq2EnPatchCp },
-	{  true, 701, "copy protection", 1, pq2JpSignatureCp, pq2JpPatchCp },
-	SCI_SIGNATUREENTRY_TERMINATOR
-};
-
 // =================================================================================
 
 ScriptPatcher::ScriptPatcher() {
@@ -14593,9 +14536,6 @@ void ScriptPatcher::processScript(uint16 scriptNr, SciSpan<byte> scriptData) {
 	case GID_PQ1:
 		signatureTable = pq1vgaSignatures;
 		break;
-	case GID_PQ2:
-		signatureTable = pq2Signatures;
-		break;
 	case GID_PQ3:
 		signatureTable = pq3Signatures;
 		break;
diff --git a/engines/sci/sound/drivers/cms.cpp b/engines/sci/sound/drivers/cms.cpp
index 8652995..8b92432 100644
--- a/engines/sci/sound/drivers/cms.cpp
+++ b/engines/sci/sound/drivers/cms.cpp
@@ -33,157 +33,14 @@
 
 namespace Sci {
 
-class MidiDriver_CMS;
-
-class CMSVoice {
-public:
-	CMSVoice(uint8 id, MidiDriver_CMS *driver, CMSEmulator *cms, SciSpan<const uint8>& patchData);
-	virtual ~CMSVoice();
-
-	virtual void noteOn(int note, int velocity) = 0;
-	virtual void noteOff() = 0;
-	virtual void stop() = 0;
-	virtual void programChange(int program) = 0;
-	virtual void pitchWheel() {}
-
-	virtual void update() = 0;
-
-	virtual void reset() {}
-	virtual void setPanMask(uint8) {}
-
-	uint8 _assign;
-	uint8 _note;
-	bool _sustained;
-	uint16 _duration;
-	uint16 _releaseDuration;
-	CMSVoice *_secondaryVoice;
-
-protected:
-	void sendFrequency();
-	void cmsWrite(uint8 reg, uint8 val);
-
-	CMSEmulator *_cms;
-	MidiDriver_CMS *_driver;
-	SciSpan<const uint8> _patchData;
-
-	const uint8 _id;
-	const uint8 _regOffset;
-	const uint8 _portOffset;
-
-	static uint8 _octaveRegs[6];
-	static const int _frequencyTable[48];
-
-private:
-	virtual void recalculateFrequency(uint8 &freq, uint8 &octave) = 0;
-};
-
-class CMSVoice_V0 : public CMSVoice {
-public:
-	CMSVoice_V0(uint8 id, MidiDriver_CMS *driver, CMSEmulator *cms, SciSpan<const uint8>& patchData);
-	virtual ~CMSVoice_V0();
-
-	void noteOn(int note, int);
-	void noteOff();
-	void stop();
-	void programChange(int program);
-
-	void update();
-
-	void reset();
-	void setPanMask(uint8 mask);
-
-private:
-	void recalculateFrequency(uint8 &frequency, uint8 &octave);
-	void recalculateEvelopeLevels();
-	void selectEnvelope(int id);
-
-	enum EnvelopeState {
-		kReady		= 0,
-		kRestart	= 1,
-		kAttack		= 2,
-		kDecay		= 3,
-		kSustain	= 4,
-		kRelease	= 5		
-	};
-	
-	EnvelopeState _envState;
-	uint8 _envAR;
-	uint8 _envTL;
-	uint8 _envDR;
-	uint8 _envSL;
-	uint8 _envRR;	
-	uint8 _envSLI;
-	uint8 _envPAC;
-	uint8 _envPA;
-
-	static uint8 _envAR1;
-
-	uint8 _envNote;
-	uint8 _envSSL;
-	uint8 _panMask;
-	uint8 _strMask;
-
-	int8 _transFreq;
-	int8 _transOct;
-
-	bool _vbrOn;
-	uint8 _vbrSteps;
-	uint8 _vbrState;
-	int8 _vbrMod;
-	int8 _vbrCur;
-	int16 _vbrPhase;
-
-	int _currentLevel;
-	bool _updateCMS;
-
-	const bool _isSecondary;
-
-	static const uint8 _envelopeDataTable[256];
-	static const uint8 _volumeTable[176];
-	static const uint8 _pitchWheelTable[65];
-};
-
-class CMSVoice_V1 : public CMSVoice {
-public:
-	CMSVoice_V1(uint8 id, MidiDriver_CMS *driver, CMSEmulator *cms, SciSpan<const uint8>& patchData);
-	virtual ~CMSVoice_V1();
-
-	void noteOn(int note, int velocity);
-	void noteOff();
-	void stop();
-	void programChange(int program);
-	void pitchWheel();
-
-	void update();
-
-private:
-	void recalculateFrequency(uint8 &frequency, uint8 &octave);
-
-	void updateVoiceAmplitude();
-	void setupVoiceAmplitude();
-
-	SciSpan<const uint8> _patchDataCur;
-	uint8 _velocity;
-	uint8 _patchDataIndex;
-	uint8 _amplitudeTimer;
-	uint8 _amplitudeModifier;
-	bool _release;
-
-	static const int _velocityTable[32];
-};
+// FIXME: We don't seem to be sending the polyphony init data, so disable this for now
+#define CMS_DISABLE_VOICE_MAPPING
 
 class MidiDriver_CMS : public MidiDriver_Emulated {
 public:
-	enum {
-		MIDI_PROP_CHANNEL_VOLUME = 1,
-		MIDI_PROP_CHANNEL_PITCHWHEEL = 2,
-		MIDI_PROP_CHANNEL_PANPOS = 3,
-		MIDI_PROP_PLAYSWITCH = 4
-	};
-
-public:
-	MidiDriver_CMS(Audio::Mixer *mixer, ResourceManager *resMan, SciVersion version);
-	~MidiDriver_CMS();
+	MidiDriver_CMS(Audio::Mixer *mixer, ResourceManager *resMan)
+	    : MidiDriver_Emulated(mixer), _resMan(resMan), _cms(0), _rate(0), _playSwitch(true), _masterVolume(0) {
+	}
 
 	int open();
 	void close();
@@ -191,102 +48,105 @@ public:
 	void send(uint32 b);
 	uint32 property(int prop, uint32 param);
 
-	void initTrack(SciSpan<const byte>& header);
-
-	void onTimer();
-
 	MidiChannel *allocateChannel() { return 0; }
 	MidiChannel *getPercussionChannel() { return 0; }
 
 	bool isStereo() const { return true; }
 	int getRate() const { return _rate; }
 
+	void playSwitch(bool play);
 private:
-	void noteOn(int channelNr, int note, int velocity);
-	void noteOff(int channelNr, int note);
-	void controlChange(int channelNr, int control, int value);
-	void programChange(int channelNr, int value);
-	void pitchWheel(int channelNr, int value);
-
-	void voiceMapping(int channelNr, int value);
-	void bindVoices(int channelNr, int voices, bool bindSecondary, bool doProgramChange);
-	void unbindVoices(int channelNr, int voices, bool bindSecondary);
-	void donateVoices(bool bindSecondary);
-	int findVoice(int channelNr, int note);
-	int findVoiceBasic(int channelNr);
-
-	void writeToChip(int chip, int address, int data);
 	void generateSamples(int16 *buffer, int len);
 
+	ResourceManager *_resMan;
+	CMSEmulator *_cms;
+
+	void writeToChip1(int address, int data);
+	void writeToChip2(int address, int data);
+
+	int32 _samplesPerCallback;
+	int32 _samplesPerCallbackRemainder;
+	int32 _samplesTillCallback;
+	int32 _samplesTillCallbackRemainder;
+
+	int _rate;
+	bool _playSwitch;
+	uint16 _masterVolume;
+
+	Common::SpanOwner<SciSpan<uint8> > _patchData;
+
 	struct Channel {
-		Channel() : program(0), volume(0), pan(0x40), hold(0), missingVoices(0), lastVoiceUsed(0), pitchWheel(0x2000), isValid(true) {}
-		uint8 program;
+		Channel()
+		    : patch(0), volume(0), pan(0x40), hold(0), extraVoices(0),
+		      pitchWheel(0x2000), pitchModifier(0), pitchAdditive(false),
+		      lastVoiceUsed(0) {
+		}
+
+		uint8 patch;
 		uint8 volume;
 		uint8 pan;
 		uint8 hold;
-		uint8 missingVoices;
-		uint8 lastVoiceUsed;
+		uint8 extraVoices;
 		uint16 pitchWheel;
-		bool isValid;
+		uint8 pitchModifier;
+		bool pitchAdditive;
+		uint8 lastVoiceUsed;
 	};
 
 	Channel _channel[16];
-	CMSVoice *_voice[12];
-
-	const int _numVoicesPrimary;
-	const int _numVoicesSecondary;
-
-	CMSEmulator *_cms;
-	ResourceManager *_resMan;
-	Common::SpanOwner<SciSpan<const uint8> > _patchData;
 
-	bool _playSwitch;
-	uint16 _masterVolume;
-
-	const int _actualTimerInterval;
-	const int _reqTimerInterval;
-	int _updateTimer;
-	int _rate;
+	struct Voice {
+		Voice() : channel(0xFF), note(0xFF), sustained(0xFF), ticks(0),
+		    turnOffTicks(0), patchDataPtr(), patchDataIndex(0),
+		    amplitudeTimer(0), amplitudeModifier(0), turnOff(false),
+		    velocity(0) {
+		}
 
-	SciVersion _version;
-};
+		uint8 channel;
+		uint8 note;
+		uint8 sustained;
+		uint16 ticks;
+		uint16 turnOffTicks;
+		SciSpan<uint8> patchDataPtr;
+		uint8 patchDataIndex;
+		uint8 amplitudeTimer;
+		uint8 amplitudeModifier;
+		bool turnOff;
+		uint8 velocity;
+	};
 
-CMSVoice::CMSVoice(uint8 id, MidiDriver_CMS* driver, CMSEmulator *cms, SciSpan<const uint8>& patchData) : _id(id), _regOffset(id > 5 ? id - 6 : id), _portOffset(id > 5 ? 2 : 0),
-	_driver(driver), _cms(cms), _assign(0xFF), _note(0xFF), _sustained(false), _duration(0), _releaseDuration(0), _secondaryVoice(0), _patchData(patchData) {
-	assert(_id < 12);
-	_octaveRegs[_id >> 1] = 0;
-}
+	Voice _voice[12];
 
-CMSVoice::~CMSVoice() {
+	void voiceOn(int voice, int note, int velocity);
+	void voiceOff(int voice);
 
-}
+	void noteSend(int voice);
 
-void CMSVoice::sendFrequency() {
-	uint8 frequency = 0;
-	uint8 octave = 0;
+	void noteOn(int channel, int note, int velocity);
+	void noteOff(int channel, int note);
+	void controlChange(int channel, int control, int value);
+	void pitchWheel(int channel, int value);
 
-	recalculateFrequency(frequency, octave);	
+	void voiceMapping(int channel, int value);
+	void bindVoices(int channel, int voices);
+	void unbindVoices(int channel, int voices);
+	void donateVoices();
+	int findVoice(int channel);
 
-	uint8 octaveData = _octaveRegs[_id >> 1];
-	octaveData = (_id & 1) ? (octaveData & 0x0F) | (octave << 4) : (octaveData & 0xF0) | octave;
+	int findVoiceBasic(int channel);
 
-	cmsWrite(8 + _regOffset, frequency);
-	cmsWrite(0x10 + (_regOffset >> 1), octaveData);
-}
+	void updateVoiceAmplitude(int voice);
+	void setupVoiceAmplitude(int voice);
 
-void CMSVoice::cmsWrite(uint8 reg, uint8 val) {
-	_cms->portWrite(0x221 + _portOffset, reg);
-	_cms->portWrite(0x220 + _portOffset, val);
+	uint8 _octaveRegs[2][3];
 
-	if (reg >= 16 && reg <= 18)
-		_octaveRegs[_id >> 1] = val;
-}
+	static const int _timerFreq = 60;
 
-uint8 CMSVoice::_octaveRegs[6] = {
-	0, 0, 0, 0, 0, 0
+	static const int _frequencyTable[];
+	static const int _velocityTable[];
 };
 
-const int CMSVoice::_frequencyTable[48] = {
+const int MidiDriver_CMS::_frequencyTable[] = {
 	  3,  10,  17,  24,
 	 31,  38,  46,  51,
 	 58,  64,  71,  77,
@@ -301,495 +161,13 @@ const int CMSVoice::_frequencyTable[48] = {
 	242, 246, 250, 253
 };
 
-CMSVoice_V0::CMSVoice_V0(uint8 id, MidiDriver_CMS* driver, CMSEmulator *cms, SciSpan<const uint8>& patchData) : CMSVoice(id, driver, cms, patchData), _envState(kReady), _currentLevel(0), _strMask(0),
-	_envAR(0), _envTL(0), _envDR(0), _envSL(0), _envRR(0), _envSLI(0), _vbrOn(false), _vbrSteps(0), _vbrState(0), _vbrMod(0), _vbrCur(0), _isSecondary(id > 7),
-	_vbrPhase(0), _transOct(0), _transFreq(0), _envPAC(0), _envPA(0), _panMask(_id & 1 ? 0xF0 : 0x0F), _envSSL(0), _envNote(0xFF), _updateCMS(false) {
-}
-
-CMSVoice_V0::~CMSVoice_V0() {
-}
-
-void CMSVoice_V0::noteOn(int note, int) {
-	if (!_driver->property(MidiDriver_CMS::MIDI_PROP_PLAYSWITCH, 0xFFFF) || !_envTL)
-		return;
-
-	_note = note;
-	_envNote = note + 3;
-	_envState = kRestart;
-	_vbrPhase = 0;
-	_vbrCur = _vbrMod;
-	_vbrState = _vbrSteps & 0x0F;
-	_envPAC = _envPA;
-
-	//debug("NOTEON: Voice: %02d, Note: %02d, AR: 0x%02x, TL: 0x%02x, DR: 0x%02x, SLI: 0x%02x, RR: 0x%02x, VBR: 0x%02x", _id, note, _envAR, _envTL, _envDR, _envSLI, _envRR, _vbrMod);
-
-	if (_secondaryVoice)
-		_secondaryVoice->noteOn(note, 127);
-}
-
-void CMSVoice_V0::noteOff() {
-	if (!_driver->property(MidiDriver_CMS::MIDI_PROP_PLAYSWITCH, 0xFFFF) || !_envTL)
-		return;
-
-	//debug("NOTEOFF: Voice: %02d", _id);
-
-	_note = 0xFF;
-	_envState = kRelease;
-	if (_secondaryVoice)
-		_secondaryVoice->noteOff();
-}
-
-void CMSVoice_V0::stop() {
-	_note = 0xFF;
-	if (_envState != kReady)
-		_envState = kRelease;
-	if (_secondaryVoice)
-		_secondaryVoice->stop();
-}
-
-void CMSVoice_V0::programChange(int program) {
-	assert(program < 128);
-	if (program == 127) {
-		// This seems to replace the start of track offset with the current position so that 0xFC (kEndOfTrack)
-		// midi events would not reset the track to the start, but to the current position instead. This cannot
-		// be handled here. All versions of the SCI0 driver that I have seen so far do this. Still, I somehow
-		// doubt that it will ever come up, but let's see...
-		warning("CMSVoice_V0::programChange(): Unhandled program change 127");
-		return;
-	}
-
-	SciSpan<const uint8> data = _patchData.subspan(128 + (_patchData.getUint8At(program) << 3));
-	uint8 pos = _isSecondary ? 3 : 0;
-
-	selectEnvelope(data.getUint8At(pos++));
-
-	if (_isSecondary) {
-		_envSSL = data.getUint8At(pos++);
-		// This decides whether the secondary voice has the same or the opposite pan position as the primary voice.
-		_panMask = _strMask ^ -(_envSSL & 1);
-	}
-
-	_transOct = data.getInt8At(pos++);
-	_transFreq = data.getInt8At(pos++);
-
-	debug("CMSVoice_V0::programChange: Voice: %02d, Envelope: %02d, TransOct: %02d, TransFreq: %02d", _id, data[_isSecondary ? 3 : 0], _transOct, _transFreq);
-
-	if (_isSecondary)
-		_envPA = data.getUint8At(pos++);
-
-	if (_secondaryVoice) {
-		assert(!_isSecondary);
-		if (data.getUint8At(pos) == 0xFF) {
-			_secondaryVoice->stop();
-			_secondaryVoice->_assign = 0xFF;
-			_secondaryVoice = 0;
-		} else {
-			_secondaryVoice->setPanMask(_panMask);
-			_secondaryVoice->programChange(program);
-		}
-	}
-}
-
-void CMSVoice_V0::update() {
-	if (_updateCMS) {
-		sendFrequency();
-		cmsWrite(_regOffset, ((_currentLevel & 0xF0) | (_currentLevel >> 4)) & _panMask);
-		_updateCMS = false;
-	}
-
-	recalculateEvelopeLevels();
-
-	switch (_envState) {
-	case kReady:
-		_envNote = 0xFF;
-		return;
-
-	case kRestart:
-		if (_envPAC) {
-			--_envPAC;
-			break;
-		} else {
-			//if ((_currentLevel >> 1) > _envAR)
-			_currentLevel = ((_currentLevel >> 1) > (int8)_envAR) ? ((_currentLevel >> 1) - _envAR1) & 0xFF : (_envAR - _envAR1) & 0xFF;
-			//_currentLevel = (uint8)MIN<int8>(0, (_currentLevel >> 1) - _envAR);
-			_envState = kAttack;
-		}
-		// fall through
-
-	case kAttack:
-		_currentLevel = _currentLevel + _envAR;
-		if (_currentLevel > _envTL || _currentLevel > 0xFF) {
-			_currentLevel = _envTL;
-			_envState = kDecay;
-		}
-		break;
-
-	case kDecay:
-		_currentLevel -= _envDR;
-		if (_currentLevel <= _envSL) {
-			if (_currentLevel < 0)
-				_currentLevel = 0;
-			_envState = kSustain;
-		}
-		break;
-
-	case kSustain:
-		_currentLevel = _envSL;
-		break;
-
-	case kRelease:
-		_currentLevel -= _envRR;
-		if (_currentLevel < 0) {
-			_currentLevel = 0;
-			_envState = kReady;
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	if (_vbrOn && _envState != kRestart) {
-		_vbrPhase += _vbrCur;
-		if (!--_vbrState) {
-			_vbrCur = -_vbrCur;
-			_vbrState = (_vbrSteps & 0x0F) << 1;
-		}
-	}
-
-	_updateCMS = true;
-	++_duration;
-}
-
-void CMSVoice_V0::reset() {
-	_envState = kReady;
-	_secondaryVoice = 0;
-	_assign = _note = _envNote = 0xFF;
-	_panMask = _id & 1 ? 0xF0 : 0x0F;
-	_envTL = 0;
-	_currentLevel = 0;
-	_duration = 0;
-	_envPA = 0;
-	_transFreq = _transOct = 0;
-	selectEnvelope(3);
-}
-
-void CMSVoice_V0::setPanMask(uint8 mask) {
-	_strMask = mask;
-}
-
-void CMSVoice_V0::recalculateFrequency(uint8 &freq, uint8 &octave) {
-	if (_assign == 0xFF || _envNote == 0xFF)
-		return;
-
-	uint8 note = _envNote % 12;
-	octave = CLIP<int>(_envNote / 12 - 2, 0, 7);
-
-	int16 pw = (_driver->property(MidiDriver_CMS::MIDI_PROP_CHANNEL_PITCHWHEEL, _assign) & 0x7FFF) - 0x2000;
-	int16 sg = (pw < 0) ? -1 : 0;
-	pw = (pw ^ sg) - sg;
-	pw = ((pw >> 7) & 1) + (pw >> 8);
-	assert(pw < ARRAYSIZE(_pitchWheelTable));
-	pw = (_pitchWheelTable[pw] ^ sg) - sg;
-
-	int frequency = note * 4 + pw;
-
-	if (frequency < 0) {
-		if (octave) {
-			frequency += 48;
-			--octave;
-		} else {
-			frequency = 0;
-		}
-	} else if (frequency >= 48) {
-		if (octave < 7) {
-			frequency -= 48;
-			++octave;
-		} else {
-			frequency = 47;
-		}
-	}
-	
-	octave = CLIP<int8>(octave + _transOct, 0, 7);
-	frequency = _frequencyTable[frequency & 0xFF] + _transFreq + _vbrPhase;
-
-	if (frequency > 255) {
-		frequency &= 0xFF;
-		octave++;
-	} else if (frequency < 0) {
-		frequency &= 0xFF;
-		octave--;
-	}
-
-	octave = CLIP<int8>(octave, 0, 7);
-	freq = frequency;
-}
-
-void CMSVoice_V0::recalculateEvelopeLevels() {
-	uint8 chanVol = _driver->property(MidiDriver_CMS::MIDI_PROP_CHANNEL_VOLUME, _assign);
-
-	if (_envTL && _isSecondary) {
-		int volIndexTLS = (chanVol >> 4) | (_envSSL & 0xF0);
-		assert(volIndexTLS < ARRAYSIZE(_volumeTable));
-		_envTL = _volumeTable[volIndexTLS];
-	} else if (_envTL) {
-		_envTL = chanVol;
-	}
-	
-	int volIndexSL = (_envSLI << 4) + (_envTL >> 4);
-	assert(volIndexSL < ARRAYSIZE(_volumeTable));
-	_envSL = _volumeTable[volIndexSL];
-}
-
-uint8 CMSVoice_V0::_envAR1 = 0;
-
-void CMSVoice_V0::selectEnvelope(int id) {
-	const uint8 *in = &_envelopeDataTable[(id & 0x1F) << 3];
-	_envAR = *in++;
-	_envTL = *in++;
-	_envDR = *in++;
-	_envSLI = *in++;
-	_envRR = *in++;
-	/*unused*/in++;
-	_vbrMod = *in++;
-	_vbrSteps = *in++;
-	_vbrOn = _vbrMod;
-	_vbrCur = _vbrMod;
-	_vbrState = _vbrSteps & 0x0F;
-	_vbrPhase = 0;
-	if (_id == 1)
-		_envAR1 = _envAR;
-}
-
-const uint8 CMSVoice_V0::_envelopeDataTable[256] = {
-	0xff, 0xff, 0x02, 0x05, 0x08, 0x00, 0x01, 0x02,
-	0xff, 0xff, 0x40, 0x02, 0x01, 0x00, 0x00, 0x00,
-	0xff, 0xff, 0x08, 0x02, 0x02, 0x00, 0x00, 0x00,
-	0xff, 0xff, 0x10, 0x02, 0x02, 0x00, 0x00, 0x00,
-	0xff, 0xff, 0x18, 0x02, 0x01, 0x00, 0x00, 0x00,
-	0x20, 0xff, 0x01, 0x06, 0x08, 0x00, 0x00, 0x00,
-	0x20, 0xff, 0x08, 0x02, 0x03, 0x00, 0x00, 0x00,
-	0x20, 0xe0, 0x02, 0x05, 0x02, 0x00, 0x00, 0x00,
-	0x10, 0xe0, 0x10, 0x03, 0x02, 0x00, 0x00, 0x00,
-	0x20, 0xe0, 0x08, 0x03, 0x03, 0x00, 0x00, 0x00,
-	0xff, 0xff, 0x04, 0x06, 0x08, 0x00, 0x01, 0x02,
-	0xff, 0xff, 0x04, 0x02, 0x04, 0x00, 0x01, 0x02,
-	0xff, 0xff, 0x08, 0x02, 0x04, 0x00, 0x01, 0x02,
-	0xff, 0xff, 0x10, 0x02, 0x04, 0x00, 0x01, 0x02,
-	0xa0, 0xff, 0x0c, 0x03, 0x08, 0x00, 0x03, 0x01,
-	0x20, 0xff, 0x01, 0x06, 0x0c, 0x00, 0x01, 0x02,
-	0x20, 0xff, 0x08, 0x02, 0x04, 0x00, 0x01, 0x02,
-	0x20, 0xd0, 0x02, 0x05, 0x02, 0x00, 0x01, 0x02,
-	0x10, 0xff, 0x20, 0x05, 0x04, 0x00, 0x02, 0x02,
-	0x08, 0xc0, 0x10, 0x04, 0x04, 0x00, 0x02, 0x02,
-	0xc8, 0xff, 0x02, 0x05, 0x10, 0x00, 0x01, 0x02,
-	0xff, 0xff, 0x04, 0x04, 0x10, 0x00, 0x01, 0x02,
-	0xff, 0xff, 0x08, 0x03, 0x08, 0x00, 0x01, 0x02,
-	0xff, 0xff, 0x0c, 0x02, 0x08, 0x00, 0x01, 0x02,
-	0x19, 0xc4, 0x04, 0x04, 0x08, 0x00, 0x02, 0x02,
-	0x10, 0xff, 0x01, 0x06, 0x08, 0x00, 0x04, 0x02,
-	0x0a, 0xff, 0x01, 0x06, 0x08, 0x00, 0x05, 0x01,
-	0x10, 0xff, 0x0a, 0x01, 0x02, 0x00, 0x05, 0x02,
-	0xff, 0xff, 0x0a, 0x02, 0x08, 0x00, 0x05, 0x01,
-	0xff, 0xff, 0x03, 0x03, 0x08, 0x00, 0x02, 0x01,
-	0xff, 0xff, 0x08, 0x01, 0x04, 0x00, 0x0c, 0x02,
-	0xff, 0xff, 0x10, 0x02, 0x04, 0x00, 0x0f, 0x0a
-};
-
-const uint8 CMSVoice_V0::_volumeTable[176] = {
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,	0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10,	0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30,
-	0x00, 0x00, 0x00, 0x00, 0x10, 0x10, 0x10, 0x20,	0x20, 0x20, 0x30, 0x30, 0x30, 0x30, 0x40, 0x40,
-	0x00, 0x00, 0x00, 0x10, 0x10, 0x20, 0x20, 0x20,	0x30, 0x30, 0x40, 0x40, 0x40, 0x50, 0x50, 0x60,
-	0x00, 0x00, 0x10, 0x10, 0x20, 0x20, 0x30, 0x30,	0x40, 0x40, 0x50, 0x50, 0x60, 0x60, 0x70, 0x70,
-	0x00, 0x00, 0x10, 0x10, 0x20, 0x30, 0x30, 0x40,	0x40, 0x50, 0x60, 0x60, 0x70, 0x70, 0x80, 0x90,
-	0x00, 0x00, 0x10, 0x20, 0x20, 0x30, 0x40, 0x40,	0x50, 0x60, 0x70, 0x70, 0x80, 0x90, 0x90, 0xa0,
-	0x00, 0x00, 0x10, 0x20, 0x30, 0x40, 0x40, 0x50,	0x60, 0x70, 0x80, 0x80, 0x90, 0xa0, 0xb0, 0xc0,
-	0x00, 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60,	0x70, 0x80, 0x90, 0x90, 0xa0, 0xb0, 0xc0, 0xd0,
-	0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,	0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0
-};
-
-const uint8 CMSVoice_V0::_pitchWheelTable[65] = {
-	0x00, 0x01, 0x02, 0x02, 0x03, 0x04, 0x05, 0x05,
-	0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b, 0x0b,
-	0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x11, 0x11,
-	0x12, 0x13, 0x14, 0x14, 0x15, 0x16, 0x17, 0x17,
-	0x18, 0x19, 0x1a, 0x1a, 0x1b, 0x1c, 0x1d, 0x1d,
-	0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23, 0x23,
-	0x24, 0x25, 0x26, 0x26, 0x27, 0x28, 0x29, 0x29,
-	0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x2f,
-	0x30
-};
-
-CMSVoice_V1::CMSVoice_V1(uint8 id, MidiDriver_CMS* driver, CMSEmulator *cms, SciSpan<const uint8>& patchData) : CMSVoice(id, driver, cms, patchData), _velocity(0), _patchDataIndex(0),
-	_amplitudeTimer(0), _amplitudeModifier(0), _release(false) {
-}
-
-CMSVoice_V1::~CMSVoice_V1() {
-}
-
-void CMSVoice_V1::noteOn(int note, int velocity) {
-	_note = note;
-	_release = false;
-	_patchDataIndex = 0;
-	_amplitudeTimer = 0;
-	_duration = 0;
-	_releaseDuration = 0;
-	_velocity = velocity ? _velocityTable[velocity >> 3] : 0;
-	sendFrequency();
-}
-
-void CMSVoice_V1::noteOff() {
-	_release = true;
-}
-
-void CMSVoice_V1::stop() {
-	_velocity = 0;
-	_note = 0xFF;
-	_sustained = false;
-	_release = false;
-	_patchDataIndex = 0;
-	_amplitudeTimer = 0;
-	_amplitudeModifier = 0;
-	_duration = 0;
-	_releaseDuration = 0;
-
-	setupVoiceAmplitude();
-}
-
-void CMSVoice_V1::programChange(int program) {
-	_patchDataCur = _patchData.subspan(_patchData.getUint16LEAt(program << 1));
-}
-
-void CMSVoice_V1::pitchWheel() {
-	sendFrequency();
-}
-
-void CMSVoice_V1::update() {
-	if (_note == 0xFF)
-		return;
-
-	if (_release)
-		++_releaseDuration;
-	++_duration;
-
-	updateVoiceAmplitude();
-	setupVoiceAmplitude();
-}
-
-void CMSVoice_V1::recalculateFrequency(uint8 &freq, uint8 &octave) {
-	assert(_assign != 0xFF);
-
-	int frequency = (CLIP<int>(_note, 21, 116) - 21) * 4;
-	int16 pw = _driver->property(MidiDriver_CMS::MIDI_PROP_CHANNEL_PITCHWHEEL, _assign);
-	int modifier = (pw < 0x2000) ? (0x2000 - pw) / 170 : ((pw > 0x2000) ? (pw - 0x2000) / 170 : 0);
-
-	if (modifier) {
-		if (pw < 0x2000) {
-			if (frequency > modifier)
-				frequency -= modifier;
-			else
-				frequency = 0;
-		} else {
-			int tempFrequency = 384 - frequency;
-			if (modifier < tempFrequency)
-				frequency += modifier;
-			else
-				frequency = 383;
-		}
-	}
-
-	octave = 0;
-	while (frequency >= 48) {
-		frequency -= 48;
-		++octave;
-	}
-
-	freq = _frequencyTable[frequency & 0xFF];
-}
-
-void CMSVoice_V1::updateVoiceAmplitude() {
-	if (_amplitudeTimer != 0 && _amplitudeTimer != 254) {
-		--_amplitudeTimer;
-		return;
-	} else if (_amplitudeTimer == 254) {
-		if (!_release)
-			return;
-		_amplitudeTimer = 0;
-	}
-
-	int nextDataIndex = _patchDataIndex;
-	uint8 timerData = 0;
-	uint8 amplitudeData = _patchDataCur[nextDataIndex];
-
-	if (amplitudeData == 255) {
-		timerData = amplitudeData = 0;
-		stop();
-	} else {
-		timerData = _patchDataCur[nextDataIndex + 1];
-		nextDataIndex += 2;
-	}
-
-	_patchDataIndex = nextDataIndex;
-	_amplitudeTimer = timerData;
-	_amplitudeModifier = amplitudeData;
-}
-
-void CMSVoice_V1::setupVoiceAmplitude() {
-	assert(_assign != 0xFF);
-	uint amplitude = 0;
-	uint8 chanVolume = _driver->property(MidiDriver_CMS::MIDI_PROP_CHANNEL_VOLUME, _assign);
-	uint8 masterVolume = _driver->property(MIDI_PROP_MASTER_VOLUME, 0xFFFF);
-
-	if (chanVolume && _velocity && _amplitudeModifier && masterVolume) {
-		amplitude = chanVolume * _velocity;
-		amplitude /= 0x0F;
-		amplitude *= _amplitudeModifier;
-		amplitude /= 0x0F;
-		amplitude *= masterVolume;
-		amplitude /= 0x0F;
-
-		if (!amplitude)
-			++amplitude;
-	}
-
-	uint8 amplitudeData = 0;
-	int pan = _driver->property(MidiDriver_CMS::MIDI_PROP_CHANNEL_PANPOS, _assign) >> 2;
-	if (pan >= 16) {
-		amplitudeData = (amplitude * (31 - pan) / 0x0F) & 0x0F;
-		amplitudeData |= (amplitude << 4);
-	} else {
-		amplitudeData = (amplitude * pan / 0x0F) & 0x0F;
-		amplitudeData <<= 4;
-		amplitudeData |= amplitude;
-	}
-
-	if (!_driver->property(MidiDriver_CMS::MIDI_PROP_PLAYSWITCH, 0xFFFF))
-		amplitudeData = 0;
-
-	cmsWrite(_regOffset, amplitudeData);
-}
-
-const int CMSVoice_V1::_velocityTable[32] = {
+const int MidiDriver_CMS::_velocityTable[] = {
 	 1,  3,  6,  8,  9, 10, 11, 12,
 	12, 13, 13, 14, 14, 14, 15, 15,
 	 0,  1,  2,  2,  3,  4,  4,  5,
 	 6,  6,  7,  8,  8,  9, 10, 10
 };
 
-MidiDriver_CMS::MidiDriver_CMS(Audio::Mixer* mixer, ResourceManager* resMan, SciVersion version) : MidiDriver_Emulated(mixer), _resMan(resMan),
-	_version(version), _cms(0), _rate(0), _playSwitch(true), _masterVolume(0), _numVoicesPrimary(version > SCI_VERSION_0_LATE ? 12 : 8),
-	_actualTimerInterval(1000000000 /(_baseFreq*1000)), _reqTimerInterval(1000000000/60000), _numVoicesSecondary(version > SCI_VERSION_0_LATE ? 0 : 4) {
-	memset(_voice, 0, sizeof(_voice));
-	_updateTimer = _reqTimerInterval;
-}
-
-MidiDriver_CMS::~MidiDriver_CMS() {
-	for (int i = 0; i < 12; ++i)
-		delete _voice[i];
-}
-
 int MidiDriver_CMS::open() {
 	if (_cms)
 		return MERR_ALREADY_OPEN;
@@ -798,42 +176,36 @@ int MidiDriver_CMS::open() {
 	Resource *res = _resMan->findResource(ResourceId(kResourceTypePatch, 101), false);
 	if (!res)
 		return -1;
-	
-	_patchData->allocateFromSpan(_version < SCI_VERSION_1_EARLY ? res->subspan(30) : *res);
 
-	_rate = _mixer->getOutputRate();
-	_cms = new CMSEmulator(_rate);
-	assert(_cms);	
-	
+	_patchData->allocateFromSpan(*res);
+
 	for (uint i = 0; i < ARRAYSIZE(_channel); ++i)
 		_channel[i] = Channel();
 
-	for (uint i = 0; i < ARRAYSIZE(_voice); ++i) {
-		if (_version < SCI_VERSION_1_EARLY)
-			_voice[i] = new CMSVoice_V0(i, this, _cms, *_patchData);
-		else
-			_voice[i] = new CMSVoice_V1(i, this, _cms, *_patchData);
-	}
-	
+	for (uint i = 0; i < ARRAYSIZE(_voice); ++i)
+		_voice[i] = Voice();
+
+	_rate = _mixer->getOutputRate();
+	_cms = new CMSEmulator(_rate);
+	assert(_cms);
 	_playSwitch = true;
 	_masterVolume = 0;
 
 	for (int i = 0; i < 31; ++i) {
-		writeToChip(0, i, 0);
-		writeToChip(1, i, 0);
+		writeToChip1(i, 0);
+		writeToChip2(i, 0);
 	}
 
-	// Enable frequency for all channels
-	writeToChip(0, 0x14, _version < SCI_VERSION_1_EARLY ? 0x3F : 0xFF);
-	writeToChip(1, 0x14, _version < SCI_VERSION_1_EARLY ? 0x3F : 0xFF);
+	writeToChip1(0x14, 0xFF);
+	writeToChip2(0x14, 0xFF);
 
-	// Sync and reset generators
-	writeToChip(0, 0x1C, 2);
-	writeToChip(1, 0x1C, 2);
+	writeToChip1(0x1C, 1);
+	writeToChip2(0x1C, 1);
 
-	// Enable all channels
-	writeToChip(0, 0x1C, 1);
-	writeToChip(1, 0x1C, 1);
+	_samplesPerCallback = getRate() / _timerFreq;
+	_samplesPerCallbackRemainder = getRate() % _timerFreq;
+	_samplesTillCallback = 0;
+	_samplesTillCallbackRemainder = 0;
 
 	int retVal = MidiDriver_Emulated::open();
 	if (retVal != 0)
@@ -857,10 +229,6 @@ void MidiDriver_CMS::send(uint32 b) {
 	const uint8 op1 = (b >> 8) & 0xff;
 	const uint8 op2 = (b >> 16) & 0xff;
 
-	// This is a SCI0 only feature. For SCI1 we simply set all channels to valid by default so that this check will always pass.
-	if (!_channel[channel].isValid)
-		return;
-
 	switch (command) {
 	case 0x80:
 		noteOff(channel, op1);
@@ -875,7 +243,7 @@ void MidiDriver_CMS::send(uint32 b) {
 		break;
 
 	case 0xC0:
-		programChange(channel, op1);
+		_channel[channel].patch = op1;
 		break;
 
 	case 0xE0:
@@ -893,140 +261,215 @@ uint32 MidiDriver_CMS::property(int prop, uint32 param) {
 		if (param != 0xffff)
 			_masterVolume = param;
 		return _masterVolume;
-	case MIDI_PROP_PLAYSWITCH:
-		if (param != 0xffff)
-			_playSwitch = param ? true : false;
-		return _playSwitch ? 1 : 0;
-	case MIDI_PROP_CHANNEL_VOLUME:
-		return (param < 16) ? _channel[param].volume : 0;
-	case MIDI_PROP_CHANNEL_PITCHWHEEL:
-		return (param < 16) ? _channel[param].pitchWheel : 0;
-	case MIDI_PROP_CHANNEL_PANPOS:
-		return (param < 16) ? _channel[param].pan : 0;
+
 	default:
 		return MidiDriver_Emulated::property(prop, param);
 	}
 }
 
-void MidiDriver_CMS::initTrack(SciSpan<const byte>& header) {
-	if (!_isOpen || _version > SCI_VERSION_0_LATE)
-		return;
+void MidiDriver_CMS::playSwitch(bool play) {
+	_playSwitch = play;
+}
 
-	uint8 readPos = 0;
-	uint8 caps = header.getInt8At(readPos++);
-	int numChan = (caps == 2) ? 15 : 16;
-	if (caps != 0 && caps != 2)
-		return;
+void MidiDriver_CMS::writeToChip1(int address, int data) {
+	_cms->portWrite(0x221, address);
+	_cms->portWrite(0x220, data);
 
-	for (int i = 0; i < 12; ++i)
-		_voice[i]->reset();
+	if (address >= 16 && address <= 18)
+		_octaveRegs[0][address - 16] = data;
+}
 
-	for (int i = 0; i < 16; ++i) {
-		_channel[i].isValid = false;
-		_channel[i].volume = 180;
-		_channel[i].pitchWheel = 0x2000;
-		_channel[i].pan = 0;
+void MidiDriver_CMS::writeToChip2(int address, int data) {
+	_cms->portWrite(0x223, address);
+	_cms->portWrite(0x222, data);
 
-		if (i >= numChan)
-			continue;
+	if (address >= 16 && address <= 18)
+		_octaveRegs[1][address - 16] = data;
+}
 
-		uint8 num = header.getInt8At(readPos++) & 0x0F;
-		uint8 flags = header.getInt8At(readPos++);
+void MidiDriver_CMS::voiceOn(int voiceNr, int note, int velocity) {
+	Voice &voice = _voice[voiceNr];
+	voice.note = note;
+	voice.turnOff = false;
+	voice.patchDataIndex = 0;
+	voice.amplitudeTimer = 0;
+	voice.ticks = 0;
+	voice.turnOffTicks = 0;
+	voice.patchDataPtr = _patchData->subspan(_patchData->getUint16LEAt(_channel[voice.channel].patch * 2));
+	if (velocity)
+		velocity = _velocityTable[(velocity >> 3)];
+	voice.velocity = velocity;
+	noteSend(voiceNr);
+}
 
-		if (num == 15 || !(flags & 4))
-			continue;
+void MidiDriver_CMS::voiceOff(int voiceNr) {
+	Voice &voice = _voice[voiceNr];
+	voice.velocity = 0;
+	voice.note = 0xFF;
+	voice.sustained = 0;
+	voice.turnOff = false;
+	voice.patchDataIndex = 0;
+	voice.amplitudeTimer = 0;
+	voice.amplitudeModifier = 0;
+	voice.ticks = 0;
+	voice.turnOffTicks = 0;
 
-		// Another strange thing about this driver... All channels to be used have to be marked as valid here
-		// or they will be blocked in send(). Even control change voice mapping won't be accessible. This means
-		// that a num == 0 setting could even make sense here, since it will mark that channel as valid for
-		// later use (e.g. assigning voices via control change voice mapping).
-		_channel[i].isValid = true;
-		if (num == 0)
-			continue;
+	setupVoiceAmplitude(voiceNr);
+}
+
+void MidiDriver_CMS::noteSend(int voiceNr) {
+	Voice &voice = _voice[voiceNr];
 
-		// This weird driver will assign a second voice if the number of requested voices is exactly 1.
-		// The secondary voice is configured differently (has its own instrument patch data). The secondary
-		// voice is controlled through the primary voice. It will not receive its own separate commands.
-		// The main purpose seems providing stereo channels with 2 discrete voices for the left and right
-		// speaker output. However, the instrument patch can also turn this around so that both voices
-		// use the same panning. What an awesome concept...
-		bindVoices(i, num, num == 1, false);
+	int frequency = (CLIP<int>(voice.note, 21, 116) - 21) * 4;
+	if (_channel[voice.channel].pitchModifier) {
+		int modifier = _channel[voice.channel].pitchModifier;
+
+		if (!_channel[voice.channel].pitchAdditive) {
+			if (frequency > modifier)
+				frequency -= modifier;
+			else
+				frequency = 0;
+		} else {
+			int tempFrequency = 384 - frequency;
+			if (modifier < tempFrequency)
+				frequency += modifier;
+			else
+				frequency = 383;
+		}
 	}
-}
 
-void MidiDriver_CMS::onTimer() {
-	for (_updateTimer -= _actualTimerInterval; _updateTimer <= 0; _updateTimer += _reqTimerInterval) {
-		for (uint i = 0; i < ARRAYSIZE(_voice); ++i)
-			_voice[i]->update();
+	int chipNumber = 0;
+	if (voiceNr >= 6) {
+		voiceNr -= 6;
+		chipNumber = 1;
+	}
+
+	int octave = 0;
+	while (frequency >= 48) {
+		frequency -= 48;
+		++octave;
 	}
+
+	frequency = _frequencyTable[frequency];
+
+	if (chipNumber == 1)
+		writeToChip2(8 + voiceNr, frequency);
+	else
+		writeToChip1(8 + voiceNr, frequency);
+
+	uint8 octaveData = _octaveRegs[chipNumber][voiceNr >> 1];
+
+	if (voiceNr & 1) {
+		octaveData &= 0x0F;
+		octaveData |= (octave << 4);
+	} else {
+		octaveData &= 0xF0;
+		octaveData |= octave;
+	}
+
+	if (chipNumber == 1)
+		writeToChip2(0x10 + (voiceNr >> 1), octaveData);
+	else
+		writeToChip1(0x10 + (voiceNr >> 1), octaveData);
 }
 
-void MidiDriver_CMS::noteOn(int channelNr, int note, int velocity) {
+void MidiDriver_CMS::noteOn(int channel, int note, int velocity) {
 	if (note < 21 || note > 116)
 		return;
 
 	if (velocity == 0) {
-		noteOff(channelNr, note);
+		noteOff(channel, note);
 		return;
 	}
 
-	for (int i = 0; i < _numVoicesPrimary; ++i) {
-		if (_voice[i]->_assign == channelNr && _voice[i]->_note == note) {
-			if (_version > SCI_VERSION_0_LATE) {
-				_voice[i]->stop();
-				_voice[i]->programChange(_channel[channelNr].program);
-			}
-			_voice[i]->noteOn(note, velocity);
+	for (uint i = 0; i < ARRAYSIZE(_voice); ++i) {
+		if (_voice[i].channel == channel && _voice[i].note == note) {
+			_voice[i].sustained = 0;
+			voiceOff(i);
+			voiceOn(i, note, velocity);
 			return;
 		}
 	}
 
 #ifdef CMS_DISABLE_VOICE_MAPPING
-	int id = findVoiceBasic(channelNr);
+	int voice = findVoiceBasic(channel);
 #else
-	int id = findVoice(channelNr, note);
+	int voice = findVoice(channel);
 #endif
-	if (id != -1) {
-		if (_version > SCI_VERSION_0_LATE)
-			_voice[id]->programChange(_channel[channelNr].program);
-		_voice[id]->noteOn(note, velocity);
+	if (voice != -1)
+		voiceOn(voice, note, velocity);
+}
+
+int MidiDriver_CMS::findVoiceBasic(int channel) {
+	int voice = -1;
+	int oldestVoice = -1;
+	int oldestAge = -1;
+
+	// Try to find a voice assigned to this channel that is free (round-robin)
+	for (int i = 0; i < ARRAYSIZE(_voice); i++) {
+		int v = (_channel[channel].lastVoiceUsed + i + 1) % ARRAYSIZE(_voice);
+
+		if (_voice[v].note == 0xFF) {
+			voice = v;
+			break;
+		}
+
+		// We also keep track of the oldest note in case the search fails
+		if (_voice[v].ticks > oldestAge) {
+			oldestAge = _voice[v].ticks;
+			oldestVoice = v;
+		}
+	}
+
+	if (voice == -1) {
+		if (oldestVoice >= 0) {
+			voiceOff(oldestVoice);
+			voice = oldestVoice;
+		} else {
+			return -1;
+		}
 	}
+
+	_voice[voice].channel = channel;
+	_channel[channel].lastVoiceUsed = voice;
+	return voice;
 }
 
-void MidiDriver_CMS::noteOff(int channelNr, int note) {
+void MidiDriver_CMS::noteOff(int channel, int note) {
 	for (uint i = 0; i < ARRAYSIZE(_voice); ++i) {
-		if (_voice[i]->_assign == channelNr && _voice[i]->_note == note) {
-			if (_channel[channelNr].hold != 0)
-				_voice[i]->_sustained = true;
+		if (_voice[i].channel == channel && _voice[i].note == note) {
+			if (_channel[channel].hold != 0)
+				_voice[i].sustained = true;
 			else
-				_voice[i]->noteOff();
+				_voice[i].turnOff = true;
 		}
 	}
 }
 
-void MidiDriver_CMS::controlChange(int channelNr, int control, int value) {
-	// The original SCI0 CMS drivers do not have Midi control 123. I support it nonetheless,
-	// since our current music engine seems to want to have it and it does not cause problems either.
-	if (_version < SCI_VERSION_1_EARLY && (control == 10 || control == 64))
-		return;
-
+void MidiDriver_CMS::controlChange(int channel, int control, int value) {
 	switch (control) {
 	case 7:
-		_channel[channelNr].volume = (_version < SCI_VERSION_1_EARLY) ? MAX<uint8>((value & 0x78) << 1, 0x40) : (value ? MAX<uint8>(value >> 3, 1) : 0);
+		if (value) {
+			value >>= 3;
+			if (!value)
+				++value;
+		}
+
+		_channel[channel].volume = value;
 		break;
 
 	case 10:
-		_channel[channelNr].pan = value;
+		_channel[channel].pan = value;
 		break;
 
 	case 64:
-		_channel[channelNr].hold = value;
+		_channel[channel].hold = value;
 
 		if (!value) {
-			for (int i = 0; i < _numVoicesPrimary; ++i) {
-				if (_voice[i]->_assign == channelNr && _voice[i]->_sustained) {
-					_voice[i]->_sustained = false;
-					_voice[i]->noteOff();
+			for (uint i = 0; i < ARRAYSIZE(_voice); ++i) {
+				if (_voice[i].channel == channel && _voice[i].sustained) {
+					_voice[i].sustained = 0;
+					_voice[i].turnOff = true;
 				}
 			}
 		}
@@ -1034,14 +477,14 @@ void MidiDriver_CMS::controlChange(int channelNr, int control, int value) {
 
 	case 75:
 #ifndef CMS_DISABLE_VOICE_MAPPING
-		voiceMapping(channelNr, value);
+		voiceMapping(channel, value);
 #endif
 		break;
 
 	case 123:
 		for (uint i = 0; i < ARRAYSIZE(_voice); ++i) {
-			if (_voice[i]->_assign == channelNr && _voice[i]->_note != 0xFF)
-				_voice[i]->stop();
+			if (_voice[i].channel == channel && _voice[i].note != 0xFF)
+				voiceOff(i);
 		}
 		break;
 
@@ -1050,100 +493,80 @@ void MidiDriver_CMS::controlChange(int channelNr, int control, int value) {
 	}
 }
 
-void MidiDriver_CMS::programChange(int channelNr, int value) {
-	_channel[channelNr].program = value;
-	if (_version > SCI_VERSION_0_LATE)
-		return;
+void MidiDriver_CMS::pitchWheel(int channelNr, int value) {
+	Channel &channel = _channel[channelNr];
+	channel.pitchWheel = value;
+	channel.pitchAdditive = false;
+	channel.pitchModifier = 0;
 
-	for (int i = 0; i < _numVoicesPrimary; ++i) {
-		if (_voice[i]->_assign == channelNr)
-			_voice[i]->programChange(value);
+	if (value < 0x2000) {
+		channel.pitchModifier = (0x2000 - value) / 170;
+	} else if (value > 0x2000) {
+		channel.pitchModifier = (value - 0x2000) / 170;
+		channel.pitchAdditive = true;
 	}
-}
 
-void MidiDriver_CMS::pitchWheel(int channelNr, int value) {
-	_channel[channelNr].pitchWheel = value;
-	for (int i = 0; i < _numVoicesPrimary; ++i) {
-		if (_voice[i]->_assign == channelNr && _voice[i]->_note != 0xFF)
-			_voice[i]->pitchWheel();
+	for (uint i = 0; i < ARRAYSIZE(_voice); ++i) {
+		if (_voice[i].channel == channelNr && _voice[i].note != 0xFF)
+			noteSend(i);
 	}
 }
 
 void MidiDriver_CMS::voiceMapping(int channelNr, int value) {
 	int curVoices = 0;
 
-	for (int i = 0; i < _numVoicesPrimary; ++i) {
-		if (_voice[i]->_assign == channelNr)
+	for (uint i = 0; i < ARRAYSIZE(_voice); ++i) {
+		if (_voice[i].channel == channelNr)
 			++curVoices;
 	}
 
-	curVoices += _channel[channelNr].missingVoices;
+	curVoices += _channel[channelNr].extraVoices;
 
-	if (curVoices < value) {
-		bindVoices(channelNr, value - curVoices, curVoices == 0 && value == 1, true);
-	} else if (curVoices > value) {
-		unbindVoices(channelNr, curVoices - value, value == 1);
-		donateVoices(value == 1);
+	if (curVoices == value) {
+		return;
+	} else if (curVoices < value) {
+		bindVoices(channelNr, value - curVoices);
+	} else {
+		unbindVoices(channelNr, curVoices - value);
+		donateVoices();
 	}
 }
 
-void MidiDriver_CMS::bindVoices(int channelNr, int voices, bool bindSecondary, bool doProgramChange) {
-	int secondary = bindSecondary ? _numVoicesSecondary : 0;
-
-	for (int i = 0; i < _numVoicesPrimary; ++i) {
-		if (_voice[i]->_assign != 0xFF)
+void MidiDriver_CMS::bindVoices(int channel, int voices) {
+	for (uint i = 0; i < ARRAYSIZE(_voice); ++i) {
+		if (_voice[i].channel == 0xFF)
 			continue;
 
-		//debug("===== MidiDriver_CMS: hardware channel %02d is assigned to device channel %02d (primary voice) =======", i, channelNr);
-		_voice[i]->_assign = channelNr;
-		if (_voice[i]->_note != 0xFF)
-			_voice[i]->stop();
-
-		for (int ii = _numVoicesPrimary; ii < _numVoicesPrimary + secondary; ++ii) {
-			if (_voice[ii]->_assign != 0xFF)
-				continue;
-
-			_voice[ii]->_assign = channelNr;
-			_voice[i]->_secondaryVoice = _voice[ii];
-
-			//debug("===== MidiDriver_CMS: hardware channel %02d is assigned to device channel %02d (secondary voice) =====", ii, channelNr);
-			break;
-		}
+		Voice &voice = _voice[i];
+		voice.channel = channel;
 
-		// This will also release the secondary voice binding immediately if the current patch does
-		// not require such an extra channel. This condition will not be checked when called from initTrack().
-		if (doProgramChange)
-			_voice[i]->programChange(_channel[channelNr].program);
+		if (voice.note != 0xFF)
+			voiceOff(i);
 
 		--voices;
 		if (voices == 0)
 			break;
 	}
 
-	_channel[channelNr].missingVoices += voices;
+	_channel[channel].extraVoices += voices;
+
+	// The original called "PatchChange" here, since this just
+	// copies the value of _channel[channel].patch to itself
+	// it is left out here though.
 }
 
-void MidiDriver_CMS::unbindVoices(int channelNr, int voices, bool bindSecondary) {
-	int secondary = bindSecondary ? _numVoicesSecondary : 0;
+void MidiDriver_CMS::unbindVoices(int channelNr, int voices) {
 	Channel &channel = _channel[channelNr];
 
-	if (channel.missingVoices >= voices) {
-		channel.missingVoices -= voices;
+	if (channel.extraVoices >= voices) {
+		channel.extraVoices -= voices;
 	} else {
-		voices -= channel.missingVoices;
-		channel.missingVoices = 0;
-
-		for (int i = 0; i < _numVoicesPrimary; ++i) {
-			if (_voice[i]->_assign == channelNr && _voice[i]->_note == 0xFF) {
-				_voice[i]->_assign = 0xFF;
-				
-				CMSVoice *sec = _voice[i]->_secondaryVoice;
-				if (sec) {
-					sec->stop();
-					sec->_assign = 0xFF;
-					_voice[i]->_secondaryVoice = 0;
-				}
+		voices -= channel.extraVoices;
+		channel.extraVoices = 0;
 
+		for (uint i = 0; i < ARRAYSIZE(_voice); ++i) {
+			if (_voice[i].channel == channelNr
+			    && _voice[i].note == 0xFF) {
 				--voices;
 				if (voices == 0)
 					return;
@@ -1154,15 +577,15 @@ void MidiDriver_CMS::unbindVoices(int channelNr, int voices, bool bindSecondary)
 			uint16 voiceTime = 0;
 			uint voiceNr = 0;
 
-			for (int i = 0; i < _numVoicesPrimary; ++i) {
-				if (_voice[i]->_assign != channelNr)
+			for (uint i = 0; i < ARRAYSIZE(_voice); ++i) {
+				if (_voice[i].channel != channelNr)
 					continue;
 
-				uint16 curTime = _voice[i]->_releaseDuration;
+				uint16 curTime = _voice[i].turnOffTicks;
 				if (curTime)
 					curTime += 0x8000;
 				else
-					curTime = _voice[i]->_duration;
+					curTime = _voice[i].ticks;
 
 				if (curTime >= voiceTime) {
 					voiceNr = i;
@@ -1170,112 +593,72 @@ void MidiDriver_CMS::unbindVoices(int channelNr, int voices, bool bindSecondary)
 				}
 			}
 
-			_voice[voiceNr]->_sustained = false;
-			_voice[voiceNr]->stop();
-			_voice[voiceNr]->_assign = 0xFF;
-
-			CMSVoice *sec = _voice[voiceNr]->_secondaryVoice;
-			if (sec) {
-				sec->stop();
-				sec->_assign = 0xFF;
-				_voice[voiceNr]->_secondaryVoice = 0;
-			}
-
+			_voice[voiceNr].sustained = 0;
+			voiceOff(voiceNr);
+			_voice[voiceNr].channel = 0xFF;
 			--voices;
 		} while (voices != 0);
 	}
-
-	for (int i = _numVoicesPrimary; i < _numVoicesPrimary + secondary; ++i) {
-		if (_voice[i]->_assign != 0xFF)
-			continue;
-
-		_voice[i]->_assign = channelNr;
-		if (_voice[i]->_note != 0xFF)
-			_voice[i]->stop();
-
-		for (int ii = 0; ii < _numVoicesPrimary; ++ii) {
-			if (_voice[ii]->_assign != channelNr)
-				continue;
-			_voice[ii]->_secondaryVoice = _voice[i];
-			// This will release the secondary binding immediately if the current patch does not require such an extra channel.
-			_voice[ii]->programChange(_channel[channelNr].program);
-			break;
-		}
-
-		if (_voice[i]->_assign == channelNr && _voice[i]->_note != 0xFF)
-			_voice[i]->stop();
-		break;
-	}
 }
 
-void MidiDriver_CMS::donateVoices(bool bindSecondary) {
+void MidiDriver_CMS::donateVoices() {
 	int freeVoices = 0;
 
-	for (int i = 0; i < _numVoicesPrimary; ++i) {
-		if (_voice[i]->_assign == 0xFF)
+	for (uint i = 0; i < ARRAYSIZE(_voice); ++i) {
+		if (_voice[i].channel == 0xFF)
 			++freeVoices;
 	}
 
 	if (!freeVoices)
 		return;
 
-	for (int i = 0; i < ARRAYSIZE(_channel); ++i) {
+	for (uint i = 0; i < ARRAYSIZE(_channel); ++i) {
 		Channel &channel = _channel[i];
 
-		if (!channel.missingVoices) {
+		if (!channel.extraVoices) {
 			continue;
-		} else if (channel.missingVoices < freeVoices) {
-			freeVoices -= channel.missingVoices;
-			int missing = channel.missingVoices;
-			channel.missingVoices = 0;
-			bindVoices(i, missing, bindSecondary, true);
+		} else if (channel.extraVoices < freeVoices) {
+			freeVoices -= channel.extraVoices;
+			channel.extraVoices = 0;
+			bindVoices(i, channel.extraVoices);
 		} else {
-			channel.missingVoices -= freeVoices;
-			bindVoices(i, freeVoices, bindSecondary, true);
+			channel.extraVoices -= freeVoices;
+			bindVoices(i, freeVoices);
 			return;
 		}
 	}
 }
 
-int MidiDriver_CMS::findVoice(int channelNr, int note) {
+int MidiDriver_CMS::findVoice(int channelNr) {
 	Channel &channel = _channel[channelNr];
 	int voiceNr = channel.lastVoiceUsed;
+
 	int newVoice = 0;
-	int newVoiceAltSCI0 = (_version > SCI_VERSION_0_LATE) ? -2 : -1;
 	uint16 newVoiceTime = 0;
 
 	bool loopDone = false;
 	do {
 		++voiceNr;
 
-		if (voiceNr == _numVoicesPrimary)
+		if (voiceNr == 12)
 			voiceNr = 0;
 
+		Voice &voice = _voice[voiceNr];
+
 		if (voiceNr == channel.lastVoiceUsed)
 			loopDone = true;
 
-		if (_voice[voiceNr]->_assign == channelNr) {
-			if (_voice[voiceNr]->_note == 0xFF) {
-				channel.lastVoiceUsed = (_version > SCI_VERSION_0_LATE) ? voiceNr : _numVoicesPrimary - 1;
+		if (voice.channel == channelNr) {
+			if (voice.note == 0xFF) {
+				channel.lastVoiceUsed = voiceNr;
 				return voiceNr;
 			}
 
-			int cnt = 1;
-			for (int i = voiceNr + 1; i < _numVoicesPrimary; ++i) {
-				if (_voice[i]->_assign == channelNr)
-					++cnt;
-			}
-
-			// The SCI0 driver will (before resorting to the "note age test") simply return the first
-			// assigned voice as long as there are no other (primary) voices assigned to the midi part.
-			if (cnt == 1 && newVoiceAltSCI0 == -1)
-				newVoiceAltSCI0 = voiceNr;
-
-			uint16 curTime = _voice[voiceNr]->_releaseDuration;
+			uint16 curTime = voice.turnOffTicks;
 			if (curTime)
 				curTime += 0x8000;
 			else
-				curTime = _voice[voiceNr]->_duration;
+				curTime = voice.ticks;
 
 			if (curTime >= newVoiceTime) {
 				newVoice = voiceNr;
@@ -1284,109 +667,147 @@ int MidiDriver_CMS::findVoice(int channelNr, int note) {
 		}
 	} while (!loopDone);
 
-	if (newVoiceAltSCI0 >= 0)
-		return newVoiceAltSCI0;
-
 	if (newVoiceTime > 0) {
 		voiceNr = newVoice;
-		channel.lastVoiceUsed = _numVoicesPrimary - 1;
-
-		if (_version > SCI_VERSION_0_LATE) {
-			_voice[voiceNr]->stop();
-			channel.lastVoiceUsed = voiceNr;
-		}
-
+		_voice[voiceNr].sustained = 0;
+		voiceOff(voiceNr);
+		channel.lastVoiceUsed = voiceNr;
 		return voiceNr;
+	} else {
+		return -1;
 	}
-	
-	return -1;
 }
 
-int MidiDriver_CMS::findVoiceBasic(int channelNr) {
-	int voice = -1;
-	int oldestVoice = -1;
-	int oldestAge = -1;
+void MidiDriver_CMS::updateVoiceAmplitude(int voiceNr) {
+	Voice &voice = _voice[voiceNr];
 
-	// Try to find a voice assigned to this channel that is free (round-robin)
-	for (int i = 0; i < _numVoicesPrimary; i++) {
-		int v = (_channel[channelNr].lastVoiceUsed + i + 1) % _numVoicesPrimary;
-
-		if (_voice[v]->_note == 0xFF) {
-			voice = v;
-			break;
-		}
+	if (voice.amplitudeTimer != 0 && voice.amplitudeTimer != 254) {
+		--voice.amplitudeTimer;
+		return;
+	} else if (voice.amplitudeTimer == 254) {
+		if (!voice.turnOff)
+			return;
 
-		// We also keep track of the oldest note in case the search fails
-		if (_voice[v]->_duration > oldestAge) {
-			oldestAge = _voice[v]->_duration;
-			oldestVoice = v;
-		}
+		voice.amplitudeTimer = 0;
 	}
 
-	if (voice == -1) {
-		if (oldestVoice >= 0) {
-			_voice[oldestVoice]->stop();
-			voice = oldestVoice;
-		} else {
-			return -1;
-		}
+	int nextDataIndex = voice.patchDataIndex;
+	uint8 timerData = 0;
+	uint8 amplitudeData = voice.patchDataPtr[nextDataIndex];
+
+	if (amplitudeData == 255) {
+		timerData = amplitudeData = 0;
+		voiceOff(voiceNr);
+	} else {
+		timerData = voice.patchDataPtr[nextDataIndex + 1];
+		nextDataIndex += 2;
 	}
 
-	_voice[voice]->_assign = channelNr;
-	_channel[channelNr].lastVoiceUsed = (_version > SCI_VERSION_0_LATE) ? voice : 0;
-	return voice;
+	voice.patchDataIndex = nextDataIndex;
+	voice.amplitudeTimer = timerData;
+	voice.amplitudeModifier = amplitudeData;
 }
 
-void MidiDriver_CMS::writeToChip(int chip, int address, int data) {
-	assert(chip == 0 || chip == 1);
-	_cms->portWrite(0x221 + (chip << 1), address);
-	_cms->portWrite(0x220 + (chip << 1), data);
+void MidiDriver_CMS::setupVoiceAmplitude(int voiceNr) {
+	Voice &voice = _voice[voiceNr];
+	uint amplitude = 0;
+
+	if (_channel[voice.channel].volume && voice.velocity
+	    && voice.amplitudeModifier && _masterVolume) {
+		amplitude = _channel[voice.channel].volume * voice.velocity;
+		amplitude /= 0x0F;
+		amplitude *= voice.amplitudeModifier;
+		amplitude /= 0x0F;
+		amplitude *= _masterVolume;
+		amplitude /= 0x0F;
+
+		if (!amplitude)
+			++amplitude;
+	}
+
+	uint8 amplitudeData = 0;
+	int pan = _channel[voice.channel].pan >> 2;
+	if (pan >= 16) {
+		amplitudeData = (amplitude * (31 - pan) / 0x0F) & 0x0F;
+		amplitudeData |= (amplitude << 4);
+	} else {
+		amplitudeData = (amplitude * pan / 0x0F) & 0x0F;
+		amplitudeData <<= 4;
+		amplitudeData |= amplitude;
+	}
+
+	if (!_playSwitch)
+		amplitudeData = 0;
+
+	if (voiceNr >= 6)
+		writeToChip2(voiceNr - 6, amplitudeData);
+	else
+		writeToChip1(voiceNr, amplitudeData);
 }
 
 void MidiDriver_CMS::generateSamples(int16 *buffer, int len) {
-	_cms->readBuffer(buffer, len);
+	while (len) {
+		if (!_samplesTillCallback) {
+			for (uint i = 0; i < ARRAYSIZE(_voice); ++i) {
+				if (_voice[i].note == 0xFF)
+					continue;
+
+				++_voice[i].ticks;
+				if (_voice[i].turnOff)
+					++_voice[i].turnOffTicks;
+
+				updateVoiceAmplitude(i);
+				setupVoiceAmplitude(i);
+			}
+
+			_samplesTillCallback = _samplesPerCallback;
+			_samplesTillCallbackRemainder += _samplesPerCallbackRemainder;
+			if (_samplesTillCallbackRemainder >= _timerFreq) {
+				_samplesTillCallback++;
+				_samplesTillCallbackRemainder -= _timerFreq;
+			}
+		}
+
+		int32 render = MIN<int32>(len, _samplesTillCallback);
+		len -= render;
+		_samplesTillCallback -= render;
+		_cms->readBuffer(buffer, render);
+		buffer += render * 2;
+	}
 }
 
+
 class MidiPlayer_CMS : public MidiPlayer {
 public:
-	MidiPlayer_CMS(SciVersion version) : MidiPlayer(version) {}
+	MidiPlayer_CMS(SciVersion version) : MidiPlayer(version) {
+	}
 
-	int open(ResourceManager *resMan);
-	void close();
+	int open(ResourceManager *resMan) {
+		if (_driver)
+			return MidiDriver::MERR_ALREADY_OPEN;
 
-	void MidiPlayer_CMS::initTrack(SciSpan<const byte>& trackData);
+		_driver = new MidiDriver_CMS(g_system->getMixer(), resMan);
+		int driverRetVal = _driver->open();
+		if (driverRetVal != 0)
+			return driverRetVal;
+
+		return 0;
+	}
+
+	void close() {
+		_driver->setTimerCallback(0, 0);
+		_driver->close();
+		delete _driver;
+		_driver = nullptr;
+	}
 
 	bool hasRhythmChannel() const { return false; }
-	byte getPlayId() const { return _version > SCI_VERSION_0_LATE ? 9 : 4; }
+	byte getPlayId() const { return 9; }
 	int getPolyphony() const { return 12; }
 
-	void playSwitch(bool play) { _driver->property(MidiDriver_CMS::MIDI_PROP_PLAYSWITCH, play ? 1 : 0); }
+	void playSwitch(bool play) { static_cast<MidiDriver_CMS *>(_driver)->playSwitch(play); }
 };
 
-int MidiPlayer_CMS::open(ResourceManager *resMan) {
-	if (_driver)
-		return MidiDriver::MERR_ALREADY_OPEN;
-
-	_driver = new MidiDriver_CMS(g_system->getMixer(), resMan, _version);
-	int driverRetVal = _driver->open();
-	if (driverRetVal != 0)
-		return driverRetVal;
-
-	return 0;
-}
-
-void MidiPlayer_CMS::close() {
-	_driver->setTimerCallback(0, 0);
-	_driver->close();
-	delete _driver;
-	_driver = nullptr;
-}
-
-void MidiPlayer_CMS::initTrack(SciSpan<const byte>& trackData) {
-	if (_driver)
-		static_cast<MidiDriver_CMS*>(_driver)->initTrack(trackData);
-}
-
 MidiPlayer *MidiPlayer_CMS_create(SciVersion version) {
 	return new MidiPlayer_CMS(version);
 }
diff --git a/engines/sci/sound/drivers/pc9801.cpp b/engines/sci/sound/drivers/pc9801.cpp
index 824c4c9..fe7d5bf 100644
--- a/engines/sci/sound/drivers/pc9801.cpp
+++ b/engines/sci/sound/drivers/pc9801.cpp
@@ -1343,7 +1343,6 @@ int MidiDriver_PC9801::open() {
 			return MERR_CANNOT_CONNECT;
 		_pc98a->setSoundEffectChanMask(0);
 		_pc98a->ssgSetVolume(205);
-		_pc98a->writeReg(0, 0x26, 256 - _baseTempo / 288);
 		_ready = true;
 	}
 
diff --git a/engines/sci/sound/music.cpp b/engines/sci/sound/music.cpp
index dc62acb..5977cf0 100644
--- a/engines/sci/sound/music.cpp
+++ b/engines/sci/sound/music.cpp
@@ -84,9 +84,8 @@ void SciMusic::init() {
 	if (g_sci->_features->useAltWinGMSound())
 		deviceFlags |= MDT_PREFER_GM;
 
-	// SCI_VERSION_0_EARLY games apparently don't support the CMS. At least there
-	// is no patch resource 101 and I also haven't seen any CMS driver file so far.
-	if (getSciVersion() > SCI_VERSION_0_EARLY && getSciVersion() <= SCI_VERSION_1_1)
+	// Currently our CMS implementation only supports SCI1(.1)
+	if (getSciVersion() >= SCI_VERSION_1_EGA_ONLY && getSciVersion() <= SCI_VERSION_1_1)
 		deviceFlags |= MDT_CMS;
 
 	if (g_sci->getPlatform() == Common::kPlatformFMTowns) {





More information about the Scummvm-git-logs mailing list