[Scummvm-git-logs] scummvm master -> 28d8e43675e7f22cf5646c4aadecb5509095c394

athrxx noreply at scummvm.org
Fri Mar 22 22:07:45 UTC 2024


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:
28d8e43675 SCUMM: (IMS/MI2/FOA) - implement old style channel management


Commit: 28d8e43675e7f22cf5646c4aadecb5509095c394
    https://github.com/scummvm/scummvm/commit/28d8e43675e7f22cf5646c4aadecb5509095c394
Author: athrxx (athrxx at scummvm.org)
Date: 2024-03-22T22:55:48+01:00

Commit Message:
SCUMM: (IMS/MI2/FOA) - implement old style channel management

(fix bug #14618: Inaccurate fades in INDY4,  "Test 1")

This part of the bug ticket is not about fades. The reason
for the glitch is that the driver has no unused channels left
and the newer allocation mechanism is not able to free up
some of the used channels here.

Changed paths:
    engines/scumm/imuse/drivers/fmtowns.cpp
    engines/scumm/imuse/drivers/fmtowns.h
    engines/scumm/imuse/imuse.cpp
    engines/scumm/imuse/imuse.h
    engines/scumm/imuse/imuse_internal.h
    engines/scumm/imuse/imuse_part.cpp
    engines/scumm/imuse/imuse_player.cpp
    engines/scumm/imuse/sysex_scumm.cpp
    engines/scumm/scumm.cpp


diff --git a/engines/scumm/imuse/drivers/fmtowns.cpp b/engines/scumm/imuse/drivers/fmtowns.cpp
index fcfb9c5e8db..c3255a700b0 100644
--- a/engines/scumm/imuse/drivers/fmtowns.cpp
+++ b/engines/scumm/imuse/drivers/fmtowns.cpp
@@ -844,18 +844,18 @@ const uint8 TownsMidiInputChannel::_programAdjustLevel[] = {
 };
 
 IMuseDriver_FMTowns::IMuseDriver_FMTowns(Audio::Mixer *mixer) : _timerProc(nullptr), _timerProcPara(nullptr), _channels(nullptr), _out(nullptr),
-	_baseTempo(10080), _chanState(nullptr), _operatorLevelTable(nullptr), _tickCounter(0), _rand(1), _allocCurPos(0), _isOpen(false) {
+	_baseTempo(10080), _chanState(nullptr), _operatorLevelTable(nullptr), _tickCounter(0), _rand(1), _allocCurPos(0), _isOpen(false), _numParts(24) {
 	_intf = new TownsAudioInterface(mixer, this, true);
 
-	_channels = new TownsMidiInputChannel*[32];
-	for (int i = 0; i < 32; i++)
+	_channels = new TownsMidiInputChannel*[_numParts];
+	for (int i = 0; i < 24; i++)
 		_channels[i] = new TownsMidiInputChannel(this, i > 8 ? (i + 1) : i);
 
 	_out = new TownsMidiOutputChannel*[6];
 	for (int i = 0; i < 6; i++)
 		_out[i] = new TownsMidiOutputChannel(this, i);
 
-	_chanState = new TownsMidiChanState[32];
+	_chanState = new TownsMidiChanState[_numParts];
 
 	_operatorLevelTable = new uint8[2048];
 	for (int i = 0; i < 64; i++) {
@@ -871,7 +871,7 @@ IMuseDriver_FMTowns::~IMuseDriver_FMTowns() {
 	delete _intf;
 
 	if (_channels) {
-		for (int i = 0; i < 32; i++)
+		for (int i = 0; i < _numParts; i++)
 			delete _channels[i];
 		delete[] _channels;
 	}
@@ -974,7 +974,7 @@ MidiChannel *IMuseDriver_FMTowns::allocateChannel() {
 	if (!_isOpen)
 		return nullptr;
 
-	for (int i = 0; i < 32; ++i) {
+	for (int i = 0; i < _numParts; ++i) {
 		TownsMidiInputChannel *chan = _channels[i];
 		if (chan->allocate())
 			return chan;
diff --git a/engines/scumm/imuse/drivers/fmtowns.h b/engines/scumm/imuse/drivers/fmtowns.h
index aa8a8cedd02..c6b4378dcc4 100644
--- a/engines/scumm/imuse/drivers/fmtowns.h
+++ b/engines/scumm/imuse/drivers/fmtowns.h
@@ -63,6 +63,7 @@ private:
 	TownsMidiInputChannel **_channels;
 	TownsMidiOutputChannel **_out;
 	TownsMidiChanState *_chanState;
+	const uint8 _numParts;
 
 	Common::TimerManager::TimerProc _timerProc;
 	void *_timerProcPara;
diff --git a/engines/scumm/imuse/imuse.cpp b/engines/scumm/imuse/imuse.cpp
index 9979875c64d..b801ba6b561 100644
--- a/engines/scumm/imuse/imuse.cpp
+++ b/engines/scumm/imuse/imuse.cpp
@@ -43,9 +43,10 @@ namespace Scumm {
 //
 ////////////////////////////////////////
 
-IMuseInternal::IMuseInternal(ScummEngine *vm, MidiDriverFlags sndType, uint32 initFlags) :
-	_native_mt32(initFlags & kFlagNativeMT32),
-	_newSystem(initFlags & kFlagNewSystem),
+IMuseInternal::IMuseInternal(ScummEngine *vm, MidiDriverFlags sndType, bool nativeMT32) :
+	_native_mt32(nativeMT32),
+	_newSystem(vm->_game.id == GID_SAMNMAX),
+	_dynamicChanAllocation(vm->_game.id == GID_SAMNMAX || vm->_game.id == GID_TENTACLE),
 	_midi_adlib(nullptr),
 	_midi_native(nullptr),
 	_sysex(nullptr),
@@ -1413,8 +1414,8 @@ int IMuseInternal::get_volchan_entry(uint a) {
 	return -1;
 }
 
-IMuseInternal *IMuseInternal::create(ScummEngine *vm, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver, MidiDriverFlags sndType, uint32 initFlags) {
-	IMuseInternal *i = new IMuseInternal(vm, sndType, initFlags);
+IMuseInternal *IMuseInternal::create(ScummEngine *vm, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver, MidiDriverFlags sndType, bool nativeMT32) {
+	IMuseInternal *i = new IMuseInternal(vm, sndType, nativeMT32);
 	i->initialize(vm->_system, nativeMidiDriver, adlibMidiDriver);
 	return i;
 }
@@ -1541,12 +1542,73 @@ void IMuseInternal::midiTimerCallback(void *data) {
 	info->imuse->on_timer(info->driver);
 }
 
+MidiChannel *IMuseInternal::allocateChannel(MidiDriver *midi, byte prio) {
+	MidiChannel *mc = midi->allocateChannel();
+	if (mc)
+		return mc;
+
+	Part *best = nullptr;
+	for (Part *part = _parts; part < &_parts[ARRAYSIZE(_parts)]; ++part) {
+		if (!part->_percussion && part->_mc && part->_mc->device() == midi && part->_pri_eff <= prio) {
+			prio = part->_pri_eff;
+			best = part;
+		}
+	}
+
+	if (best) {
+		best->off();
+		suspendPart(best);
+		mc = midi->allocateChannel();
+	}
+
+	return mc;
+}
+
+bool IMuseInternal::reassignChannelAndResumePart(MidiChannel *mc) {
+	while (!_waitingPartsQueue.empty()) {
+		Part *part = _waitingPartsQueue.remove_at(0);
+		if (part->_player) {
+			part->_mc = mc;
+			part->sendAll();
+			return true;
+		}
+	}
+
+	return false;
+}
+
+void IMuseInternal::suspendPart(Part *part) {
+	if (_waitingPartsQueue.empty()) {
+		_waitingPartsQueue.push_back(part);
+		return;
+	}
+
+	for (Common::Array<Part*>::iterator it = _waitingPartsQueue.begin(); it != _waitingPartsQueue.end(); ++it) {
+		if ((*it)->_pri_eff > part->_pri_eff)
+			continue;
+		_waitingPartsQueue.insert(it, part);
+		return;
+	}
+}
+
+void IMuseInternal::removeSuspendedPart(Part *part) {
+	for (Common::Array<Part*>::iterator it = _waitingPartsQueue.begin(); it != _waitingPartsQueue.end(); ++it) {
+		if (*it != part)
+			continue;
+		_waitingPartsQueue.erase(it);
+		return;
+	}
+}
+
 void IMuseInternal::reallocateMidiChannels(MidiDriver *midi) {
 	Part *part, *hipart;
 	int i;
 	byte hipri, lopri;
 	Part *lopart;
 
+	if (!_dynamicChanAllocation)
+		return;
+
 	while (true) {
 		hipri = 0;
 		hipart = nullptr;
@@ -1625,8 +1687,8 @@ void IMuseInternal::copyGlobalInstrument(byte slot, Instrument *dest) {
  * of the implementation to be changed and updated
  * without requiring a recompile of the client code.
  */
-IMuse *IMuse::create(ScummEngine *vm, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver, MidiDriverFlags sndType, uint32 flags) {
-	IMuseInternal *engine = IMuseInternal::create(vm, nativeMidiDriver, adlibMidiDriver, sndType, flags);
+IMuse *IMuse::create(ScummEngine *vm, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver, MidiDriverFlags sndType, bool nativeMT32) {
+	IMuseInternal *engine = IMuseInternal::create(vm, nativeMidiDriver, adlibMidiDriver, sndType, nativeMT32);
 	return engine;
 }
 
diff --git a/engines/scumm/imuse/imuse.h b/engines/scumm/imuse/imuse.h
index c25efc578b2..64251880a96 100644
--- a/engines/scumm/imuse/imuse.h
+++ b/engines/scumm/imuse/imuse.h
@@ -55,11 +55,6 @@ public:
 		PROP_RECYCLE_PLAYERS
 	};
 
-	enum {
-		kFlagNewSystem	=	1 << 0,
-		kFlagNativeMT32 =	1 << 1
-	};
-
 public:
 	virtual void on_timer(MidiDriver *midi) = 0;
 	virtual void pause(bool paused) = 0;
@@ -78,7 +73,7 @@ public:
 
 public:
 	// Factory methods
-	static IMuse *create(ScummEngine *vm, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver, MidiDriverFlags sndType, uint32 flags);
+	static IMuse *create(ScummEngine *vm, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver, MidiDriverFlags sndType, bool nativeMT32);
 };
 
 } // End of namespace Scumm
diff --git a/engines/scumm/imuse/imuse_internal.h b/engines/scumm/imuse/imuse_internal.h
index 721abbf1b3a..b946e4475c5 100644
--- a/engines/scumm/imuse/imuse_internal.h
+++ b/engines/scumm/imuse/imuse_internal.h
@@ -418,6 +418,7 @@ class IMuseInternal : public IMuse {
 protected:
 	const bool _native_mt32;
 	const bool _newSystem;
+	const bool _dynamicChanAllocation;
 	const MidiDriverFlags _soundType;
 	MidiDriver *_midi_adlib;
 	MidiDriver *_midi_native;
@@ -477,7 +478,7 @@ protected:
 	} _rhyState;
 
 protected:
-	IMuseInternal(ScummEngine *vm, MidiDriverFlags sndType, uint32 initFlags);
+	IMuseInternal(ScummEngine *vm, MidiDriverFlags sndType, bool nativeMT32);
 	~IMuseInternal() override;
 
 	int initialize(OSystem *syst, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver);
@@ -534,11 +535,18 @@ protected:
 	void fix_players_after_load(ScummEngine *scumm);
 	int setImuseMasterVolume(uint vol);
 
+	MidiChannel *allocateChannel(MidiDriver *midi, byte prio);
+	bool reassignChannelAndResumePart(MidiChannel *mc);
+	void suspendPart(Part *part);
+	void removeSuspendedPart(Part *part);
 	void reallocateMidiChannels(MidiDriver *midi);
 	void setGlobalInstrument(byte slot, byte *data);
 	void copyGlobalInstrument(byte slot, Instrument *dest);
 	bool isNativeMT32() { return _native_mt32; }
 
+protected:
+	Common::Array<Part*> _waitingPartsQueue;
+
 protected:
 	// Internal mutex-free versions of the IMuse and MusicEngine methods.
 	bool startSound_internal(int sound, int offset = 0);
@@ -570,7 +578,7 @@ public:
 
 public:
 	// Factory function
-	static IMuseInternal *create(ScummEngine *vm, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver, MidiDriverFlags sndType, uint32 initFlags);
+	static IMuseInternal *create(ScummEngine *vm, MidiDriver *nativeMidiDriver, MidiDriver *adlibMidiDriver, MidiDriverFlags sndType, bool nativeMT32);
 };
 
 } // End of namespace Scumm
diff --git a/engines/scumm/imuse/imuse_part.cpp b/engines/scumm/imuse/imuse_part.cpp
index 74b285ce892..4c21f59ec88 100644
--- a/engines/scumm/imuse/imuse_part.cpp
+++ b/engines/scumm/imuse/imuse_part.cpp
@@ -194,6 +194,13 @@ void Part::fix_after_load() {
 	set_detune(_detune);
 	set_pri(_pri);
 	set_pan(_pan);
+
+	if (!_se->_dynamicChanAllocation && !_mc) {
+		_mc = _se->allocateChannel(_player->getMidiDriver(), _pri_eff);
+		if (!_mc)
+			_se->suspendPart(this);
+	}
+
 	sendAll();
 }
 
@@ -328,13 +335,15 @@ void Part::uninit() {
 		return;
 	off();
 	_player->removePart(this);
+	_se->removeSuspendedPart(this);
 	_player = nullptr;
 }
 
 void Part::off() {
 	if (_mc) {
 		_mc->allNotesOff();
-		_mc->release();
+		if (!_se->reassignChannelAndResumePart(_mc))
+			_mc->release();
 		_mc = nullptr;
 	}
 }
diff --git a/engines/scumm/imuse/imuse_player.cpp b/engines/scumm/imuse/imuse_player.cpp
index 7954d108b31..84511ce2feb 100644
--- a/engines/scumm/imuse/imuse_player.cpp
+++ b/engines/scumm/imuse/imuse_player.cpp
@@ -790,9 +790,15 @@ int Player::scan(uint totrack, uint tobeat, uint totick) {
 void Player::turn_off_parts() {
 	Part *part;
 
-	for (part = _parts; part; part = part->_next)
-		part->off();
-	_se->reallocateMidiChannels(_midi);
+	if (!_se->_dynamicChanAllocation) {
+		turn_off_pedals();
+		for (part = _parts; part; part = part->_next)
+			part->allNotesOff();
+	} else {
+		for (part = _parts; part; part = part->_next)
+			part->off();
+		_se->reallocateMidiChannels(_midi);
+	}
 }
 
 void Player::play_active_notes() {
diff --git a/engines/scumm/imuse/sysex_scumm.cpp b/engines/scumm/imuse/sysex_scumm.cpp
index 20f5bdcf1ce..3b9292e79df 100644
--- a/engines/scumm/imuse/sysex_scumm.cpp
+++ b/engines/scumm/imuse/sysex_scumm.cpp
@@ -79,10 +79,8 @@ void sysexHandler_Scumm(Player *player, const byte *msg, uint16 len) {
 			part->set_detune(buf[6]);
 			part->pitchBendFactor(buf[7]);
 			if (part->_percussion) {
-				if (part->_mc) {
+				if (part->_mc)
 					part->off();
-					se->reallocateMidiChannels(player->_midi);
-				}
 			} else {
 				if (player->_isMIDI) {
 					// Even in cases where a program does not seem to be specified,
@@ -98,6 +96,15 @@ void sysexHandler_Scumm(Player *player, const byte *msg, uint16 len) {
 					// care of setting a default instrument too.
 					se->copyGlobalInstrument(buf[8], &part->_instrument);
 				}
+				// The newer reallocateMidiChannels() method can fail to assign a
+				// hardware channel here (bug #14618: Inaccurate fades in INDY4,
+				// "Test 1"). So instead, we implement the less dynamic alloacation
+				// method of the early version drivers here. 
+				if (!part->_mc) {
+					part->_mc = se->allocateChannel(player->_midi, part->_pri_eff);
+					if (!part->_mc)
+						se->suspendPart(part);
+				}
 				part->sendAll();
 			}
 		}
@@ -111,6 +118,8 @@ void sysexHandler_Scumm(Player *player, const byte *msg, uint16 len) {
 		break;
 
 	case 2: // Start of song. Ignore for now.
+		if (!se->_dynamicChanAllocation)
+			player->uninit_parts();
 		break;
 
 	case 16: // AdLib instrument definition(Part)
diff --git a/engines/scumm/scumm.cpp b/engines/scumm/scumm.cpp
index b34a7361ac9..5d2ce11b487 100644
--- a/engines/scumm/scumm.cpp
+++ b/engines/scumm/scumm.cpp
@@ -2238,13 +2238,7 @@ void ScummEngine::setupMusic(int midi) {
 			}
 		}
 
-		uint32 imsFlags = 0;
-		if (newSystem)
-			imsFlags |= IMuse::kFlagNewSystem;
-		if (_native_mt32)
-			imsFlags |= IMuse::kFlagNativeMT32;
-
-		_imuse = IMuse::create(this, nativeMidiDriver, adlibMidiDriver, isMacM68kIMuse() ? MDT_MACINTOSH : _sound->_musicType, imsFlags);
+		_imuse = IMuse::create(this, nativeMidiDriver, adlibMidiDriver, isMacM68kIMuse() ? MDT_MACINTOSH : _sound->_musicType, _native_mt32);
 
 		if (_game.platform == Common::kPlatformFMTowns) {
 			_musicEngine = _townsPlayer = new Player_Towns_v2(this, _mixer, _imuse, true);




More information about the Scummvm-git-logs mailing list