diff options
| -rw-r--r-- | engines/made/made.cpp | 20 | ||||
| -rw-r--r-- | engines/made/made.h | 5 | ||||
| -rw-r--r-- | engines/made/module.mk | 1 | ||||
| -rw-r--r-- | engines/made/music.cpp | 274 | ||||
| -rw-r--r-- | engines/made/music.h | 150 | ||||
| -rw-r--r-- | engines/made/resource.cpp | 20 | ||||
| -rw-r--r-- | engines/made/resource.h | 16 | ||||
| -rw-r--r-- | engines/made/screen.cpp | 16 | ||||
| -rw-r--r-- | engines/made/screen.h | 3 | ||||
| -rw-r--r-- | engines/made/scriptfuncs.cpp | 24 | 
10 files changed, 525 insertions, 4 deletions
| diff --git a/engines/made/made.cpp b/engines/made/made.cpp index 2d04e8272e..51da50f7d3 100644 --- a/engines/made/made.cpp +++ b/engines/made/made.cpp @@ -44,6 +44,7 @@  #include "made/screen.h"  #include "made/script.h"  #include "made/sound.h" +#include "made/music.h"  #include "made/redreader.h"  namespace Made { @@ -88,6 +89,24 @@ MadeEngine::MadeEngine(OSystem *syst, const MadeGameDescription *gameDesc) : Eng  	_dat = new GameDatabase();  	_script = new ScriptInterpreter(this); +	int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI); +	bool native_mt32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32")); +	bool adlib = (midiDriver == MD_ADLIB); + +	MidiDriver *driver = MidiDriver::createMidi(midiDriver); +	if (native_mt32) +		driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE); + +	_music = new Music(driver, _musicVolume); +	_music->setNativeMT32(native_mt32); +	_music->setAdlib(adlib); + +	_musicVolume = ConfMan.getInt("music_volume"); + +	if (!_musicVolume) { +		debug(1, "Music disabled."); +	} +  }  MadeEngine::~MadeEngine() { @@ -97,6 +116,7 @@ MadeEngine::~MadeEngine() {  	delete _screen;  	delete _dat;  	delete _script; +	delete _music;  }  int MadeEngine::init() { diff --git a/engines/made/made.h b/engines/made/made.h index d897509d31..8cf26c0d81 100644 --- a/engines/made/made.h +++ b/engines/made/made.h @@ -61,6 +61,7 @@ class PmvPlayer;  class Screen;  class ScriptInterpreter;  class GameDatabase; +class Music;  class MadeEngine : public ::Engine {  	int _gameId; @@ -93,10 +94,12 @@ public:  	Screen *_screen;  	GameDatabase *_dat;  	ScriptInterpreter *_script; +	Music *_music;  	int _eventMouseX, _eventMouseY; -	int _soundRate;  	uint16 _eventKey; +	int _soundRate; +	int _musicVolume;  	int32 _timers[50];  	int16 getTimer(int16 timerNum); diff --git a/engines/made/module.mk b/engines/made/module.mk index 1f4cf73cb8..9963f19660 100644 --- a/engines/made/module.mk +++ b/engines/made/module.mk @@ -5,6 +5,7 @@ MODULE_OBJS = \  	detection.o \  	graphics.o \  	made.o \ +	music.o \  	pmvplayer.o \  	redreader.o \  	resource.o \ diff --git a/engines/made/music.cpp b/engines/made/music.cpp new file mode 100644 index 0000000000..8394e78b24 --- /dev/null +++ b/engines/made/music.cpp @@ -0,0 +1,274 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +// FIXME: This code is taken from SAGA and needs more work (e.g. setVolume). + +// MIDI and digital music class + +#include "sound/audiostream.h" +#include "sound/mididrv.h" +#include "sound/midiparser.h" +#include "common/config-manager.h" +#include "common/file.h" + +#include "made/music.h" + +namespace Made { + +MusicPlayer::MusicPlayer(MidiDriver *driver) : _parser(0), _driver(driver), _looping(false), _isPlaying(false), _passThrough(false), _isGM(false) { +	memset(_channel, 0, sizeof(_channel)); +	_masterVolume = 0; +	this->open(); +} + +MusicPlayer::~MusicPlayer() { +	_driver->setTimerCallback(NULL, NULL); +	stopMusic(); +	this->close(); +} + +void MusicPlayer::setVolume(int volume) { +	volume = CLIP(volume, 0, 255); + +	if (_masterVolume == volume) +		return; + +	_masterVolume = volume; + +	for (int i = 0; i < 16; ++i) { +		if (_channel[i]) { +			_channel[i]->volume(_channelVolume[i] * _masterVolume / 255); +		} +	} +} + +int MusicPlayer::open() { +	// Don't ever call open without first setting the output driver! +	if (!_driver) +		return 255; + +	int ret = _driver->open(); +	if (ret) +		return ret; + +	_driver->setTimerCallback(this, &onTimer); +	return 0; +} + +void MusicPlayer::close() { +	stopMusic(); +	if (_driver) +		_driver->close(); +	_driver = 0; +} + +void MusicPlayer::send(uint32 b) { +	if (_passThrough) { +		_driver->send(b); +		return; +	} + +	byte channel = (byte)(b & 0x0F); +	if ((b & 0xFFF0) == 0x07B0) { +		// Adjust volume changes by master volume +		byte volume = (byte)((b >> 16) & 0x7F); +		_channelVolume[channel] = volume; +		volume = volume * _masterVolume / 255; +		b = (b & 0xFF00FFFF) | (volume << 16); +	} else if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) { +		b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8; +	} +	else if ((b & 0xFFF0) == 0x007BB0) { +		//Only respond to All Notes Off if this channel +		//has currently been allocated +		if (_channel[b & 0x0F]) +			return; +	} + +	if (!_channel[channel]) +		_channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel(); + +	if (_channel[channel]) +		_channel[channel]->send(b); +} + +void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) { + +	switch (type) { +	case 0x2F:	// End of Track +		if (_looping) +			_parser->jumpToTick(0); +		else +			stopMusic(); +		break; +	default: +		//warning("Unhandled meta event: %02x", type); +		break; +	} +} + +void MusicPlayer::onTimer(void *refCon) { +	MusicPlayer *music = (MusicPlayer *)refCon; +	Common::StackLock lock(music->_mutex); + +	if (music->_isPlaying) +		music->_parser->onTimer(); +} + +void MusicPlayer::playMusic() { +	_isPlaying = true; +} + +void MusicPlayer::stopMusic() { +	Common::StackLock lock(_mutex); + +	_isPlaying = false; +	if (_parser) { +		_parser->unloadMusic(); +		_parser = NULL; +	} +} + +Music::Music(MidiDriver *driver, int enabled) : _enabled(enabled), _adlib(false) { +	_player = new MusicPlayer(driver); +	_currentVolume = 0; + +	xmidiParser = MidiParser::createParser_XMIDI(); + +	_songTableLen = 0; +	_songTable = 0; + +	_midiMusicData = NULL; +} + +Music::~Music() { +	delete _player; +	xmidiParser->setMidiDriver(NULL); +	delete xmidiParser; + +	free(_songTable); +	if (_midiMusicData) +		delete[] _midiMusicData; +} + +void Music::setVolume(int volume, int time) { +	_targetVolume = volume * 2; // ScummVM has different volume scale +	_currentVolumePercent = 0; + +	if (volume == -1) // Set Full volume +		volume = 255; + +	if (time == 1) { +		_player->setVolume(volume); +		_currentVolume = volume; +		return; +	} + +} + +bool Music::isPlaying() { +	return _player->isPlaying(); +} + +void Music::play(XmidiResource *midiResource, MusicFlags flags) { +	MidiParser *parser; +	byte *resourceData; +	size_t resourceSize; + +	debug(2, "Music::play %d", flags); + +	if (!_enabled) { +		return; +	} + +	if (isPlaying()) { +		return; +	} + +	_player->stopMusic(); + +	/* +	if (!_vm->_musicVolume) { +		return; +	} +	*/ + +	if (flags == MUSIC_DEFAULT) { +		flags = MUSIC_NORMAL; +	} + +	// Load MIDI/XMI resource data + +	_player->setGM(true); + +	resourceSize = midiResource->getSize(); +	resourceData = new byte[resourceSize]; +	memcpy(resourceData, midiResource->getData(), resourceSize); + +	if (resourceSize < 4) { +		error("Music::play() wrong music resource size"); +	} + +	if (xmidiParser->loadMusic(resourceData, resourceSize)) { +		//_player->setGM(false); +		parser = xmidiParser; +	} + +	parser->setTrack(0); +	parser->setMidiDriver(_player); +	parser->setTimerRate(_player->getBaseTempo()); +	parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1); + +	_player->_parser = parser; +	//setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25); +	setVolume(255); + +	if (flags & MUSIC_LOOP) +		_player->setLoop(true); +	else +		_player->setLoop(false); + +	_player->playMusic(); +	if (_midiMusicData) +		delete[] _midiMusicData; +	_midiMusicData = resourceData; +} + +void Music::pause(void) { +	_player->setVolume(-1); +	_player->setPlaying(false); +} + +void Music::resume(void) { +	//_player->setVolume(_vm->_musicVolume == 10 ? 255 : _vm->_musicVolume * 25); +	setVolume(255); +	_player->setPlaying(true); +} + +void Music::stop(void) { +	_player->stopMusic(); +} + +} // End of namespace Made diff --git a/engines/made/music.h b/engines/made/music.h new file mode 100644 index 0000000000..1403a7c0a1 --- /dev/null +++ b/engines/made/music.h @@ -0,0 +1,150 @@ +/* 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. + * + * $URL$ + * $Id$ + * + */ + +// Music class + +#ifndef MADE_MUSIC_H +#define MADE_MUSIC_H + +#include "sound/audiocd.h" +#include "sound/mididrv.h" +#include "sound/midiparser.h" +#include "sound/mp3.h" +#include "sound/vorbis.h" +#include "sound/flac.h" +#include "common/mutex.h" + +#include "made/resource.h" + +namespace Made { + +enum MusicFlags { +	MUSIC_NORMAL = 0, +	MUSIC_LOOP = 0x0001, +	MUSIC_DEFAULT = 0xffff +}; + +class MusicPlayer : public MidiDriver { +public: +	MusicPlayer(MidiDriver *driver); +	~MusicPlayer(); + +	bool isPlaying() { return _isPlaying; } +	void setPlaying(bool playing) { _isPlaying = playing; } + +	void setVolume(int volume); +	int getVolume() { return _masterVolume; } + +	void setNativeMT32(bool b) { _nativeMT32 = b; } +	bool hasNativeMT32() { return _nativeMT32; } +	void playMusic(); +	void stopMusic(); +	void setLoop(bool loop) { _looping = loop; } +	void setPassThrough(bool b) { _passThrough = b; } + +	void setGM(bool isGM) { _isGM = isGM; } + +	//MidiDriver interface implementation +	int open(); +	void close(); +	void send(uint32 b); + +	void metaEvent(byte type, byte *data, uint16 length); + +	void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { } +	uint32 getBaseTempo(void)	{ return _driver ? _driver->getBaseTempo() : 0; } + +	//Channel allocation functions +	MidiChannel *allocateChannel()		{ return 0; } +	MidiChannel *getPercussionChannel()	{ return 0; } + +	MidiParser *_parser; +	Common::Mutex _mutex; + +protected: + +	static void onTimer(void *data); + +	MidiChannel *_channel[16]; +	MidiDriver *_driver; +	byte _channelVolume[16]; +	bool _nativeMT32; +	bool _isGM; +	bool _passThrough; + +	bool _isPlaying; +	bool _looping; +	bool _randomLoop; +	byte _masterVolume; + +	byte *_musicData; +	uint16 *_buf; +	size_t _musicDataSize; +}; + +class Music { +public: + +	Music(MidiDriver *driver, int enabled); +	~Music(void); +	void setNativeMT32(bool b)	{ _player->setNativeMT32(b); } +	bool hasNativeMT32()		{ return _player->hasNativeMT32(); } +	void setAdlib(bool b)		{ _adlib = b; } +	bool hasAdlib()			{ return _adlib; } +	void setPassThrough(bool b)	{ _player->setPassThrough(b); } +	bool isPlaying(void); + +	void play(XmidiResource *midiResource, MusicFlags flags = MUSIC_DEFAULT); +	void pause(void); +	void resume(void); +	void stop(void); + +	void setVolume(int volume, int time = 1); +	int getVolume() { return _currentVolume; } + +	int32 *_songTable; +	int _songTableLen; + +private: + +	MusicPlayer *_player; +	uint32 _trackNumber; + +	int _enabled; +	bool _adlib; + +	int _targetVolume; +	int _currentVolume; +	int _currentVolumePercent; + +	MidiParser *xmidiParser; + +	byte *_midiMusicData; + +}; + +} // End of namespace Made + +#endif diff --git a/engines/made/resource.cpp b/engines/made/resource.cpp index cb7cf6e7f5..4450d86c31 100644 --- a/engines/made/resource.cpp +++ b/engines/made/resource.cpp @@ -205,6 +205,22 @@ const char *MenuResource::getString(uint index) const {  		return NULL;  } +/* XmidiResource */ + +XmidiResource::XmidiResource() : _data(NULL), _size(0) { +} + +XmidiResource::~XmidiResource() { +	if (_data) +		delete[] _data; +} + +void XmidiResource::load(byte *source, int size) { +	_data = new byte[size]; +	_size = size; +	memcpy(_data, source, size); +} +  /* ProjectReader */  ProjectReader::ProjectReader() { @@ -269,6 +285,10 @@ MenuResource *ProjectReader::getMenu(int index) {  	return createResource<MenuResource>(kResMENU, index);  } +XmidiResource *ProjectReader::getXmidi(int index) { +	return createResource<XmidiResource>(kResXMID, index); +} +  void ProjectReader::loadIndex(ResourceSlots *slots) {  	_fd->readUint32LE(); // skip INDX  	_fd->readUint32LE(); // skip index size diff --git a/engines/made/resource.h b/engines/made/resource.h index e2f305dc79..5350ed5242 100644 --- a/engines/made/resource.h +++ b/engines/made/resource.h @@ -44,7 +44,8 @@ enum ResourceType {  	kResFLEX = MKID_BE('FLEX'),  	kResSNDS = MKID_BE('SNDS'),  	kResANIM = MKID_BE('ANIM'), -	kResMENU = MKID_BE('MENU') +	kResMENU = MKID_BE('MENU'), +	kResXMID = MKID_BE('XMID')  };  struct ResourceSlot; @@ -110,6 +111,18 @@ protected:  	Common::Array<Common::String> _strings;  }; +class XmidiResource : public Resource { +public: +	XmidiResource(); +	~XmidiResource(); +	void load(byte *source, int size); +	byte *getData() const { return _data; } +	int getSize() const { return _size; } +protected: +	byte *_data; +	int _size; +}; +  struct ResourceSlot {  	uint32 offs;  	uint32 size; @@ -133,6 +146,7 @@ public:  	AnimationResource *getAnimation(int index);  	SoundResource *getSound(int index);  	MenuResource *getMenu(int index); +	XmidiResource *getXmidi(int index);  	void freeResource(Resource *resource); diff --git a/engines/made/screen.cpp b/engines/made/screen.cpp index e63854db64..ede49e25f4 100644 --- a/engines/made/screen.cpp +++ b/engines/made/screen.cpp @@ -472,4 +472,20 @@ void Screen::show() {  } +void Screen::flash(int flashCount) { +	int palSize = _paletteColorCount * 3; +	if (flashCount < 1) +		flashCount = 1; +	for (int i = 0; i < palSize; i++) +		_fxPalette[i] = CLIP<byte>(255 - _palette[i], 0, 255); +	while (flashCount--) { +		setRGBPalette(_fxPalette, 0, _paletteColorCount); +		_vm->_system->updateScreen(); +		_vm->_system->delayMillis(30); +		setRGBPalette(_palette, 0, _paletteColorCount); +		_vm->_system->updateScreen(); +		_vm->_system->delayMillis(30); +	} +} +  } // End of namespace Made diff --git a/engines/made/screen.h b/engines/made/screen.h index eb072477a3..fa58dde88d 100644 --- a/engines/made/screen.h +++ b/engines/made/screen.h @@ -102,6 +102,7 @@ public:  	uint16 placeText(uint16 channelIndex, uint16 textObjectIndex, int16 x, int16 y, uint16 fontNum, int16 textColor, int16 outlineColor);  	void show(); +	void flash(int count);  	byte _screenPalette[256 * 4]; @@ -111,7 +112,7 @@ protected:  	bool _screenLock;  	bool _paletteLock; -	byte _palette[768], _newPalette[768]; +	byte _palette[768], _newPalette[768], _fxPalette[768];  	int _paletteColorCount, _oldPaletteColorCount;  	bool _paletteInitialized, _needPalette; diff --git a/engines/made/scriptfuncs.cpp b/engines/made/scriptfuncs.cpp index 5c5995f593..cd3d3daf1a 100644 --- a/engines/made/scriptfuncs.cpp +++ b/engines/made/scriptfuncs.cpp @@ -36,6 +36,7 @@  #include "made/script.h"  #include "made/pmvplayer.h"  #include "made/scriptfuncs.h" +#include "made/music.h"  namespace Made { @@ -288,15 +289,25 @@ int16 ScriptFunctionsRtz::o1_PLAYSND(int16 argc, int16 *argv) {  }  int16 ScriptFunctionsRtz::o1_PLAYMUS(int16 argc, int16 *argv) { +	int16 musicId = argv[0]; +	if (musicId > 0) { +		XmidiResource *xmidi = _vm->_res->getXmidi(musicId); +		_vm->_music->play(xmidi); +		_vm->_res->freeResource(xmidi); +	}  	return 0;  }  int16 ScriptFunctionsRtz::o1_STOPMUS(int16 argc, int16 *argv) { +	_vm->_music->stop();  	return 0;  }  int16 ScriptFunctionsRtz::o1_ISMUS(int16 argc, int16 *argv) { -	return 0; +	if (_vm->_music->isPlaying()) +		return 1; +	else +		return 0;  }  int16 ScriptFunctionsRtz::o1_TEXTPOS(int16 argc, int16 *argv) { @@ -304,6 +315,7 @@ int16 ScriptFunctionsRtz::o1_TEXTPOS(int16 argc, int16 *argv) {  }  int16 ScriptFunctionsRtz::o1_FLASH(int16 argc, int16 *argv) { +	_vm->_screen->flash(argv[0]);  	return 0;  } @@ -536,10 +548,20 @@ int16 ScriptFunctionsRtz::o1_PLAYMOVIE(int16 argc, int16 *argv) {  }  int16 ScriptFunctionsRtz::o1_LOADSND(int16 argc, int16 *argv) { +	SoundResource *sound = _vm->_res->getSound(argv[0]); +	if (sound) { +		_vm->_res->freeResource(sound); +		return 1; +	}  	return 0;  }  int16 ScriptFunctionsRtz::o1_LOADMUS(int16 argc, int16 *argv) { +	XmidiResource *xmidi = _vm->_res->getXmidi(argv[0]); +	if (xmidi) { +		_vm->_res->freeResource(xmidi); +		return 1; +	}  	return 0;  } | 
