[Scummvm-cvs-logs] SF.net SVN: scummvm:[49607] scummvm/trunk/engines/saga

thebluegr at users.sourceforge.net thebluegr at users.sourceforge.net
Sat Jun 12 20:20:22 CEST 2010


Revision: 49607
          http://scummvm.svn.sourceforge.net/scummvm/?rev=49607&view=rev
Author:   thebluegr
Date:     2010-06-12 18:20:22 +0000 (Sat, 12 Jun 2010)

Log Message:
-----------
SAGA: Music code cleanup. The music driver is now placed inside the MusicPlayer class, instead of the SagaEngine class. Split the functionality that the music parser should handle from the functionality that the music driver should handle. Also, fixed a bug in MusicDriver::send() (the notes off signal was sent to unallocated channels, not allocated ones)

Modified Paths:
--------------
    scummvm/trunk/engines/saga/music.cpp
    scummvm/trunk/engines/saga/music.h
    scummvm/trunk/engines/saga/saga.cpp
    scummvm/trunk/engines/saga/saga.h

Modified: scummvm/trunk/engines/saga/music.cpp
===================================================================
--- scummvm/trunk/engines/saga/music.cpp	2010-06-12 11:43:30 UTC (rev 49606)
+++ scummvm/trunk/engines/saga/music.cpp	2010-06-12 18:20:22 UTC (rev 49607)
@@ -42,19 +42,25 @@
 #define BUFFER_SIZE 4096
 #define MUSIC_SUNSPOT 26
 
-MusicPlayer::MusicPlayer(MidiDriver *driver) : _parser(0), _driver(driver), _looping(false), _isPlaying(false), _passThrough(false), _isGM(false) {
+MusicDriver::MusicDriver() : _isGM(false) {
 	memset(_channel, 0, sizeof(_channel));
 	_masterVolume = 0;
+	_nativeMT32 = ConfMan.getBool("native_mt32");
+
+	_driverType = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI);
+	_driver = MidiDriver::createMidi(_driverType);
+	if (isMT32())
+		_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+
 	this->open();
 }
 
-MusicPlayer::~MusicPlayer() {
-	_driver->setTimerCallback(NULL, NULL);
-	stopMusic();
+MusicDriver::~MusicDriver() {
 	this->close();
+	delete _driver;
 }
 
-void MusicPlayer::setVolume(int volume) {
+void MusicDriver::setVolume(int volume) {
 	volume = CLIP(volume, 0, 255);
 
 	if (_masterVolume == volume)
@@ -71,32 +77,7 @@
 	}
 }
 
-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;
-	}
-
+void MusicDriver::send(uint32 b) {
 	byte channel = (byte)(b & 0x0F);
 	if ((b & 0xFFF0) == 0x07B0) {
 		// Adjust volume changes by master volume
@@ -104,72 +85,87 @@
 		_channelVolume[channel] = volume;
 		volume = volume * _masterVolume / 255;
 		b = (b & 0xFF00FFFF) | (volume << 16);
-	} else if ((b & 0xF0) == 0xC0 && !_isGM && !_nativeMT32) {
+	} else if ((b & 0xF0) == 0xC0 && !_isGM && !isMT32()) {
+		// Remap MT32 instruments to General Midi
 		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])
+	} else if ((b & 0xFFF0) == 0x007BB0) {
+		// Only respond to All Notes Off if this channel
+		// has currently been allocated
+		if (!_channel[channel])
 			return;
 	}
 
 	if (!_channel[channel])
 		_channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
-
-	if (_channel[channel])
+	else
 		_channel[channel]->send(b);
 }
 
-void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
-	// FIXME: The "elkfanfare" is played much too quickly. There are some
-	//        meta events that we don't handle. Perhaps there is a
-	//        connection...?
+Music::Music(SagaEngine *vm, Audio::Mixer *mixer) : _vm(vm), _mixer(mixer) {
+	_currentVolume = 0;
+	_driver = new MusicDriver();
 
-	switch (type) {
-	case 0x2F:	// End of Track
-		if (_looping)
-			_parser->jumpToTick(0);
-		else
-			stopMusic();
-		break;
-	default:
-		//warning("Unhandled meta event: %02x", type);
-		break;
-	}
-}
+	_digitalMusicContext = _vm->_resource->getContext(GAME_DIGITALMUSICFILE);
+	if (!_driver->isAdlib())
+		_musicContext = _vm->_resource->getContext(GAME_MUSICFILE_GM);
+	else
+		_musicContext = _vm->_resource->getContext(GAME_MUSICFILE_FM);
 
-void MusicPlayer::onTimer(void *refCon) {
-	MusicPlayer *music = (MusicPlayer *)refCon;
-	Common::StackLock lock(music->_mutex);
+	if (!_musicContext) {
+		if (_vm->getGameId() == GID_ITE) {
+			_musicContext = _vm->_resource->getContext(GAME_RESOURCEFILE);
+		} else {
+			// I've listened to music from both the FM and the GM
+			// file, and I've tentatively reached the conclusion
+			// that they are both General MIDI. My guess is that
+			// the FM file has been reorchestrated to sound better
+			// on AdLib and other FM synths.
+			//
+			// Sev says the AdLib music does not sound like in the
+			// original, but I still think assuming General MIDI is
+			// the right thing to do. Some music, like the End
+			// Title (song 0) sound absolutely atrocious when piped
+			// through our MT-32 to GM mapping.
+			//
+			// It is, however, quite possible that the original
+			// used a different GM to FM mapping. If the original
+			// sounded markedly better, perhaps we should add some
+			// way of replacing our stock mapping in adlib.cpp?
+			//
+			// For the composer's own recording of the End Title,
+			// see http://www.johnottman.com/
 
-	if (music->_isPlaying)
-		music->_parser->onTimer();
-}
+			// Oddly enough, the intro music (song 1) is very
+			// different in the two files. I have no idea why.
+			// Note that the IHNM demo has only got one music file
+			// (music.rsc). It is assumed that it contains FM music
+			_musicContext = _vm->_resource->getContext(GAME_MUSICFILE_FM);
+		}
+	}
 
-void MusicPlayer::playMusic() {
-	_isPlaying = true;
-}
-
-void MusicPlayer::stopMusic() {
-	Common::StackLock lock(_mutex);
-
-	_isPlaying = false;
-	if (_parser) {
-		_parser->unloadMusic();
-		_parser = NULL;
+	// Check if the game is using XMIDI or SMF music
+	if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) {
+		// Just set an XMIDI parser for Mac IHNM for now
+		_parser = MidiParser::createParser_XMIDI();
+	} else {
+		byte *resourceData;
+		size_t resourceSize;
+		int resourceId = (_vm->getGameId() == GID_ITE ? 9 : 0);
+		_vm->_resource->loadResource(_musicContext, resourceId, resourceData, resourceSize);
+		if (!memcmp(resourceData, "FORM", 4)) {
+			_parser = MidiParser::createParser_XMIDI();
+			// ITE had MT32 mapped instruments
+			_driver->setGM(_vm->getGameId() != GID_ITE);
+		} else {
+			_parser = MidiParser::createParser_SMF();
+		}
+		free(resourceData);
 	}
-}
 
-Music::Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver) : _vm(vm), _mixer(mixer), _adlib(false) {
-	_player = new MusicPlayer(driver);
-	_currentVolume = 0;
+	_parser->setMidiDriver(_driver);
+	_parser->setTimerRate(_driver->getBaseTempo());
+	_parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
 
-	xmidiParser = MidiParser::createParser_XMIDI();
-	smfParser = MidiParser::createParser_SMF();
-
-	_digitalMusicContext = _vm->_resource->getContext(GAME_DIGITALMUSICFILE);
-
 	_songTableLen = 0;
 	_songTable = 0;
 
@@ -180,11 +176,11 @@
 Music::~Music() {
 	_vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback);
 	_mixer->stopHandle(_musicHandle);
-	delete _player;
-	xmidiParser->setMidiDriver(NULL);
-	smfParser->setMidiDriver(NULL);
-	delete xmidiParser;
-	delete smfParser;
+	_driver->setTimerCallback(NULL, NULL);
+	_driver->close();
+	delete _driver;
+	_parser->setMidiDriver(NULL);
+	delete _parser;
 
 	free(_songTable);
 	free(_midiMusicData);
@@ -194,6 +190,12 @@
 	((Music *)refCon)->musicVolumeGauge();
 }
 
+void Music::onTimer(void *refCon) {
+	Music *music = (Music *)refCon;
+	Common::StackLock lock(music->_driver->_mutex);
+	music->_parser->onTimer();
+}
+
 void Music::musicVolumeGauge() {
 	int volume;
 
@@ -209,7 +211,7 @@
 		volume = 1;
 
 	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
-	_player->setVolume(volume);
+	_driver->setVolume(volume);
 
 	if (_currentVolumePercent == 100) {
 		_vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback);
@@ -226,7 +228,7 @@
 
 	if (time == 1) {
 		_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
-		_player->setVolume(volume);
+		_driver->setVolume(volume);
 		_vm->getTimerManager()->removeTimerProc(&musicVolumeGaugeCallback);
 		_currentVolume = volume;
 		return;
@@ -236,13 +238,11 @@
 }
 
 bool Music::isPlaying() {
-	return _mixer->isSoundHandleActive(_musicHandle) || _player->isPlaying();
+	return _mixer->isSoundHandleActive(_musicHandle) || _parser->isPlaying();
 }
 
 void Music::play(uint32 resourceId, MusicFlags flags) {
 	Audio::SeekableAudioStream *audioStream = NULL;
-	MidiParser *parser;
-	ResourceContext *context = NULL;
 	byte *resourceData;
 	size_t resourceSize;
 	uint32 loopStart;
@@ -254,8 +254,8 @@
 	}
 
 	_trackNumber = resourceId;
-	_player->stopMusic();
 	_mixer->stopHandle(_musicHandle);
+	_parser->unloadMusic();
 
 	int realTrackNumber;
 
@@ -356,55 +356,10 @@
 		return;
 	}
 
-	if (flags == MUSIC_DEFAULT) {
+	if (flags == MUSIC_DEFAULT)
 		flags = MUSIC_NORMAL;
-	}
 
 	// Load MIDI/XMI resource data
-
-	if (_vm->getGameId() == GID_ITE) {
-		context = _vm->_resource->getContext(GAME_MUSICFILE_GM);
-		if (context == NULL) {
-			context = _vm->_resource->getContext(GAME_RESOURCEFILE);
-		}
-	} else if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) {
-		// The music of the Mac version of IHNM is loaded from its
-		// associated external file later on
-	} else {
-		// I've listened to music from both the FM and the GM
-		// file, and I've tentatively reached the conclusion
-		// that they are both General MIDI. My guess is that
-		// the FM file has been reorchestrated to sound better
-		// on AdLib and other FM synths.
-		//
-		// Sev says the AdLib music does not sound like in the
-		// original, but I still think assuming General MIDI is
-		// the right thing to do. Some music, like the End
-		// Title (song 0) sound absolutely atrocious when piped
-		// through our MT-32 to GM mapping.
-		//
-		// It is, however, quite possible that the original
-		// used a different GM to FM mapping. If the original
-		// sounded markedly better, perhaps we should add some
-		// way of replacing our stock mapping in adlib.cpp?
-		//
-		// For the composer's own recording of the End Title,
-		// see http://www.johnottman.com/
-
-		// Oddly enough, the intro music (song 1) is very
-		// different in the two files. I have no idea why.
-		// Note that the IHNM demo has only got one music file
-		// (music.rsc). It is assumed that it contains FM music
-
-		if (hasAdLib() || _vm->isIHNMDemo()) {
-			context = _vm->_resource->getContext(GAME_MUSICFILE_FM);
-		} else {
-			context = _vm->_resource->getContext(GAME_MUSICFILE_GM);
-		}
-	}
-
-	_player->setGM(true);
-
 	if (_vm->getGameId() == GID_IHNM && _vm->isMacResources()) {
 		// Load the external music file for Mac IHNM
 #if 0
@@ -422,56 +377,39 @@
 #endif
 		return;
 	} else {
-		_vm->_resource->loadResource(context, resourceId, resourceData, resourceSize);
+		_vm->_resource->loadResource(_musicContext, resourceId, resourceData, resourceSize);
 	}
 
 	if (resourceSize < 4) {
 		error("Music::play() wrong music resource size");
 	}
 
-	if (xmidiParser->loadMusic(resourceData, resourceSize)) {
-		if (_vm->getGameId() == GID_ITE)
-			_player->setGM(false);
+	if (!_parser->loadMusic(resourceData, resourceSize))
+		error("Music::play() wrong music resource");
 
-		parser = xmidiParser;
-	} else {
-		if (smfParser->loadMusic(resourceData, resourceSize)) {
-			parser = smfParser;
-		} else {
-			error("Music::play() wrong music resource");
-		}
-	}
+	_parser->setTrack(0);
+	_driver->setTimerCallback(this, &onTimer);
 
-	parser->setTrack(0);
-	parser->setMidiDriver(_player);
-	parser->setTimerRate(_player->getBaseTempo());
-	parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
-
-	_player->_parser = parser;
 	setVolume(_vm->_musicVolume);
 
-	if (flags & MUSIC_LOOP)
-		_player->setLoop(true);
-	else
-		_player->setLoop(false);
+	// Handle music looping
+	_parser->property(MidiParser::mpAutoLoop, (flags & MUSIC_LOOP) ? 1 : 0);
 
-	_player->playMusic();
 	free(_midiMusicData);
 	_midiMusicData = resourceData;
 }
 
 void Music::pause() {
-	_player->setVolume(-1);
-	_player->setPlaying(false);
+	_driver->setTimerCallback(NULL, NULL);
 }
 
 void Music::resume() {
-	_player->setVolume(_vm->_musicVolume);
-	_player->setPlaying(true);
+	_driver->setTimerCallback(this, &onTimer);
 }
 
 void Music::stop() {
-	_player->stopMusic();
+	_driver->setTimerCallback(NULL, NULL);
+	_parser->unloadMusic();
 }
 
 } // End of namespace Saga

Modified: scummvm/trunk/engines/saga/music.h
===================================================================
--- scummvm/trunk/engines/saga/music.h	2010-06-12 11:43:30 UTC (rev 49606)
+++ scummvm/trunk/engines/saga/music.h	2010-06-12 18:20:22 UTC (rev 49607)
@@ -44,41 +44,32 @@
 	MUSIC_DEFAULT = 0xffff
 };
 
-class MusicPlayer : public MidiDriver {
+class MusicDriver : public MidiDriver {
 public:
-	MusicPlayer(MidiDriver *driver);
-	~MusicPlayer();
+	MusicDriver();
+	~MusicDriver();
 
-	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; }
-
+	bool isAdlib() { return _driverType == MD_ADLIB; }
+	bool isMT32() { return _driverType == MD_MT32 || _nativeMT32; }
 	void setGM(bool isGM) { _isGM = isGM; }
 
 	//MidiDriver interface implementation
-	int open();
-	void close();
+	int open() { return _driver->open(); }
+	void close() { _driver->close(); }
 	void send(uint32 b);
 
-	void metaEvent(byte type, byte *data, uint16 length);
+	void metaEvent(byte type, byte *data, uint16 length) {}
 
-	void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { }
-	uint32 getBaseTempo()	{ return _driver ? _driver->getBaseTempo() : 0; }
+	void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { _driver->setTimerCallback(timerParam, timerProc); }
+	uint32 getBaseTempo()	{ return _driver->getBaseTempo(); }
 
 	//Channel allocation functions
 	MidiChannel *allocateChannel()		{ return 0; }
 	MidiChannel *getPercussionChannel()	{ return 0; }
 
-	MidiParser *_parser;
 	Common::Mutex _mutex;
 
 protected:
@@ -87,14 +78,11 @@
 
 	MidiChannel *_channel[16];
 	MidiDriver *_driver;
+	MidiDriverType _driverType;
 	byte _channelVolume[16];
-	bool _nativeMT32;
 	bool _isGM;
-	bool _passThrough;
+	bool _nativeMT32;
 
-	bool _isPlaying;
-	bool _looping;
-	bool _randomLoop;
 	byte _masterVolume;
 
 	byte *_musicData;
@@ -105,13 +93,8 @@
 class Music {
 public:
 
-	Music(SagaEngine *vm, Audio::Mixer *mixer, MidiDriver *driver);
+	Music(SagaEngine *vm, Audio::Mixer *mixer);
 	~Music();
-	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();
 	bool hasDigitalMusic() { return _digitalMusic; }
 
@@ -130,24 +113,23 @@
 	SagaEngine *_vm;
 	Audio::Mixer *_mixer;
 
-	MusicPlayer *_player;
+	MusicDriver *_driver;
 	Audio::SoundHandle _musicHandle;
 	uint32 _trackNumber;
 
-	bool _adlib;
-
 	int _targetVolume;
 	int _currentVolume;
 	int _currentVolumePercent;
 	bool _digitalMusic;
 
+	ResourceContext *_musicContext;
 	ResourceContext *_digitalMusicContext;
-	MidiParser *xmidiParser;
-	MidiParser *smfParser;
+	MidiParser *_parser;
 
 	byte *_midiMusicData;
 
 	static void musicVolumeGaugeCallback(void *refCon);
+	static void onTimer(void *refCon);
 	void musicVolumeGauge();
 };
 

Modified: scummvm/trunk/engines/saga/saga.cpp
===================================================================
--- scummvm/trunk/engines/saga/saga.cpp	2010-06-12 11:43:30 UTC (rev 49606)
+++ scummvm/trunk/engines/saga/saga.cpp	2010-06-12 18:20:22 UTC (rev 49607)
@@ -83,7 +83,6 @@
 	_sndRes = NULL;
 	_sound = NULL;
 	_music = NULL;
-	_driver = NULL;
 	_anim = NULL;
 	_render = NULL;
 	_isoMap = NULL;
@@ -198,9 +197,6 @@
 	delete _sound;
 	_sound = NULL;
 
-	delete _driver;
-	_driver = NULL;
-
 	delete _gfx;
 	_gfx = NULL;
 
@@ -285,17 +281,7 @@
 	_console = new Console(this);
 
 	// Graphics should be initialized before music
-	MidiDriverType 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);
-
-	_driver = MidiDriver::createMidi(midiDriver);
-	if (native_mt32)
-		_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
-
-	_music = new Music(this, _mixer, _driver);
-	_music->setNativeMT32(native_mt32);
-	_music->setAdLib(adlib);
+	_music = new Music(this, _mixer);
 	_render = new Render(this, _system);
 	if (!_render->initialized()) {
 		return Common::kUnknownError;

Modified: scummvm/trunk/engines/saga/saga.h
===================================================================
--- scummvm/trunk/engines/saga/saga.h	2010-06-12 11:43:30 UTC (rev 49606)
+++ scummvm/trunk/engines/saga/saga.h	2010-06-12 18:20:22 UTC (rev 49607)
@@ -525,7 +525,6 @@
 	SndRes *_sndRes;
 	Sound *_sound;
 	Music *_music;
-	MidiDriver *_driver;
 	Anim *_anim;
 	Render *_render;
 	IsoMap *_isoMap;


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