[Scummvm-cvs-logs] CVS: scummvm/queen music.h,1.4,1.5 music.cpp,1.6,1.7

Joost Peters joostp at users.sourceforge.net
Mon Jan 19 13:24:08 CET 2004


Update of /cvsroot/scummvm/scummvm/queen
In directory sc8-pr-cvs1:/tmp/cvs-serv30529/queen

Modified Files:
	music.h music.cpp 
Log Message:
Added MusicPlayer class (MidiDriver derivate) for greater flexibility


Index: music.h
===================================================================
RCS file: /cvsroot/scummvm/scummvm/queen/music.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- music.h	6 Jan 2004 12:45:29 -0000	1.4
+++ music.h	19 Jan 2004 21:23:42 -0000	1.5
@@ -23,13 +23,65 @@
 #define QUEENMUSIC_H
 
 #include "common/util.h"
+#include "sound/mididrv.h"
 
-class MidiDriver;
 class MidiParser;
 
 namespace Queen {
 
 class QueenEngine;
+
+class MusicPlayer : public MidiDriver {
+public:
+	MusicPlayer(MidiDriver *driver, byte *data, uint32 size);
+	~MusicPlayer();
+	
+	void playMusic();
+	void stopMusic();
+	void setLoop(bool loop)		{ _looping = loop; }
+	bool queueSong(uint16 songNum);
+	void queueClear();
+	
+	//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; }
+	
+protected:
+
+	enum {
+		MUSIC_QUEUE_SIZE	=	8
+	};
+
+	void queueUpdatePos();
+	static void onTimer(void *data);
+	uint32 songOffset(uint16 songNum);
+	uint32 songLength(uint16 songNum);
+
+	MidiDriver *_driver;
+	MidiParser *_parser;
+	MidiChannel *_channel[16];
+	byte _channelVolume[16];
+		
+	bool _isPlaying;
+	bool _looping;
+	byte _volume;
+	uint8 _queuePos;
+	int16 _songQueue[MUSIC_QUEUE_SIZE];
+	
+	uint16 _numSongs;
+	byte *_musicData;
+	uint32 _musicDataSize;
+};
 	
 class Music {
 public:
@@ -37,20 +89,12 @@
 	~Music();
 	void playSong(uint16 songNum);
 	void stopSong();
-	void loop(bool val)	{ _loop = val; }
+	void loop(bool val)	{ return _player->setLoop(val); }
 	
 protected:
-	bool _isPlaying;
-	bool _loop;
 	byte *_musicData;
-	uint16 _numSongs;
 	uint32 _musicDataSize;
-	MidiDriver *_driver;
-	MidiParser *_midi;
-
-	static void myTimerProc(void *refCon);	
-	uint32 songOffset(uint16 songNum);
-	uint32 songLength(uint16 songNum);
+	MusicPlayer *_player;
 };
 
 } // End of namespace Queen

Index: music.cpp
===================================================================
RCS file: /cvsroot/scummvm/scummvm/queen/music.cpp,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- music.cpp	6 Jan 2004 12:45:29 -0000	1.6
+++ music.cpp	19 Jan 2004 21:23:42 -0000	1.7
@@ -24,70 +24,168 @@
 #include "queen/queen.h"
 #include "queen/resource.h"
 
-#include "sound/mididrv.h"
 #include "sound/midiparser.h"
 
 namespace Queen {
 
-	Music::Music(MidiDriver *driver, QueenEngine *vm) : _isPlaying(false), _loop(false), _driver(driver) {
-		_midi = MidiParser::createParser_SMF();
-		_midi->setMidiDriver(_driver);
-		int ret = _driver->open();
-		if (ret)
-			warning("MIDI Player init failed: \"%s\"", _driver->getErrorName(ret));
-		_midi->setTimerRate(_driver->getBaseTempo());
-		_driver->setTimerCallback(this, myTimerProc);			
+	MusicPlayer::MusicPlayer(MidiDriver *driver, byte *data, uint32 size) : _driver(driver), _isPlaying(false), _looping(false), _volume(255), _queuePos(0), _musicData(data), _musicDataSize(size) {
+		queueClear();
+		_parser = MidiParser::createParser_SMF();
+		_parser->setMidiDriver(this);
+		_parser->setTimerRate(_driver->getBaseTempo());
 		
-		if (vm->resource()->isDemo()) {
-			_musicData = vm->resource()->loadFile("AQ8.RL", 0, NULL);
-			_musicDataSize = vm->resource()->fileSize("AQ8.RL");
-		} else {
-			_musicData = vm->resource()->loadFile("AQ.RL", 0, NULL);
-			_musicDataSize = vm->resource()->fileSize("AQ.RL");
-		}
 		_numSongs = READ_LE_UINT16(_musicData);
+		this->open();
 	}
-
-	Music::~Music() {
+	
+	MusicPlayer::~MusicPlayer() {
 		_driver->setTimerCallback(NULL, NULL);
-		_midi->unloadMusic();
-		_driver->close();
-		delete _midi;
-		delete[] _musicData;	
+		_parser->unloadMusic();
+		this->close();
+		delete _parser;
 	}
-
-	void Music::playSong(uint16 songNum) {
-		if (_loop)
-			_midi->property(MidiParser::mpAutoLoop, 1);
+	
+	bool MusicPlayer::queueSong(uint16 songNum) {
+		uint8 emptySlots = 0;
+		for (int i = 0; i < MUSIC_QUEUE_SIZE; i++)
+			if (!_songQueue[i])
+				emptySlots++;
+		
+		if (!emptySlots)
+			return false;
+			
+		_songQueue[MUSIC_QUEUE_SIZE - emptySlots] = songNum;
+		return true;
+	}
+	
+	void MusicPlayer::queueClear() {
+		_queuePos = 0;
+		memset(_songQueue, 0, sizeof(_songQueue));
+	}
+	
+	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) {
+		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 & 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) {
+		//Only thing we care about is End of Track.
+		if (type != 0x2F)
+			return;
+		
+		if (_looping || _songQueue[1]) 
+			playMusic();
 		else
-			_midi->property(MidiParser::mpAutoLoop, 0);
+			stopMusic();
+	}
+	
+	void MusicPlayer::onTimer(void *refCon) {
+		MusicPlayer *music = (MusicPlayer *)refCon;
+		if (music->_isPlaying)
+			music->_parser->onTimer();
+	}
+	
+	void MusicPlayer::playMusic() {
+		if (!_queuePos && !_songQueue[_queuePos]) {
+			debug(5, "MusicPlayer::playMusic - Music queue is empty!");
+			return;
+		}
 		
+		uint16 songNum = _songQueue[_queuePos];
+		_parser->loadMusic(_musicData + songOffset(songNum), songLength(songNum));
+		_parser->setTrack(0);	
+		//debug(0, "Playing song %d [queue position: %d]", songNum, _queuePos);
 		_isPlaying = true;
-		_midi->loadMusic(_musicData + songOffset(songNum), songLength(songNum));
-		_midi->setTrack(0);		
+		queueUpdatePos();
 	}
-
-	void Music::stopSong() {
+	
+	void MusicPlayer::queueUpdatePos() {
+		if (_queuePos < (MUSIC_QUEUE_SIZE - 1) && _songQueue[_queuePos + 1])
+			_queuePos++;
+		else
+			_queuePos = 0;
+	}
+	
+	void MusicPlayer::stopMusic() {
 		_isPlaying = false;
-		_midi->unloadMusic();
+		_parser->unloadMusic();
 	}
 
-	void Music::myTimerProc(void *refCon) {
-		Music *music = (Music *)refCon;
-		if (music->_isPlaying)
-			music->_midi->onTimer();
-	}
-	
-	uint32 Music::songOffset(uint16 songNum) {
+	uint32 MusicPlayer::songOffset(uint16 songNum) {
 		uint16 offsLo = READ_LE_UINT16(_musicData + (songNum * 4) + 2);
 		uint16 offsHi = READ_LE_UINT16(_musicData + (songNum * 4) + 4);
 		return (offsHi << 4) | offsLo;
 	}
 
-	uint32 Music::songLength(uint16 songNum) {
+	uint32 MusicPlayer::songLength(uint16 songNum) {
 		if (songNum < _numSongs)
 			return (songOffset(songNum + 1) - songOffset(songNum));
 		return (_musicDataSize - songOffset(songNum));
 	}
+
+	Music::Music(MidiDriver *driver, QueenEngine *vm) {
+		if (vm->resource()->isDemo()) {
+			_musicData = vm->resource()->loadFile("AQ8.RL", 0, NULL);
+			_musicDataSize = vm->resource()->fileSize("AQ8.RL");
+		} else {
+			_musicData = vm->resource()->loadFile("AQ.RL", 0, NULL);
+			_musicDataSize = vm->resource()->fileSize("AQ.RL");
+		}
+		
+		_player = new MusicPlayer(driver, _musicData, _musicDataSize);
+	}
+
+	Music::~Music() {
+		delete _player;
+		delete[] _musicData;	
+	}
+
+	void Music::playSong(uint16 songNum) {
+		_player->queueClear();
+		_player->queueSong(songNum);
+		_player->playMusic();				
+	}
+
+	void Music::stopSong() {
+		return _player->stopMusic();
+	}
 	
 } // End of namespace Queen





More information about the Scummvm-git-logs mailing list