[Scummvm-cvs-logs] SF.net SVN: scummvm:[47321] scummvm/trunk/engines/sci/sound

waltervn at users.sourceforge.net waltervn at users.sourceforge.net
Sat Jan 16 17:06:41 CET 2010


Revision: 47321
          http://scummvm.svn.sourceforge.net/scummvm/?rev=47321&view=rev
Author:   waltervn
Date:     2010-01-16 16:06:41 +0000 (Sat, 16 Jan 2010)

Log Message:
-----------
SCI: Add support for earlier MT-32 patch format

Modified Paths:
--------------
    scummvm/trunk/engines/sci/sound/music.cpp
    scummvm/trunk/engines/sci/sound/softseq/midi.cpp
    scummvm/trunk/engines/sci/sound/softseq/mididriver.h

Modified: scummvm/trunk/engines/sci/sound/music.cpp
===================================================================
--- scummvm/trunk/engines/sci/sound/music.cpp	2010-01-16 16:00:21 UTC (rev 47320)
+++ scummvm/trunk/engines/sci/sound/music.cpp	2010-01-16 16:06:41 UTC (rev 47321)
@@ -317,6 +317,12 @@
 
 			// Find out what channels to filter for SCI0
 			channelFilterMask = pSnd->soundRes->getChannelFilterMask(_pMidiDrv->getPlayId(_soundVersion));
+
+			// Enable rhythm channel when requested
+			channelFilterMask &= ~(1 << MIDI_RHYTHM_CHANNEL);
+			if (_pMidiDrv->hasRhythmChannel())
+				channelFilterMask |= (1 << MIDI_RHYTHM_CHANNEL);
+
 			pSnd->pMidiParser->loadMusic(track, pSnd, channelFilterMask, _soundVersion);
 
 			// Fast forward to the last position and perform associated events when loading

Modified: scummvm/trunk/engines/sci/sound/softseq/midi.cpp
===================================================================
--- scummvm/trunk/engines/sci/sound/softseq/midi.cpp	2010-01-16 16:00:21 UTC (rev 47320)
+++ scummvm/trunk/engines/sci/sound/softseq/midi.cpp	2010-01-16 16:06:41 UTC (rev 47321)
@@ -37,24 +37,34 @@
 class MidiPlayer_Midi : public MidiPlayer {
 public:
 	enum {
-		kVoices = 32
+		kVoices = 32,
+		kReverbConfigNr = 11,
+		kMaxSysExSize = 264
 	};
 
 	MidiPlayer_Midi();
 	virtual ~MidiPlayer_Midi();
 
 	int open(ResourceManager *resMan);
+	void close();
 	void send(uint32 b);
+	void sysEx(const byte *msg, uint16 length);
 	bool hasRhythmChannel() const { return true; }
 	byte getPlayId(SciVersion soundVersion);
 	int getPolyphony() const { return kVoices; }
 	void setVolume(byte volume);
 	int getVolume();
+	void setReverb(byte reverb);
 	void playSwitch(bool play);
 
 private:
 	bool isMt32GmPatch(const byte *data, int size);
 	void readMt32GmPatch(const byte *data, int size);
+	void readMt32Patch(const byte *data, int size);
+	void sendMt32SysEx(const uint32 addr, Common::MemoryReadStream *str, int len, bool noDelay);
+	void sendMt32SysEx(const uint32 addr, const byte *buf, int len, bool noDelay);
+	void setMt32Volume(byte volume);
+	void resetMt32();
 
 	void noteOn(int channel, int note, int velocity);
 	void setPatch(int channel, int patch);
@@ -76,10 +86,11 @@
 	};
 
 	bool _isMt32;
-	bool _isHardwareMt32;
+	bool _hasReverb;
 	bool _playSwitch;
 	int _masterVolume;
 
+	byte _reverbConfig[kReverbConfigNr][3];
 	Channel _channels[16];	
 	uint8 _percussionMap[128];
 	int8 _keyShift[128];
@@ -87,18 +98,21 @@
 	uint8 _patchMap[128];
 	uint8 _velocityMapIdx[128];
 	uint8 _velocityMap[4][128];
+	byte _goodbyeMsg[20];
+	byte _sysExBuf[kMaxSysExSize];
 };
 
-MidiPlayer_Midi::MidiPlayer_Midi() : _playSwitch(true), _masterVolume(15), _isMt32(false), _isHardwareMt32(false) {
+MidiPlayer_Midi::MidiPlayer_Midi() : _playSwitch(true), _masterVolume(15), _isMt32(false), _hasReverb(false) {
 	MidiDriverType midiType = MidiDriver::detectMusicDriver(MDT_MIDI);
 	_driver = createMidi(midiType);
 
-	if (midiType == MD_MT32)
+	if (midiType == MD_MT32 || ConfMan.getBool("native_mt32"))
 		_isMt32 = true;
-	else if ((midiType != MD_FLUIDSYNTH) && (midiType != MD_TIMIDITY) && ConfMan.getBool("native_mt32")) {
-		_isMt32 = true;
-		_isHardwareMt32 = true;
-	}
+
+	_sysExBuf[0] = 0x41;
+	_sysExBuf[1] = 0x10;
+	_sysExBuf[2] = 0x16;
+	_sysExBuf[3] = 0x12;
 }
 
 MidiPlayer_Midi::~MidiPlayer_Midi() {
@@ -262,6 +276,12 @@
 	return _masterVolume;
 }
 
+void MidiPlayer_Midi::setReverb(byte reverb) {
+	_reverb = CLIP<byte>(reverb, 0, kReverbConfigNr - 1);
+	if (_hasReverb)
+		sendMt32SysEx(0x100001, _reverbConfig[_reverb], 3, true);
+}
+
 void MidiPlayer_Midi::playSwitch(bool play) {
 	_playSwitch = play;
 	if (play)
@@ -302,6 +322,100 @@
 	return isMt32Gm;
 }
 
+void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, Common::MemoryReadStream *str, int len, bool noDelay = false) {
+	if (len + 8 > kMaxSysExSize) {
+		warning("SysEx message exceed maximum size; ignoring");
+		return;
+	}
+
+	uint16 chk = 0;
+
+	_sysExBuf[4] = (addr >> 16) & 0xff;
+	_sysExBuf[5] = (addr >> 8) & 0xff;
+	_sysExBuf[6] = addr & 0xff;
+
+	for (int i = 0; i < len; i++)
+		_sysExBuf[7 + i] = str->readByte();
+
+	for (int i = 4; i < 7 + len; i++)
+		chk += _sysExBuf[i];
+
+	_sysExBuf[7 + len] = 128 - chk % 128;
+
+	if (noDelay)
+		_driver->sysEx(_sysExBuf, len + 8);
+	else
+		sysEx(_sysExBuf, len + 8);
+}
+
+void MidiPlayer_Midi::sendMt32SysEx(const uint32 addr, const byte *buf, int len, bool noDelay = false) {
+	Common::MemoryReadStream *str = new Common::MemoryReadStream(buf, len);
+	sendMt32SysEx(addr, str, len, noDelay);
+	delete str;
+}
+
+void MidiPlayer_Midi::readMt32Patch(const byte *data, int size) {
+	Common::MemoryReadStream *str = new Common::MemoryReadStream(data, size);
+
+	// Send before-SysEx text
+	str->seek(0x14);
+	sendMt32SysEx(0x200000, str, 20);
+
+	// Save goodbye message
+	str->read(_goodbyeMsg, 20);
+
+	// Skip volume, we leave the MT-32 volume alone
+	str->seek(2, SEEK_CUR);
+
+	// Reverb default only used in (roughly) SCI0/SCI01
+	_reverb = str->readByte();
+	_hasReverb = true;
+
+	// Skip reverb SysEx message
+	str->seek(11, SEEK_CUR);
+
+	// Read reverb data
+	for (int i = 0; i < kReverbConfigNr; i++) {
+		_reverbConfig[i][0] = str->readByte();
+		_reverbConfig[i][1] = str->readByte();
+		_reverbConfig[i][2] = str->readByte();
+	}
+
+	// Patches 1-48
+	sendMt32SysEx(0x50000, str, 256);
+	sendMt32SysEx(0x50200, str, 128);
+
+	// Timbres
+	byte timbresNr = str->readByte();
+	for (int i = 0; i < timbresNr; i++)
+		sendMt32SysEx(0x80000 + (i << 9), str, 246);
+
+	uint16 flag = str->readUint16BE();
+
+	if (!str->eos() && (flag == 0xabcd)) {
+		// Patches 49-96
+		sendMt32SysEx(0x50300, str, 256);
+		sendMt32SysEx(0x50500, str, 128);
+		flag = str->readUint16BE();
+	}
+
+	if (!str->eos() && (flag == 0xdcba)) {
+		// Rhythm key map
+		sendMt32SysEx(0x30110, str, 256);
+		// Partial reserve
+		sendMt32SysEx(0x100004, str, 9);
+	}
+
+	// Send after-SysEx text
+	str->seek(0);
+	sendMt32SysEx(0x200000, str, 20);
+
+	// Send the mystery SysEx
+	sendMt32SysEx(0x52000a, (const byte *)"\x16\x16\x16\x16\x16\x16", 6);
+
+	delete str;
+}
+
 void MidiPlayer_Midi::readMt32GmPatch(const byte *data, int size) {
 	memcpy(_patchMap, data, 0x80);
 	memcpy(_keyShift, data + 0x80, 0x80);
@@ -334,9 +448,7 @@
 					error("Failed to find end of sysEx");
 
 				int len = sysExEnd - (midi + i);
-				_driver->sysEx(midi + i, len);
-				if (_isHardwareMt32)
-					g_system->delayMillis(100);
+				sysEx(midi + i, len);
 
 				i += len + 1; // One more for the 0x7f
 				break;
@@ -368,6 +480,17 @@
 	}
 }
 
+void MidiPlayer_Midi::setMt32Volume(byte volume) {
+	sendMt32SysEx(0x100016, &volume, 1);
+}
+
+void MidiPlayer_Midi::resetMt32() {
+	sendMt32SysEx(0x7f0000, (const byte *)"\x01\x00", 2, true);
+
+	// This seems to require a longer delay than usual
+	g_system->delayMillis(150);
+}
+
 int MidiPlayer_Midi::open(ResourceManager *resMan) {
 	assert(resMan != NULL);
 
@@ -377,6 +500,11 @@
 		return retval;
 	}
 
+	if (_isMt32) {
+		resetMt32();
+		setMt32Volume(80);
+	}
+
 	Resource *res = NULL;
 
 	if (!_isMt32) {
@@ -393,14 +521,19 @@
 
 	if (isMt32GmPatch(res->data, res->size)) {
 		readMt32GmPatch(res->data, res->size);
+		strncpy((char *)_goodbyeMsg, "      ScummVM       ", 20);
 	} else {
-		// TODO
-		warning("Old MT-32 patch format currently not supported");
-		for (uint i = 0; i < 127; i++) {
+		if (!_isMt32) {
+			warning("MT-32 to GM translation not yet supported");
+		}
+
+		readMt32Patch(res->data, res->size);
+
+		// No mapping
+		for (uint i = 0; i < 128; i++) {
 			_percussionMap[i] = i;
 			_patchMap[i] = i;
-			for (uint j = 0; j < 4; j++)
-				_velocityMap[j][i] = i;
+			_velocityMap[0][i] = i;
 			_keyShift[i] = 0;
 			_volAdjust[i] = 0;
 			_velocityMapIdx[i] = 0;
@@ -410,6 +543,29 @@
 	return 0;
 }
 
+void MidiPlayer_Midi::close() {
+	if (_isMt32) {
+		// Send goodbye message
+		sendMt32SysEx(0x200000, _goodbyeMsg, 20);
+	}
+
+	_driver->close();
+}
+
+void MidiPlayer_Midi::sysEx(const byte *msg, uint16 length) {
+	_driver->sysEx(msg, length);
+
+	// Wait the time it takes to send the SysEx data
+	uint32 delay = (length + 2) * 1000 / 3125;
+
+	// Plus an additional delay for the MT-32 rev00
+	if (_isMt32)
+		delay += 40;
+
+	g_system->delayMillis(delay);
+	g_system->updateScreen();
+}
+
 byte MidiPlayer_Midi::getPlayId(SciVersion soundVersion) {
 	switch (soundVersion) {
 	case SCI_VERSION_0_EARLY:

Modified: scummvm/trunk/engines/sci/sound/softseq/mididriver.h
===================================================================
--- scummvm/trunk/engines/sci/sound/softseq/mididriver.h	2010-01-16 16:00:21 UTC (rev 47320)
+++ scummvm/trunk/engines/sci/sound/softseq/mididriver.h	2010-01-16 16:06:41 UTC (rev 47321)
@@ -67,7 +67,11 @@
 class MidiPlayer : public MidiDriver {
 protected:
 	MidiDriver *_driver;
+	byte _reverb;
+
 public:
+	MidiPlayer() : _reverb(0) { }
+
 	int open() {
 		ResourceManager *resMan = ((SciEngine *)g_engine)->getResourceManager();	// HACK
 		return open(resMan);
@@ -93,6 +97,9 @@
 		return _driver ? _driver->property(MIDI_PROP_MASTER_VOLUME, 0xffff) : 0;
  	}
 
+	virtual byte getReverb() { return _reverb; }
+	virtual void setReverb(byte reverb) { _reverb = reverb; }
+
 	virtual void playSwitch(bool play) {
 		if (!play) {
 			// Send "All Sound Off" on all channels


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list