diff options
| author | Martin Kiewitz | 2015-05-30 01:48:30 +0200 | 
|---|---|---|
| committer | Martin Kiewitz | 2015-05-30 01:48:30 +0200 | 
| commit | f80cc4a84d9a1ff4e761438164e94425b4239908 (patch) | |
| tree | 7e913c5d1098cf0c23694a0908c32ed1301937e9 | |
| parent | 508dc14e30c1d30c90a0632ffdaf4a916755d58d (diff) | |
| download | scummvm-rg350-f80cc4a84d9a1ff4e761438164e94425b4239908.tar.gz scummvm-rg350-f80cc4a84d9a1ff4e761438164e94425b4239908.tar.bz2 scummvm-rg350-f80cc4a84d9a1ff4e761438164e94425b4239908.zip  | |
SHERLOCK: add (unfinished) adlib driver
| -rw-r--r-- | engines/sherlock/music.cpp | 112 | ||||
| -rw-r--r-- | engines/sherlock/music.h | 11 | ||||
| -rw-r--r-- | engines/sherlock/scalpel/drivers/adlib.cpp | 532 | ||||
| -rw-r--r-- | engines/sherlock/scalpel/drivers/mididriver.h | 91 | 
4 files changed, 722 insertions, 24 deletions
diff --git a/engines/sherlock/music.cpp b/engines/sherlock/music.cpp index c1aebda2b3..ed047f61f8 100644 --- a/engines/sherlock/music.cpp +++ b/engines/sherlock/music.cpp @@ -23,11 +23,14 @@  #include "common/config-manager.h"  #include "sherlock/sherlock.h"  #include "sherlock/music.h" +#include "sherlock/scalpel/drivers/mididriver.h"  namespace Sherlock {  #define NUM_SONGS 45 +#define USE_SCI_MIDI_PLAYER 1 +  /* This tells which song to play in each room, 0 = no song played */  static const char ROOM_SONG[62] = {  	 0, 20, 43,  6, 11,  2,  8, 15,  6, 28, @@ -59,7 +62,7 @@ MidiParser_SH::MidiParser_SH() {  }  void MidiParser_SH::parseNextEvent(EventInfo &info) { -	warning("parseNextEvent"); +//	warning("parseNextEvent");  	// An attempt to remap MT32 instruments to GMIDI. Only partially successful, it still  	// does not sound even close to the real MT32. Oddly enough, on the actual hardware MT32 @@ -88,13 +91,15 @@ void MidiParser_SH::parseNextEvent(EventInfo &info) {  	info.delta = 0;  	info.event = *_position._playPos++; -	warning("Event %x", info.event); +	//warning("Event %x", info.event);  	_position._runningStatus = info.event;  	switch (info.command()) { -	case 0xC: { +	case 0xC: { // program change  		int idx = *_position._playPos++; -		info.basic.param1 = mt32Map[idx & 0x7f]; // remap MT32 to GM +		info.basic.param1 = idx & 0x7f; +		// don't do this here, it breaks adlib +		//info.basic.param1 = mt32Map[idx & 0x7f]; // remap MT32 to GM  		info.basic.param2 = 0;  		}  		break; @@ -160,14 +165,12 @@ bool MidiParser_SH::loadMusic(byte *data, uint32 size) {  	warning("loadMusic");  	unloadMusic(); -	byte *pos = data; +	byte  *headerPtr  = data; +	byte  *pos        = data; +	uint16 headerSize = READ_LE_UINT16(headerPtr); +	assert(headerSize == 0x7F); -	if (memcmp("            ", pos, 12)) { -		warning("Expected header not found in music file"); -		return false; -	} -	pos += 12; -	byte headerSize = *pos; +	// Skip over header  	pos += headerSize;  	_lastEvent = 0; @@ -190,16 +193,49 @@ Music::Music(SherlockEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {  		_vm->_res->addToCache("MUSIC.LIB");  	MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB | MDT_PREFER_GM); -	_driver = MidiDriver::createMidi(dev); -	assert(_driver); -	int ret = _driver->open(); -	if (ret == 0) { -		_driver->sendGMReset(); -		_driver->setTimerCallback(&_midiParser, &_midiParser.timerCallback); +	_musicType = MidiDriver::getMusicType(dev); + +#if USE_SCI_MIDI_PLAYER +	_pMidiDrv = NULL; +#endif +	_driver = NULL; + +	switch (_musicType) { +	case MT_ADLIB: +#if USE_SCI_MIDI_PLAYER +		_pMidiDrv = MidiPlayer_AdLib_create(); +#else +		_driver = MidiDriver_AdLib_create(); +#endif +		break; +	default: +		_driver = MidiDriver::createMidi(dev); +		break; +	} +#if USE_SCI_MIDI_PLAYER +	if (_pMidiDrv) { +		assert(_pMidiDrv); +		int ret = _pMidiDrv->open(); +		if (ret == 0) { +			_pMidiDrv->setTimerCallback(&_midiParser, &_midiParser.timerCallback); +		} +		_midiParser.setMidiDriver(_pMidiDrv); +		_midiParser.setTimerRate(_pMidiDrv->getBaseTempo()); +	} +#endif + +	if (_driver) { +		assert(_driver); + +		int ret = _driver->open(); +		if (ret == 0) { +			_driver->sendGMReset(); +			_driver->setTimerCallback(&_midiParser, &_midiParser.timerCallback); +		} +		_midiParser.setMidiDriver(_driver); +		_midiParser.setTimerRate(_driver->getBaseTempo());  	} -	_midiParser.setMidiDriver(_driver); -	_midiParser.setTimerRate(_driver->getBaseTempo());  	_musicPlaying = false;  	_musicOn = true; @@ -248,17 +284,49 @@ bool Music::playMusic(const Common::String &name) {  	Common::SeekableReadStream *stream = _vm->_res->load(name, "MUSIC.LIB");  	byte *data = new byte[stream->size()]; -	byte *ptr = data; +	int32 dataSize = stream->size(); +	assert(data); + +	stream->read(data, dataSize); -	stream->read(ptr, stream->size()); +	// for dumping the music tracks +#if 0  	Common::DumpFile outFile;  	outFile.open(name + ".RAW");  	outFile.write(data, stream->size());  	outFile.flush();  	outFile.close(); +#endif -	_midiParser.loadMusic(data, stream->size()); +	if (dataSize < 14) { +		warning("not enough data in music file"); +		return false; +	} + +	byte *dataPos = data; +	if (memcmp("            ", dataPos, 12)) { +		warning("Expected header not found in music file"); +		return false; +	} +	dataPos += 12; +	dataSize -= 12; + +	uint16 headerSize = READ_LE_UINT16(dataPos); +	if (headerSize != 0x7F) { +		warning("music header is not as expected"); +		return false; +	} + +	if (_musicType == MT_ADLIB) { +		if (_driver) +			MidiDriver_AdLib_newMusicData(_driver, dataPos, dataSize); +#if USE_SCI_MIDI_PLAYER +		if (_pMidiDrv) +			MidiPlayer_AdLib_newMusicData(_pMidiDrv, dataPos, dataSize); +#endif +	} +	_midiParser.loadMusic(dataPos, dataSize);  	return true;  } diff --git a/engines/sherlock/music.h b/engines/sherlock/music.h index 51ee7bb84f..a195b26b68 100644 --- a/engines/sherlock/music.h +++ b/engines/sherlock/music.h @@ -25,7 +25,8 @@  #include "audio/midiplayer.h"  #include "audio/midiparser.h" -#include "audio/mididrv.h" +//#include "audio/mididrv.h" +#include "sherlock/scalpel/drivers/mididriver.h"  namespace Sherlock { @@ -44,15 +45,21 @@ public:  	virtual bool loadMusic(byte *data, uint32 size);  }; -class Music : public Audio::MidiPlayer { +class Music {  private:  	SherlockEngine *_vm;  	Audio::Mixer *_mixer;  	MidiParser_SH _midiParser; +	MidiPlayer *_pMidiDrv; +	MidiDriver *_driver;  public:  	bool _musicPlaying;  	bool _musicOn; + +private: +	MusicType _musicType; +  public:  	Music(SherlockEngine *vm, Audio::Mixer *mixer); diff --git a/engines/sherlock/scalpel/drivers/adlib.cpp b/engines/sherlock/scalpel/drivers/adlib.cpp new file mode 100644 index 0000000000..7ee5256138 --- /dev/null +++ b/engines/sherlock/scalpel/drivers/adlib.cpp @@ -0,0 +1,532 @@ +/* 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 "sherlock/sherlock.h" +#include "sherlock/scalpel/drivers/mididriver.h" + +#include "common/file.h" +#include "common/system.h" +#include "common/textconsole.h" + +#include "audio/fmopl.h" +#include "audio/softsynth/emumidi.h" + +namespace Sherlock { + +#define USE_SCI_MIDI_PLAYER 1 + +#define SHERLOCK_ADLIB_VOICES_COUNT 9 +#define SHERLOCK_ADLIB_NOTES_COUNT 96 + +byte adlib_Operator1Register[SHERLOCK_ADLIB_VOICES_COUNT] = { +	0x00, 0x01, 0x02, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12 +}; + +byte adlib_Operator2Register[SHERLOCK_ADLIB_VOICES_COUNT] = { +	0x03, 0x04, 0x05, 0x0B, 0x0C, 0x0D, 0x13, 0x14, 0x15 +}; + +struct adlib_InstrumentEntry { +	byte reg20op1; +	byte reg40op1; +	byte reg60op1; +	byte reg80op1; +	byte regE0op1; +	byte reg20op2; +	byte reg40op2; +	byte reg60op2; +	byte reg80op2; +	byte regE0op2; +	byte regC0; +	byte frequencyAdjust; +}; + +// hardcoded, dumped from ADHOM.DRV +const adlib_InstrumentEntry adlib_instrumentTable[] = { +	{ 0x71, 0x89, 0x51, 0x11, 0x00, 0x61, 0x23, 0x42, 0x15, 0x01, 0x02, 0xF4 }, +	{ 0x22, 0x20, 0x97, 0x89, 0x00, 0xA2, 0x1F, 0x70, 0x07, 0x00, 0x0A, 0xF4 }, +	{ 0x70, 0x1A, 0x64, 0x13, 0x00, 0x20, 0x1F, 0x53, 0x46, 0x00, 0x0E, 0xF4 }, +	{ 0xB6, 0x4A, 0xB6, 0x32, 0x00, 0x11, 0x2B, 0xD1, 0x31, 0x00, 0x0E, 0xE8 }, +	{ 0x71, 0x8B, 0x51, 0x11, 0x00, 0x61, 0x20, 0x32, 0x35, 0x01, 0x02, 0xF4 }, +	{ 0x71, 0x8A, 0x51, 0x11, 0x00, 0x61, 0x20, 0x32, 0x25, 0x01, 0x02, 0xF4 }, +	{ 0x23, 0x0F, 0xF4, 0x04, 0x02, 0x2F, 0x25, 0xF0, 0x43, 0x00, 0x06, 0xE8 }, +	{ 0x71, 0x1C, 0x71, 0x03, 0x00, 0x21, 0x1F, 0x54, 0x17, 0x00, 0x0E, 0xF4 }, +	{ 0x71, 0x8A, 0x6E, 0x17, 0x00, 0x25, 0x27, 0x6B, 0x0E, 0x00, 0x02, 0xF4 }, +	{ 0x71, 0x1D, 0x81, 0x03, 0x00, 0x21, 0x1F, 0x64, 0x17, 0x00, 0x0E, 0xF4 }, +	{ 0x01, 0x4B, 0xF1, 0x50, 0x00, 0x01, 0x23, 0xD2, 0x76, 0x00, 0x06, 0xF4 }, +	{ 0x2F, 0xCA, 0xF8, 0xE5, 0x00, 0x21, 0x1F, 0xC0, 0xFF, 0x00, 0x00, 0xF4 }, +	{ 0x29, 0xCD, 0xF0, 0x91, 0x00, 0x21, 0x1F, 0xE0, 0x86, 0x00, 0x02, 0xF4 }, +	{ 0x24, 0xD0, 0xF0, 0x01, 0x00, 0x21, 0x1F, 0xE0, 0x86, 0x00, 0x02, 0xF4 }, +	{ 0x23, 0xC8, 0xF0, 0x01, 0x00, 0x21, 0x1F, 0xE0, 0x86, 0x00, 0x02, 0xF4 }, +	{ 0x64, 0xC9, 0xB0, 0x01, 0x00, 0x61, 0x1F, 0xF0, 0x86, 0x00, 0x02, 0xF4 }, +	{ 0x33, 0x85, 0xA1, 0x10, 0x00, 0x15, 0x9F, 0x72, 0x23, 0x00, 0x08, 0xF4 }, +	{ 0x31, 0x85, 0xA1, 0x10, 0x00, 0x15, 0x9F, 0x73, 0x33, 0x00, 0x08, 0xF4 }, +	{ 0x31, 0x81, 0xA1, 0x30, 0x00, 0x16, 0x9F, 0xC2, 0x74, 0x00, 0x08, 0xF4 }, +	{ 0x03, 0x8A, 0xF0, 0x7B, 0x00, 0x02, 0x9F, 0xF4, 0x7B, 0x00, 0x08, 0xF4 }, +	{ 0x03, 0x8A, 0xF0, 0x7B, 0x00, 0x01, 0x9F, 0xF4, 0x7B, 0x00, 0x08, 0xF4 }, +	{ 0x23, 0x8A, 0xF2, 0x7B, 0x00, 0x01, 0x9F, 0xF4, 0x7B, 0x00, 0x08, 0xF4 }, +	{ 0x32, 0x80, 0x01, 0x10, 0x00, 0x12, 0x9F, 0x72, 0x33, 0x00, 0x08, 0xF4 }, +	{ 0x32, 0x80, 0x01, 0x10, 0x00, 0x14, 0x9F, 0x73, 0x33, 0x00, 0x08, 0xF4 }, +	{ 0x31, 0x16, 0x73, 0x8E, 0x00, 0x21, 0x1F, 0x80, 0x9E, 0x00, 0x0E, 0xF4 }, +	{ 0x30, 0x16, 0x73, 0x7E, 0x00, 0x21, 0x1F, 0x80, 0x9E, 0x00, 0x0E, 0x00 }, +	{ 0x31, 0x94, 0x33, 0x73, 0x00, 0x21, 0x1F, 0xA0, 0x97, 0x00, 0x0E, 0xF4 }, +	{ 0x31, 0x94, 0xD3, 0x73, 0x00, 0x21, 0x20, 0xA0, 0x97, 0x00, 0x0E, 0xF4 }, +	{ 0x31, 0x45, 0xF1, 0x53, 0x00, 0x32, 0x1F, 0xF2, 0x27, 0x00, 0x06, 0xF4 }, +	{ 0x13, 0x0C, 0xF2, 0x01, 0x00, 0x15, 0x2F, 0xF2, 0xB6, 0x00, 0x08, 0xF4 }, +	{ 0x11, 0x0C, 0xF2, 0x01, 0x00, 0x11, 0x1F, 0xF2, 0xB6, 0x00, 0x08, 0xF4 }, +	{ 0x11, 0x0A, 0xFE, 0x04, 0x00, 0x11, 0x1F, 0xF2, 0xBD, 0x00, 0x08, 0xF4 }, +	{ 0x16, 0x4D, 0xFA, 0x11, 0x00, 0xE1, 0x20, 0xF1, 0xF1, 0x00, 0x08, 0xF4 }, +	{ 0x16, 0x40, 0xBA, 0x11, 0x00, 0xF1, 0x20, 0x24, 0x31, 0x00, 0x08, 0xF4 }, +	{ 0x61, 0xA7, 0x72, 0x8E, 0x00, 0xE1, 0x9F, 0x50, 0x1A, 0x00, 0x02, 0xF4 }, +	{ 0x18, 0x4D, 0x32, 0x13, 0x00, 0xE1, 0x20, 0x51, 0xE3, 0x00, 0x08, 0xF4 }, +	{ 0x17, 0xC0, 0x12, 0x41, 0x00, 0x31, 0x9F, 0x13, 0x31, 0x00, 0x06, 0xF4 }, +	{ 0x03, 0x8F, 0xF5, 0x55, 0x00, 0x21, 0x9F, 0xF3, 0x33, 0x00, 0x00, 0xF4 }, +	{ 0x13, 0x4D, 0xFA, 0x11, 0x00, 0xE1, 0x20, 0xF1, 0xF1, 0x00, 0x08, 0xF4 }, +	{ 0x11, 0x43, 0x20, 0x15, 0x00, 0xF1, 0x20, 0x31, 0xF8, 0x00, 0x08, 0xF4 }, +	{ 0x11, 0x03, 0x82, 0x97, 0x00, 0xE4, 0x60, 0xF0, 0xF2, 0x00, 0x08, 0xF4 }, +	{ 0x05, 0x40, 0xD1, 0x53, 0x00, 0x14, 0x1F, 0x51, 0x71, 0x00, 0x06, 0xF4 }, +	{ 0xF1, 0x01, 0x77, 0x17, 0x00, 0x21, 0x1F, 0x81, 0x18, 0x00, 0x02, 0xF4 }, +	{ 0xF1, 0x18, 0x32, 0x11, 0x00, 0xE1, 0x1F, 0xF1, 0x13, 0x00, 0x00, 0xF4 }, +	{ 0x73, 0x48, 0xF1, 0x53, 0x00, 0x71, 0x1F, 0xF1, 0x06, 0x00, 0x08, 0xF4 }, +	{ 0x71, 0x8D, 0x71, 0x11, 0x00, 0x61, 0x5F, 0x72, 0x15, 0x00, 0x06, 0xF4 }, +	{ 0xD7, 0x4F, 0xF2, 0x61, 0x00, 0xD2, 0x1F, 0xF1, 0xB2, 0x00, 0x08, 0xF4 }, +	{ 0x01, 0x11, 0xF0, 0xFF, 0x00, 0x01, 0x1F, 0xF0, 0xF8, 0x00, 0x0A, 0xF4 }, +	{ 0x31, 0x8B, 0x41, 0x11, 0x00, 0x61, 0x1F, 0x22, 0x13, 0x00, 0x06, 0xF4 }, +	{ 0x71, 0x1C, 0x71, 0x03, 0x00, 0x21, 0x1F, 0x64, 0x07, 0x00, 0x0E, 0xF4 }, +	{ 0x31, 0x8B, 0x41, 0x11, 0x00, 0x61, 0x1F, 0x32, 0x15, 0x00, 0x02, 0xF4 }, +	{ 0x71, 0x1C, 0xFD, 0x13, 0x00, 0x21, 0x1F, 0xE7, 0xD6, 0x00, 0x0E, 0xF4 }, +	{ 0x71, 0x1C, 0x51, 0x03, 0x00, 0x21, 0x1F, 0x54, 0x67, 0x00, 0x0E, 0xF4 }, +	{ 0x71, 0x1C, 0x51, 0x03, 0x00, 0x21, 0x1F, 0x54, 0x17, 0x00, 0x0E, 0xF4 }, +	{ 0x71, 0x1C, 0x54, 0x15, 0x00, 0x21, 0x1F, 0x53, 0x49, 0x00, 0x0E, 0xF4 }, +	{ 0x71, 0x56, 0x51, 0x03, 0x00, 0x61, 0x1F, 0x54, 0x17, 0x00, 0x0E, 0xF4 }, +	{ 0x71, 0x1C, 0x51, 0x03, 0x00, 0x21, 0x1F, 0x54, 0x17, 0x00, 0x0E, 0xF4 }, +	{ 0x02, 0x29, 0xF5, 0x75, 0x00, 0x01, 0x9F, 0xF2, 0xF3, 0x00, 0x00, 0xF4 }, +	{ 0x02, 0x29, 0xF0, 0x75, 0x00, 0x01, 0x9F, 0xF4, 0x33, 0x00, 0x00, 0xF4 }, +	{ 0x01, 0x49, 0xF1, 0x53, 0x00, 0x11, 0x1F, 0xF1, 0x74, 0x00, 0x06, 0xF4 }, +	{ 0x01, 0x89, 0xF1, 0x53, 0x00, 0x11, 0x1F, 0xF1, 0x74, 0x00, 0x06, 0xF4 }, +	{ 0x02, 0x89, 0xF1, 0x53, 0x00, 0x11, 0x1F, 0xF1, 0x74, 0x00, 0x06, 0xF4 }, +	{ 0x02, 0x80, 0xF1, 0x53, 0x00, 0x11, 0x1F, 0xF1, 0x74, 0x00, 0x06, 0xF4 }, +	{ 0x01, 0x40, 0xF1, 0x53, 0x00, 0x08, 0x5F, 0xF1, 0x53, 0x00, 0x00, 0xF4 }, +	{ 0x21, 0x15, 0xD3, 0x2C, 0x00, 0x21, 0x9F, 0xC3, 0x2C, 0x00, 0x0A, 0xF4 }, +	{ 0x01, 0x18, 0xD4, 0xF2, 0x00, 0x21, 0x9F, 0xC4, 0x8A, 0x00, 0x0A, 0xF4 }, +	{ 0x01, 0x4E, 0xF0, 0x7B, 0x00, 0x11, 0x1F, 0xF4, 0xC8, 0x00, 0x04, 0xF4 }, +	{ 0x01, 0x44, 0xF0, 0xAB, 0x00, 0x11, 0x1F, 0xF3, 0xAB, 0x00, 0x04, 0xF4 }, +	{ 0x53, 0x0E, 0xF4, 0xC8, 0x00, 0x11, 0x1F, 0xF1, 0xBB, 0x00, 0x04, 0xF4 }, +	{ 0x53, 0x0B, 0xF2, 0xC8, 0x00, 0x11, 0x1F, 0xF2, 0xC5, 0x00, 0x04, 0xF4 }, +	{ 0x21, 0x15, 0xB4, 0x4C, 0x00, 0x21, 0x1F, 0x94, 0xAC, 0x00, 0x0A, 0xF4 }, +	{ 0x21, 0x15, 0x94, 0x1C, 0x00, 0x21, 0x1F, 0x64, 0xAC, 0x00, 0x0A, 0xF4 }, +	{ 0x22, 0x1B, 0x97, 0x89, 0x00, 0xA2, 0x1F, 0x70, 0x07, 0x00, 0x0A, 0xF4 }, +	{ 0x21, 0x19, 0x77, 0xBF, 0x00, 0xA1, 0x9F, 0x60, 0x2A, 0x00, 0x06, 0xF4 }, +	{ 0xA1, 0x13, 0xD6, 0xAF, 0x00, 0xE2, 0x9F, 0x60, 0x2A, 0x00, 0x02, 0xF4 }, +	{ 0xA2, 0x1D, 0x95, 0x24, 0x00, 0xE2, 0x9F, 0x60, 0x2A, 0x00, 0x02, 0xF4 }, +	{ 0x32, 0x9A, 0x51, 0x19, 0x00, 0x61, 0x9F, 0x60, 0x39, 0x00, 0x0C, 0xF4 }, +	{ 0xA4, 0x12, 0xF4, 0x30, 0x00, 0xE2, 0x9F, 0x60, 0x2A, 0x00, 0x02, 0xF4 }, +	{ 0x21, 0x16, 0x63, 0x0E, 0x00, 0x21, 0x1F, 0x63, 0x0E, 0x00, 0x0C, 0xF4 }, +	{ 0x31, 0x16, 0x63, 0x0A, 0x00, 0x21, 0x1F, 0x63, 0x0B, 0x00, 0x0C, 0xF4 }, +	{ 0x21, 0x1B, 0x63, 0x0A, 0x00, 0x21, 0x1F, 0x63, 0x0B, 0x00, 0x0C, 0xF4 }, +	{ 0x20, 0x1B, 0x63, 0x0A, 0x00, 0x21, 0x1F, 0x63, 0x0B, 0x00, 0x0C, 0xF4 }, +	{ 0x32, 0x1C, 0x82, 0x18, 0x00, 0x61, 0x9F, 0x60, 0x07, 0x00, 0x0C, 0xF4 }, +	{ 0x32, 0x18, 0x61, 0x14, 0x00, 0xE1, 0x9F, 0x72, 0x16, 0x00, 0x0C, 0xF4 }, +	{ 0x31, 0xC0, 0x77, 0x17, 0x00, 0x22, 0x1F, 0x6B, 0x09, 0x00, 0x02, 0xF4 }, +	{ 0x71, 0xC3, 0x8E, 0x17, 0x00, 0x22, 0x24, 0x8B, 0x0E, 0x00, 0x02, 0xF4 }, +	{ 0x70, 0x8D, 0x6E, 0x17, 0x00, 0x22, 0x1F, 0x6B, 0x0E, 0x00, 0x02, 0xF4 }, +	{ 0x24, 0x4F, 0xF2, 0x06, 0x00, 0x31, 0x1F, 0x52, 0x06, 0x00, 0x0E, 0xF4 }, +	{ 0x31, 0x1B, 0x64, 0x07, 0x00, 0x61, 0x1F, 0xD0, 0x67, 0x00, 0x0E, 0xF4 }, +	{ 0x31, 0x1B, 0x61, 0x06, 0x00, 0x61, 0x1F, 0xD2, 0x36, 0x00, 0x0C, 0xF4 }, +	{ 0x31, 0x1F, 0x31, 0x06, 0x00, 0x61, 0x1F, 0x50, 0x36, 0x00, 0x0C, 0xF4 }, +	{ 0x31, 0x1F, 0x41, 0x06, 0x00, 0x61, 0x1F, 0xA0, 0x36, 0x00, 0x0C, 0xF4 }, +	{ 0x21, 0x9A, 0x53, 0x56, 0x00, 0x21, 0x9F, 0xA0, 0x16, 0x00, 0x0E, 0xF4 }, +	{ 0x21, 0x9A, 0x53, 0x56, 0x00, 0x21, 0x9F, 0xA0, 0x16, 0x00, 0x0E, 0xF4 }, +	{ 0x61, 0x19, 0x53, 0x58, 0x00, 0x21, 0x1F, 0xA0, 0x18, 0x00, 0x0C, 0xF4 }, +	{ 0x61, 0x19, 0x73, 0x57, 0x00, 0x21, 0x1F, 0xA0, 0x17, 0x00, 0x0C, 0xF4 }, +	{ 0x21, 0x1B, 0x71, 0xA6, 0x00, 0x21, 0x1F, 0xA1, 0x96, 0x00, 0x0E, 0xF4 }, +	{ 0x85, 0x91, 0xF5, 0x44, 0x00, 0xA1, 0x1F, 0xF0, 0x45, 0x00, 0x06, 0xF4 }, +	{ 0x07, 0x51, 0xF5, 0x33, 0x00, 0x61, 0x1F, 0xF0, 0x25, 0x00, 0x06, 0xF4 }, +	{ 0x13, 0x8C, 0xFF, 0x21, 0x00, 0x11, 0x9F, 0xFF, 0x03, 0x00, 0x0E, 0xF4 }, +	{ 0x38, 0x8C, 0xF3, 0x0D, 0x00, 0xB1, 0x5F, 0xF5, 0x33, 0x00, 0x0E, 0xF4 }, +	{ 0x87, 0x91, 0xF5, 0x55, 0x00, 0x22, 0x1F, 0xF0, 0x54, 0x00, 0x06, 0xF4 }, +	{ 0xB6, 0x4A, 0xB6, 0x32, 0x00, 0x11, 0x2B, 0xD1, 0x31, 0x00, 0x0E, 0xF4 }, +	{ 0x04, 0x00, 0xFE, 0xF0, 0x00, 0xC2, 0x1F, 0xF6, 0xB5, 0x00, 0x0E, 0xF4 }, +	{ 0x05, 0x4E, 0xDA, 0x15, 0x00, 0x01, 0x9F, 0xF0, 0x13, 0x00, 0x0A, 0xF4 }, +	{ 0x31, 0x44, 0xF2, 0x9A, 0x00, 0x32, 0x1F, 0xF0, 0x27, 0x00, 0x06, 0xF4 }, +	{ 0xB0, 0xC4, 0xA4, 0x02, 0x00, 0xD7, 0x9F, 0x40, 0x42, 0x00, 0x00, 0xF4 }, +	{ 0xCA, 0x84, 0xF0, 0xF0, 0x00, 0xCF, 0x1F, 0x59, 0x62, 0x00, 0x0C, 0xF4 }, +	{ 0x30, 0x35, 0xF5, 0xF0, 0x00, 0x35, 0x1F, 0xF0, 0x9B, 0x00, 0x02, 0xF4 }, +	{ 0x63, 0x0F, 0xF4, 0x04, 0x02, 0x6F, 0x1F, 0xF0, 0x43, 0x00, 0x06, 0xF4 }, +	{ 0x07, 0x40, 0x09, 0x53, 0x00, 0x05, 0x1F, 0xF6, 0x94, 0x00, 0x0E, 0xF4 }, +	{ 0x09, 0x4E, 0xDA, 0x25, 0x00, 0x01, 0x1F, 0xF1, 0x15, 0x00, 0x0A, 0xF4 }, +	{ 0x04, 0x00, 0xF3, 0xA0, 0x02, 0x04, 0x1F, 0xF8, 0x46, 0x00, 0x0E, 0xF4 }, +	{ 0x07, 0x00, 0xF0, 0xF0, 0x00, 0x00, 0x1F, 0x5C, 0xDC, 0x00, 0x0E, 0xF4 }, +	{ 0x1F, 0x1E, 0xE5, 0x5B, 0x00, 0x0F, 0x1F, 0x5D, 0xFA, 0x00, 0x0E, 0xF4 }, +	{ 0x11, 0x8A, 0xF1, 0x11, 0x00, 0x01, 0x5F, 0xF1, 0xB3, 0x00, 0x06, 0xF4 }, +	{ 0x00, 0x40, 0xD1, 0x53, 0x00, 0x00, 0x1F, 0xF2, 0x56, 0x00, 0x0E, 0xF4 }, +	{ 0x32, 0x44, 0xF8, 0xFF, 0x00, 0x11, 0x1F, 0xF5, 0x7F, 0x00, 0x0E, 0xF4 }, +	{ 0x00, 0x40, 0x09, 0x53, 0x00, 0x02, 0x1F, 0xF7, 0x94, 0x00, 0x0E, 0xF4 }, +	{ 0x11, 0x86, 0xF2, 0xA8, 0x00, 0x01, 0x9F, 0xA0, 0xA8, 0x00, 0x08, 0xF4 }, +	{ 0x00, 0x50, 0xF2, 0x70, 0x00, 0x13, 0x1F, 0xF2, 0x72, 0x00, 0x0E, 0xF4 }, +	{ 0xF0, 0x00, 0x11, 0x11, 0x00, 0xE0, 0xDF, 0x11, 0x11, 0x00, 0x0E, 0xF4 } +}; + +// hardcoded, dumped from ADHOM.DRV +uint16 adlib_FrequencyLookUpTable[SHERLOCK_ADLIB_NOTES_COUNT] = { +	0x0158, 0x016C, 0x0182, 0x0199, 0x01B1, 0x01CB, 0x01E6, 0x0203, 0x0222, 0x0242, +	0x0265, 0x0289, 0x0558, 0x056C, 0x0582, 0x0599, 0x05B1, 0x05CB, 0x05E6, 0x0603, +	0x0622, 0x0642, 0x0665, 0x0689, 0x0958, 0x096C, 0x0982, 0x0999, 0x09B1, 0x09CB, +	0x09E6, 0x0A03, 0x0A22, 0x0A42, 0x0A65, 0x0A89, 0x0D58, 0x0D6C, 0x0D82, 0x0D99, +	0x0DB1, 0x0DCB, 0x0DE6, 0x0E03, 0x0E22, 0x0E42, 0x0E65, 0x0E89, 0x1158, 0x116C, +	0x1182, 0x1199, 0x11B1, 0x11CB, 0x11E6, 0x1203, 0x1222, 0x1242, 0x1265, 0x1289, +	0x1558, 0x156C, 0x1582, 0x1599, 0x15B1, 0x15CB, 0x15E6, 0x1603, 0x1622, 0x1642, +	0x1665, 0x1689, 0x1958, 0x196C, 0x1982, 0x1999, 0x19B1, 0x19CB, 0x19E6, 0x1A03, +	0x1A22, 0x1A42, 0x1A65, 0x1A89, 0x1D58, 0x1D6C, 0x1D82, 0x1D99, 0x1DB1, 0x1DCB, +	0x1DE6, 0x1E03, 0x1E22, 0x1E42, 0x1E65, 0x1E89 +}; + +class MidiDriver_AdLib : public MidiDriver_Emulated { +public: +	MidiDriver_AdLib(Audio::Mixer *mixer) +		: MidiDriver_Emulated(mixer), _masterVolume(15), _rhythmKeyMap(0), _opl(0) { +		memset(_voiceChannelMapping, 0, sizeof(_voiceChannelMapping)); +	} +	virtual ~MidiDriver_AdLib() { } + +	// MidiDriver +	int open(); +	void close(); +	void send(uint32 b); +	MidiChannel *allocateChannel() { return NULL; } +	MidiChannel *getPercussionChannel() { return NULL; } + +	// AudioStream +	bool isStereo() const { return false; } +	int getRate() const { return _mixer->getOutputRate(); } +	int getPolyphony() const { return SHERLOCK_ADLIB_VOICES_COUNT; } +	bool hasRhythmChannel() const { return false; } + +	// MidiDriver_Emulated +	void generateSamples(int16 *buf, int len); + +	void setVolume(byte volume); +	virtual uint32 property(int prop, uint32 param); + +	bool useRhythmChannel() const { return _rhythmKeyMap != NULL; } + +	void newMusicData(byte *musicData, int32 musicDataSize); + +private: +	struct adlib_ChannelEntry { +		bool inUse; +		const adlib_InstrumentEntry *currentInstrumentPtr; +		byte currentNote; +		byte currentA0hReg; +		byte currentB0hReg; + +		adlib_ChannelEntry() : inUse(false), currentInstrumentPtr(NULL), currentNote(0), +								currentA0hReg(0), currentB0hReg(0) { } +	}; + +	OPL::OPL *_opl; +	int _masterVolume; +	byte *_rhythmKeyMap; + +	// points to a MIDI channel for each of the new voice channels +	byte _voiceChannelMapping[SHERLOCK_ADLIB_VOICES_COUNT]; + +	// stores information about all FM voice channels +	adlib_ChannelEntry _channels[SHERLOCK_ADLIB_VOICES_COUNT]; + +	void programChange(byte channel, byte parameter); +	void setRegister(int reg, int value); +	void noteOn(byte channel, byte note, byte velocity); +	void noteOff(byte channel, byte note); +	void voiceOnOff(byte FMVoiceChannel, bool KeyOn, byte note, byte velocity); +}; + +#if USE_SCI_MIDI_PLAYER +class MidiPlayer_AdLib : public MidiPlayer { +public: +	MidiPlayer_AdLib() : MidiPlayer() { _driver = new MidiDriver_AdLib(g_system->getMixer()); } +	~MidiPlayer_AdLib() { +		delete _driver; +		_driver = 0; +	} + +	int open(); +	void close(); + +	byte getPlayId() const; +	int getPolyphony() const { return SHERLOCK_ADLIB_VOICES_COUNT; } +	bool hasRhythmChannel() const { return false; } +	void setVolume(byte volume) { static_cast<MidiDriver_AdLib *>(_driver)->setVolume(volume); } + +	//int getLastChannel() const { return (static_cast<const MidiDriver_AdLib *>(_driver)->useRhythmChannel() ? 8 : 15); } + +	void newMusicData(byte *musicData, int32 musicDataSize) { static_cast<MidiDriver_AdLib *>(_driver)->newMusicData(musicData, musicDataSize); } +}; +#endif + +int MidiDriver_AdLib::open() { +	int rate = _mixer->getOutputRate(); + +	debug(3, "ADLIB: Starting driver"); + +	_opl = OPL::Config::create(OPL::Config::kOpl2); + +	if (!_opl) +		return -1; + +	_opl->init(rate); + +	setRegister(0xBD, 0); +	setRegister(0x08, 0); +	setRegister(0x01, 0x20); + +	MidiDriver_Emulated::open(); + +	_mixer->playStream(Audio::Mixer::kPlainSoundType, &_mixerSoundHandle, this, -1, _mixer->kMaxChannelVolume, 0, DisposeAfterUse::NO); + +	return 0; +} + +void MidiDriver_AdLib::close() { +	_mixer->stopHandle(_mixerSoundHandle); + +	delete _opl; +	delete[] _rhythmKeyMap; +} + +void MidiDriver_AdLib::setVolume(byte volume) { +	_masterVolume = volume; +	//renewNotes(-1, true); +} + +// Called when a music track got loaded into memory +void MidiDriver_AdLib::newMusicData(byte *musicData, int32 musicDataSize) { +	assert(musicDataSize >= 0x7F); +	// MIDI Channel <-> FM Voice Channel mapping at offset 0x22 of music data +	memcpy(&_voiceChannelMapping, musicData + 0x22, 9); + +	// reset OPL here? +	// reset current channel data +	memset(&_channels, 0, sizeof(_channels)); +} + +// MIDI messages can be found at http://www.midi.org/techspecs/midimessages.php +void MidiDriver_AdLib::send(uint32 b) { +	byte command = b & 0xf0; +	byte channel = b & 0xf; +	byte op1 = (b >> 8) & 0xff; +	byte op2 = (b >> 16) & 0xff; + +	switch (command) { +	case 0x80: +		noteOff(channel, op1); +		break; +	case 0x90: +		noteOn(channel, op1, op2); +		break; +	case 0xb0: // Control change +		// Doesn't seem to be implemented in the Sherlock Holmes adlib driver +		break; +	case 0xc0: // Program Change +		programChange(channel, op1); +		break; +	case 0xa0: // Polyphonic key pressure (aftertouch) +	case 0xd0: // Channel pressure (aftertouch) +		// Aftertouch doesn't seem to be implemented in the Sherlock Holmes adlib driver +		break; +	case 0xe0: +		// TODO: Implement this, occurs right in the intro, second scene +		warning("pitch bend change"); +		break; +	case 0xf0: // SysEx +		warning("SysEx: %lx", b); +		break; +	default: +		warning("ADLIB: Unknown event %02x", command); +	} +} + +void MidiDriver_AdLib::generateSamples(int16 *data, int len) { +	_opl->readBuffer(data, len); +} + +void MidiDriver_AdLib::noteOn(byte MIDIchannel, byte note, byte velocity) { +	if (velocity == 0) +		return noteOff(MIDIchannel, note); + +	if (MIDIchannel != 9) { +		// Not Percussion +		for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) { +			if (_voiceChannelMapping[FMvoiceChannel] == MIDIchannel) { +				if (!_channels[FMvoiceChannel].inUse) { +					_channels[FMvoiceChannel].inUse = true; +					_channels[FMvoiceChannel].currentNote = note; + +					voiceOnOff(FMvoiceChannel, true, note, velocity); +					return; +				} +			} +		} +	} +	warning("MIDI channel not mapped/all FM voice channels busy %d", MIDIchannel); +} + +void MidiDriver_AdLib::noteOff(byte MIDIchannel, byte note) { +	for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) { +		if (_voiceChannelMapping[FMvoiceChannel] == MIDIchannel) { +			if (_channels[FMvoiceChannel].currentNote == note) { +				_channels[FMvoiceChannel].inUse = false; + +				voiceOnOff(FMvoiceChannel, false, note, 0); +				return; +			} +		} +	} +} + +void MidiDriver_AdLib::voiceOnOff(byte FMvoiceChannel, bool keyOn, byte note, byte velocity) { +	byte frequencyOffset = 0; +	uint16 frequency = 0; +	byte op2RegAdjust = 0; +	byte regValue40h = 0; +	byte regValueA0h = 0; +	byte regValueB0h = 0; + +	// Look up frequency +	if (_channels[FMvoiceChannel].currentInstrumentPtr) { +		frequencyOffset = note + _channels[FMvoiceChannel].currentInstrumentPtr->frequencyAdjust; +	} else { +		frequencyOffset = note; +	} +	if (frequencyOffset >= SHERLOCK_ADLIB_NOTES_COUNT) { +		error("bad note!"); +	} +	frequency = adlib_FrequencyLookUpTable[frequencyOffset]; + +	if (keyOn) { +		// adjust register 40h +		if (_channels[FMvoiceChannel].currentInstrumentPtr) { +			regValue40h = _channels[FMvoiceChannel].currentInstrumentPtr->reg40op2; +		} +		regValue40h = regValue40h - (velocity >> 3); +		op2RegAdjust = adlib_Operator2Register[FMvoiceChannel]; +		setRegister(0x40 + op2RegAdjust, regValue40h); +	} + +	regValueA0h = frequency & 0xFF; +	regValueB0h = frequency >> 8; +	if (keyOn) { +		regValueB0h |= 0x20; // set Key-On flag +	} + +	setRegister(0xA0 + FMvoiceChannel, regValueA0h); +	setRegister(0xB0 + FMvoiceChannel, regValueB0h); +	_channels[FMvoiceChannel].currentA0hReg = regValueA0h; +	_channels[FMvoiceChannel].currentB0hReg = regValueB0h; +} + +void MidiDriver_AdLib::programChange(byte MIDIchannel, byte op1) { +	const adlib_InstrumentEntry *instrumentPtr; +	byte op1Reg = 0; +	byte op2Reg = 0; + +	// setup instrument +	instrumentPtr = &adlib_instrumentTable[op1]; +	//warning("program change for MIDI channel %d, instrument id %d", MIDIchannel, op1); + +	for (byte FMvoiceChannel = 0; FMvoiceChannel < SHERLOCK_ADLIB_VOICES_COUNT; FMvoiceChannel++) { +		if (_voiceChannelMapping[FMvoiceChannel] == MIDIchannel) { + +			op1Reg = adlib_Operator1Register[FMvoiceChannel]; +			op2Reg = adlib_Operator2Register[FMvoiceChannel]; + +			setRegister(0x20 + op1Reg, instrumentPtr->reg20op1); +			setRegister(0x40 + op1Reg, instrumentPtr->reg40op1); +			setRegister(0x60 + op1Reg, instrumentPtr->reg60op1); +			setRegister(0x80 + op1Reg, instrumentPtr->reg80op1); +			setRegister(0xE0 + op1Reg, instrumentPtr->regE0op1); + +			setRegister(0x20 + op2Reg, instrumentPtr->reg20op2); +			setRegister(0x40 + op2Reg, instrumentPtr->reg40op2); +			setRegister(0x60 + op2Reg, instrumentPtr->reg60op2); +			setRegister(0x80 + op2Reg, instrumentPtr->reg80op2); +			setRegister(0xE0 + op2Reg, instrumentPtr->regE0op2); + +			setRegister(0xC0 + FMvoiceChannel, instrumentPtr->regC0); + +			// Remember instrument +			_channels[FMvoiceChannel].currentInstrumentPtr = instrumentPtr; +		} +	} +} +void MidiDriver_AdLib::setRegister(int reg, int value) { +	_opl->write(0x220, reg); +	_opl->write(0x221, value); +} + +uint32 MidiDriver_AdLib::property(int prop, uint32 param) { +#if 0 +	switch(prop) { +	case MIDI_PROP_MASTER_VOLUME: +		if (param != 0xffff) +			_masterVolume = param; +		return _masterVolume; +	default: +		break; +	} +#endif +	return 0; +} + +#if USE_SCI_MIDI_PLAYER +int MidiPlayer_AdLib::open() { +	return static_cast<MidiDriver_AdLib *>(_driver)->open(); +} + +void MidiPlayer_AdLib::close() { +	if (_driver) { +		_driver->close(); +	} +} + +byte MidiPlayer_AdLib::getPlayId() const { +	return 0x00; +} + +MidiPlayer *MidiPlayer_AdLib_create() { +	return new MidiPlayer_AdLib(); +} + +void MidiPlayer_AdLib_newMusicData(MidiPlayer *driver, byte *musicData, int32 musicDataSize) { +	static_cast<MidiPlayer_AdLib *>(driver)->newMusicData(musicData, musicDataSize); +} +#endif + +MidiDriver *MidiDriver_AdLib_create() { +	return new MidiDriver_AdLib(g_system->getMixer()); +} + +void MidiDriver_AdLib_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize) { +	static_cast<MidiDriver_AdLib *>(driver)->newMusicData(musicData, musicDataSize); +} + +} // End of namespace Sci diff --git a/engines/sherlock/scalpel/drivers/mididriver.h b/engines/sherlock/scalpel/drivers/mididriver.h new file mode 100644 index 0000000000..f1366f8ebc --- /dev/null +++ b/engines/sherlock/scalpel/drivers/mididriver.h @@ -0,0 +1,91 @@ +/* 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 SHERLOCK_SOFTSEQ_MIDIDRIVER_H +#define SHERLOCK_SOFTSEQ_MIDIDRIVER_H + +#include "sherlock/sherlock.h" +//#include "audio/mididrv.h" +#include "common/error.h" + +namespace Sherlock { + +#define USE_SCI_MIDIPLAYER 1 + +#if USE_SCI_MIDIPLAYER +enum { +	MIDI_CHANNELS = 16, +	MIDI_PROP_MASTER_VOLUME = 0 +}; + +#define MIDI_RHYTHM_CHANNEL 9 + +class MidiPlayer : public MidiDriver_BASE { +protected: +	MidiDriver *_driver; +	int8 _reverb; + +public: +	MidiPlayer() : _driver(0), _reverb(-1) { } + +	virtual int open() { return _driver->open(); } +	virtual void close() { _driver->close(); } +	virtual void send(uint32 b) { _driver->send(b); } +	virtual uint32 getBaseTempo() { return _driver->getBaseTempo(); } +	virtual bool hasRhythmChannel() const = 0; +	virtual void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) { _driver->setTimerCallback(timer_param, timer_proc); } + +	virtual byte getPlayId() const = 0; +	virtual int getPolyphony() const = 0; +	virtual int getFirstChannel() const { return 0; } +	//virtual int getLastChannel() const { return 15; } + +	virtual void setVolume(byte volume) { +		if(_driver) +			_driver->property(MIDI_PROP_MASTER_VOLUME, volume); +	} + +	virtual int getVolume() { +		return _driver ? _driver->property(MIDI_PROP_MASTER_VOLUME, 0xffff) : 0; +	} + +	// Returns the current reverb, or -1 when no reverb is active +	int8 getReverb() const { return _reverb; } +	// Sets the current reverb, used mainly in MT-32 +	virtual void setReverb(int8 reverb) { _reverb = reverb; } + +	// Special stuff for Sherlock Holmes +//	virtual void newMusicData(byte *musicData, int32 musicDataSize); + +//protected: +}; + +extern MidiPlayer *MidiPlayer_AdLib_create(); +extern void MidiPlayer_AdLib_newMusicData(MidiPlayer *driver, byte *musicData, int32 musicDataSize); +#endif + +extern MidiDriver *MidiDriver_AdLib_create(); +extern void MidiDriver_AdLib_newMusicData(MidiDriver *driver, byte *musicData, int32 musicDataSize); + +} // End of namespace Sci + +#endif // SHERLOCK_SOFTSEQ_MIDIDRIVER_H  | 
