[Scummvm-cvs-logs] SF.net SVN: scummvm: [28917] scummvm/trunk/engines/lure

dreammaster at users.sourceforge.net dreammaster at users.sourceforge.net
Sun Sep 16 06:06:49 CEST 2007


Revision: 28917
          http://scummvm.svn.sourceforge.net/scummvm/?rev=28917&view=rev
Author:   dreammaster
Date:     2007-09-15 21:06:49 -0700 (Sat, 15 Sep 2007)

Log Message:
-----------
Initial sound implementation

Modified Paths:
--------------
    scummvm/trunk/engines/lure/game.cpp
    scummvm/trunk/engines/lure/intro.cpp
    scummvm/trunk/engines/lure/lure.cpp
    scummvm/trunk/engines/lure/luredefs.h
    scummvm/trunk/engines/lure/scripts.cpp
    scummvm/trunk/engines/lure/scripts.h
    scummvm/trunk/engines/lure/sound.cpp
    scummvm/trunk/engines/lure/sound.h
    scummvm/trunk/engines/lure/surface.cpp

Modified: scummvm/trunk/engines/lure/game.cpp
===================================================================
--- scummvm/trunk/engines/lure/game.cpp	2007-09-16 04:05:56 UTC (rev 28916)
+++ scummvm/trunk/engines/lure/game.cpp	2007-09-16 04:06:49 UTC (rev 28917)
@@ -33,6 +33,7 @@
 #include "lure/strings.h"
 
 #include "common/config-manager.h"
+#include "common/system.h"
 
 namespace Lure {
 
@@ -300,7 +301,7 @@
 		break;
 
 	case MENUITEM_RESTART_GAME: 
-		doQuit();
+		doRestart();
 		break;
 
 	case MENUITEM_SAVE_GAME:
@@ -883,6 +884,7 @@
 
 	_soundFlag = !_soundFlag;
 	menu.getMenu(2).entries()[2] = sl.getString(_soundFlag ? S_SOUND_ON : S_SOUND_OFF);
+	Sound.setVolume(_soundFlag ? DEFAULT_VOLUME : 0);
 }
 
 void Game::handleBootParam(int value) {

Modified: scummvm/trunk/engines/lure/intro.cpp
===================================================================
--- scummvm/trunk/engines/lure/intro.cpp	2007-09-16 04:05:56 UTC (rev 28916)
+++ scummvm/trunk/engines/lure/intro.cpp	2007-09-16 04:06:49 UTC (rev 28917)
@@ -26,20 +26,26 @@
 #include "lure/intro.h"
 #include "lure/animseq.h"
 #include "lure/events.h"
+#include "lure/sound.h"
 
 namespace Lure {
 
 struct AnimRecord {
 	uint16 resourceId;
 	uint8 paletteIndex;
-	bool initialPause;
-	bool endingPause;
+	uint16 initialPause;
+	uint16 endingPause;
+	uint8 soundNumber;
 };
 
 static const uint16 start_screens[] = {0x18, 0x1A, 0x1E, 0x1C, 0};
-static const AnimRecord anim_screens[] = {{0x40, 0, true, true}, {0x42, 1, false, true}, 
-	{0x44, 2, false, false}, {0x24, 3, false, true}, {0x46, 3, false, false}, 
-	{0, 0, false, false}};
+static const AnimRecord anim_screens[] = {
+	{0x40, 0, 0x35A, 0xC8, 0},			// The kingdom was at peace
+	{0x42, 1, 0, 0x5FA, 1},				// Cliff overhang
+	{0x44, 2, 0, 0, 2},					// Siluette in moonlight
+	{0x24, 3, 0, 0x328 + 0x24, 0xff},	// Exposition of reaching town
+	{0x46, 3, 0, 0, 3},					// Skorl approaches
+	{0, 0, 0, 0, 0xff}};
 
 // showScreen
 // Shows a screen by loading it from the given resource, and then fading it in
@@ -73,25 +79,38 @@
 		if (showScreen(start_screens[ctr], start_screens[ctr] + 1, 5000)) 
 			return true;	
 
+	// Animated screens
+
 	AnimationSequence *anim;
 	bool result;
-
-	// Animated screens
-
+	uint8 currentSound = 0xff;
 	PaletteCollection coll(0x32);
 	const AnimRecord *curr_anim = anim_screens;
 	for (; curr_anim->resourceId; ++curr_anim) {
+		// Handle sound selection
+		if (curr_anim->soundNumber != 0xff) {
+			if (currentSound != 0xff) 
+				// Fade out the previous sound
+				Sound.fadeOut();
+		
+			currentSound = curr_anim->soundNumber;
+			Sound.musicInterface_Play(currentSound, 0);
+			// DEBUG TEST
+//			g_system->delayMillis(1000);
+//			Sound.musicInterface_Play(1, 1);
+		}
+
 		bool fadeIn = curr_anim == anim_screens;
 		anim = new AnimationSequence(_screen, _system, curr_anim->resourceId, 
 			coll.getPalette(curr_anim->paletteIndex), fadeIn);
-		if (curr_anim->initialPause) 
-			if (events.interruptableDelay(12000)) return true;
+		if (curr_anim->initialPause != 0)  
+			if (events.interruptableDelay(curr_anim->initialPause * 1000 / 50)) return true;
 
 		result = false;
 		switch (anim->show()) {
 			case ABORT_NONE:
-				if (curr_anim->endingPause) {
-					result = events.interruptableDelay(12000);
+				if (curr_anim->endingPause != 0) {
+					result = events.interruptableDelay(curr_anim->endingPause * 1000 / 50);
 				}
 				break;
 
@@ -104,7 +123,10 @@
 		}
 		delete anim;
 
-		if (result) return true;
+		if (result) {
+			Sound.musicInterface_KillAll();	
+			return true;
+		}
 	}
 
 	// Show battle pictures one frame at a time
@@ -118,12 +140,12 @@
 		if (result) break;
 	} while (anim->step());
 	delete anim;
-	if (result) return true;
+	
+	if (!result) 
+		// Show final introduction screen
+		showScreen(0x22, 0x21, 10000);
 
-	// Show final introduction screen
-
-	showScreen(0x22, 0x21, 10000);
-
+	Sound.musicInterface_KillAll();
 	return false;
 }
 

Modified: scummvm/trunk/engines/lure/lure.cpp
===================================================================
--- scummvm/trunk/engines/lure/lure.cpp	2007-09-16 04:05:56 UTC (rev 28916)
+++ scummvm/trunk/engines/lure/lure.cpp	2007-09-16 04:06:49 UTC (rev 28917)
@@ -34,6 +34,7 @@
 #include "lure/lure.h"
 #include "lure/intro.h"
 #include "lure/game.h"
+#include "lure/sound.h"
 
 namespace Lure {
 
@@ -45,17 +46,16 @@
 	Common::addSpecialDebugLevel(kLureDebugAnimations, "animations", "Animations debugging");
 	Common::addSpecialDebugLevel(kLureDebugHotspots, "hotspots", "Hotspots debugging");
 	Common::addSpecialDebugLevel(kLureDebugFights, "fights", "Fights debugging");
+	Common::addSpecialDebugLevel(kLureDebugSounds, "sounds", "Sounds debugging");
 
 	// Setup mixer
-/*
+
 	if (!_mixer->isReady()) {
 		warning("Sound initialization failed.");
 	}
 
 	_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume"));
 	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume"));
-	_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, ConfMan.getInt("speech_volume"));
-*/
 	
 	_features = 0;
 	_game = 0;
@@ -106,7 +106,9 @@
 int LureEngine::go() {
 	if (ConfMan.getInt("boot_param") == 0) {
 		// Show the introduction
+		Sound.loadSection(INTRO_SOUND_RESOURCE_ID);
 		Introduction *intro = new Introduction(*_screen, *_system);
+
 		intro->show();
 		delete intro;
 	}
@@ -114,6 +116,7 @@
 	// Play the game
 	if (!_events->quitFlag) {
 		// Play the game
+		Sound.loadSection(MAIN_SOUND_RESOURCE_ID);
 		Game *gameInstance = new Game();
 		gameInstance->execute();
 		delete gameInstance;

Modified: scummvm/trunk/engines/lure/luredefs.h
===================================================================
--- scummvm/trunk/engines/lure/luredefs.h	2007-09-16 04:05:56 UTC (rev 28916)
+++ scummvm/trunk/engines/lure/luredefs.h	2007-09-16 04:06:49 UTC (rev 28917)
@@ -45,7 +45,8 @@
 	kLureDebugScripts = 1 << 0,
 	kLureDebugAnimations = 1 << 1,
 	kLureDebugHotspots = 1 << 2,
-	kLureDebugFights = 1 << 3
+	kLureDebugFights = 1 << 3,
+	kLureDebugSounds = 1 << 4
 };
 
 #define ERROR_BASIC 1
@@ -229,6 +230,8 @@
 
 // Miscellaneous resources
 #define NAMES_RESOURCE_ID 9
+#define MAIN_SOUND_RESOURCE_ID 0xC
+#define INTRO_SOUND_RESOURCE_ID 0x31
 #define NOONE_ID 0x3E7
 #define PLAYER_ID 0x3E8
 #define RATPOUCH_ID 0x3E9
@@ -291,6 +294,7 @@
 #define EWAN_ALT_ANIM_ID 0x59ED
 #define PLAYER_ANIM_ID 0x5C80
 #define SELENA_ANIM_ID 0x5CAA
+#define DEFAULT_VOLUME 192
 
 #define CONVERSE_COUNTDOWN_SIZE 40
 #define IDLE_COUNTDOWN_SIZE 15

Modified: scummvm/trunk/engines/lure/scripts.cpp
===================================================================
--- scummvm/trunk/engines/lure/scripts.cpp	2007-09-16 04:05:56 UTC (rev 28916)
+++ scummvm/trunk/engines/lure/scripts.cpp	2007-09-16 04:06:49 UTC (rev 28917)
@@ -720,14 +720,11 @@
 
 // Checks if a sound is running
 
-void Script::checkSound(uint16 hotspotId, uint16 v2, uint16 v3) {
+void Script::checkSound(uint16 soundNumber, uint16 v2, uint16 v3) {
 	Sound.tidySounds();
 
-	// For now, simply set the general value field so that the Skorl schedule
-	// will work properly
-	Resources::getReference().fieldList().setField(GENERAL, 0);
-	
-	// TODO: Check whether active sound can be found or not
+	SoundDescResource *rec = Sound.findSound(soundNumber);
+	Resources::getReference().fieldList().setField(GENERAL, (rec != NULL) ? 1 : 0);
 }
 
 typedef void(*SequenceMethodPtr)(uint16, uint16, uint16);

Modified: scummvm/trunk/engines/lure/scripts.h
===================================================================
--- scummvm/trunk/engines/lure/scripts.h	2007-09-16 04:05:56 UTC (rev 28916)
+++ scummvm/trunk/engines/lure/scripts.h	2007-09-16 04:06:49 UTC (rev 28917)
@@ -142,7 +142,7 @@
 	static void addActions(uint16 hotspotId, uint16 actions, uint16 v3);
 	static void randomToGeneral(uint16 maxVal, uint16 minVal, uint16 v3);
 	static void checkCellDoor(uint16 v1, uint16 v2, uint16 v3);
-	static void checkSound(uint16 v1, uint16 v2, uint16 v3);
+	static void checkSound(uint16 soundNumber, uint16 v2, uint16 v3);
 };
 
 class HotspotScript {

Modified: scummvm/trunk/engines/lure/sound.cpp
===================================================================
--- scummvm/trunk/engines/lure/sound.cpp	2007-09-16 04:05:56 UTC (rev 28916)
+++ scummvm/trunk/engines/lure/sound.cpp	2007-09-16 04:06:49 UTC (rev 28917)
@@ -22,9 +22,14 @@
 
 #include "lure/sound.h"
 #include "lure/game.h"
+#include "lure/memory.h"
 #include "lure/res.h"
 #include "lure/room.h"
 
+#include "common/config-manager.h"
+#include "common/endian.h"
+#include "sound/midiparser.h"
+
 DECLARE_SINGLETON(Lure::SoundManager);
 
 namespace Lure {
@@ -32,12 +37,65 @@
 SoundManager::SoundManager() {
 	_descs = Disk::getReference().getEntry(SOUND_DESC_RESOURCE_ID);
 	_numDescs = _descs->size() / sizeof(SoundDescResource);
+	_soundData = NULL;
 
-	for (int channelNum = 0; channelNum < NUM_CHANNELS; ++channelNum)
-		_channels[channelNum] = 0;
+	int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PREFER_MIDI);
+	_nativeMT32 = ((midiDriver == MD_MT32) || ConfMan.getBool("native_mt32"));
+
+	memset(_channelsInUse, false, NUM_CHANNELS_OUTER);
+
+	_driver = MidiDriver::createMidi(midiDriver);
+	int statusCode = _driver->open();
+	if (statusCode) {
+		warning("Sound driver returned error code %d", statusCode);
+		_driver = NULL;
+
+	} else {
+		if (_nativeMT32)
+			_driver->property(MidiDriver::PROP_CHANNEL_MASK, 0x03FE);
+
+		for (int index = 0; index < NUM_CHANNELS_INNER; ++index) {
+			_channelsInner[index].midiChannel = _driver->allocateChannel();
+			_channelsInner[index].volume = DEFAULT_VOLUME;
+		}
+	}
 }
 
+SoundManager::~SoundManager() {
+	if (_driver)
+		_driver->setTimerCallback(this, NULL);
+
+	removeSounds();
+	_activeSounds.clear();
+	_playingSounds.clear();
+
+
+	delete _descs;
+	if (_soundData)
+		delete _soundData;
+
+	if (_driver)
+		_driver->close();
+	_driver = NULL;
+}
+
+void SoundManager::loadSection(uint16 sectionId) {
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::loadSection = %xh", sectionId);
+	killSounds();
+
+	if (_soundData) {
+		delete _soundData;
+		_driver->setTimerCallback(this, NULL);
+	}
+
+	_soundData = Disk::getReference().getEntry(sectionId);
+	_soundsTotal = *_soundData->data();
+
+	_driver->setTimerCallback(this, &onTimer);
+}
+
 void SoundManager::bellsBodge() {
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::bellsBodge");
 	Resources &res = Resources::getReference();
 	Room &room = Room::getReference();
 
@@ -64,16 +122,19 @@
 }
 
 void SoundManager::killSounds() {
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::killSounds");
+
 	// Stop the player playing all sounds
 	musicInterface_KillAll();
 
 	// Clear the active sounds
 	_activeSounds.clear();
-	for (int channelNum = 0; channelNum < NUM_CHANNELS; ++channelNum)
-		_channels[channelNum] = 0;
+	for (int channelNum = 0; channelNum < NUM_CHANNELS_INNER; ++channelNum)
+		_channelsInUse[channelNum] = false;
 }
 
 void SoundManager::addSound(uint8 soundIndex, bool tidyFlag) {
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::addSound index=%d", soundIndex);
 	Game &game = Game::getReference();
 
 	if (tidyFlag)
@@ -87,13 +148,13 @@
 	int numChannels = (rec.numChannels >> 2) & 3;
 
 	int channelCtr = 0;
-	while (channelCtr < NUM_CHANNELS) {
-		if (_channels[channelCtr] == 0) {
+	while (channelCtr <= (NUM_CHANNELS_OUTER - numChannels)) {
+		if (!_channelsInUse[channelCtr]) {
 			bool foundSpace = true;
 
-			int channelCtr2 = 0;
+			int channelCtr2 = 1;
 			while (channelCtr2 < numChannels) {
-				foundSpace = _channels[channelCtr2] == 0;
+				foundSpace = !_channelsInUse[channelCtr + channelCtr2];
 				if (!foundSpace) break;
 				++channelCtr2;
 			}
@@ -105,13 +166,15 @@
 		++channelCtr;
 	}
 
-	if (channelCtr == 8) 
+	if (channelCtr > NUM_CHANNELS_OUTER - numChannels) {
 		// No channels free
+		debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::addSound - no channels free");
 		return;
+	}
 
 	// Mark the found channels as in use
 	for (int channelCtr2 = 0; channelCtr2 < numChannels; ++channelCtr2)
-		_channels[channelCtr + channelCtr2] = 1;
+		_channelsInUse[channelCtr + channelCtr2] = true;
 
 	SoundDescResource *newEntry = new SoundDescResource();
 	newEntry->soundNumber = rec.soundNumber;
@@ -121,11 +184,18 @@
 	newEntry->volume = rec.volume;
 	_activeSounds.push_back(newEntry);
 
-	musicInterface_Play(rec.soundNumber, false, channelCtr);
+	// TODO: Figure a better way of sharing channels between multiple parsers - currently
+	// each parser seems to use 8 channels of a maximum 16 available, but here I'm 
+	// overlapping channels 4 - 7 (3rd & 4th parser) across the other two
+	byte innerChannel = (channelCtr < 4) ? ((channelCtr / 2) * 8) :
+		(4 + (channelCtr / 2) * 8);
+
+	musicInterface_Play(rec.soundNumber, innerChannel);
 	setVolume(rec.soundNumber, rec.volume);	
 }
 
 void SoundManager::addSound2(uint8 soundIndex) {
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::addSound2 index=%d", soundIndex);
 	tidySounds();
 
 	if (soundIndex == 6)
@@ -142,36 +212,55 @@
 
 
 void SoundManager::stopSound(uint8 soundIndex) {
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::stopSound index=%d", soundIndex);
 	SoundDescResource &rec = soundDescs()[soundIndex];
 	musicInterface_Stop(rec.soundNumber & 0x7f);
 }
 
 void SoundManager::killSound(uint8 soundNumber) {
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::stopSound soundNumber=%d", soundNumber);
 	musicInterface_Stop(soundNumber & 0x7f);
 }
 
 void SoundManager::setVolume(uint8 soundNumber, uint8 volume) {
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::setVolume soundNumber=%d, volume=%d", 
+		soundNumber, volume);
+	musicInterface_TidySounds();
+
 	SoundDescResource *entry = findSound(soundNumber);
-	if (entry  == NULL) return;
+	if (entry) 
+		musicInterface_SetVolume(entry->channel, volume);
+}
 
-	// Special check is done for Adlib in original game, to ignore any volume changes
+void SoundManager::setVolume(uint8 volume) {
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::setVolume volume=%d", volume);
+
+	for (int index = 0; index < NUM_CHANNELS_INNER; ++index) {
+		_channelsInner[index].midiChannel->volume(volume);
+		_channelsInner[index].volume = volume;
+	}
 }
 
 SoundDescResource *SoundManager::findSound(uint8 soundNumber) {
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::findSound soundNumber=%d", soundNumber);
 	ManagedList<SoundDescResource *>::iterator i;
 
 	for (i = _activeSounds.begin(); i != _activeSounds.end(); ++i) {
 		SoundDescResource *rec = *i;
 
-		if (rec->soundNumber == soundNumber)
+		if (rec->soundNumber == soundNumber) {
+			debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "SoundManager::findSound - sound found");
 			return rec;
+		}
 	}
 
 	// Signal that sound wasn't found
+	debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "SoundManager::findSound - sound not found");
 	return NULL;
 }
 
 void SoundManager::tidySounds() {
+	debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "SoundManager::tidySounds");
 	ManagedList<SoundDescResource *>::iterator i = _activeSounds.begin();
 
 	while (i != _activeSounds.end()) {
@@ -183,7 +272,7 @@
 		else {
 			// Mark the channels that it used as now being free
 			for (int channelCtr = 0; channelCtr < rec->numChannels; ++channelCtr) 
-				_channels[rec->channel + channelCtr] = 0;
+				_channelsInUse[rec->channel + channelCtr] = false;
 			
 			i = _activeSounds.erase(i);
 		}
@@ -191,6 +280,7 @@
 }
 
 void SoundManager::removeSounds() {
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::removeSounds");
 	bellsBodge();
 
 	ManagedList<SoundDescResource *>::iterator i = _activeSounds.begin();
@@ -206,7 +296,7 @@
 }
 
 void SoundManager::restoreSounds() {
-
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::restoreSounds");
 	ManagedList<SoundDescResource *>::iterator i = _activeSounds.begin();
 
 	while (i != _activeSounds.end()) {
@@ -214,9 +304,9 @@
 
 		if ((rec->numChannels != 0) && ((rec->flags & SF_RESTORE) != 0)) {
 			for (int channelCtr = 0; channelCtr < rec->numChannels; ++channelCtr)
-				_channels[rec->channel + channelCtr] = 1;
+				_channelsInUse[rec->channel + channelCtr] = true;
 
-			musicInterface_Play(rec->soundNumber, false, rec->channel);
+			musicInterface_Play(rec->soundNumber, rec->channel);
 			musicInterface_SetVolume(rec->soundNumber, rec->volume);
 		}
 
@@ -224,47 +314,314 @@
 	}
 }
 
+void SoundManager::fadeOut() {
+	debugC(ERROR_BASIC, kLureDebugSounds, "SoundManager::fadeOut");
 
+	// Fade out all the active sounds
+	musicInterface_TidySounds();
+
+	bool inProgress = true;
+	while (inProgress)
+	{
+		inProgress = false;
+
+		ManagedList<MidiMusic *>::iterator i;
+		for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) {
+			MidiMusic *music = *i;
+			if (music->getVolume() > 0) {
+				inProgress = true;
+				music->setVolume(music->getVolume() > 4 ? (music->getVolume() - 10) : 0);
+			}
+		}
+
+		g_system->delayMillis(10);
+	}
+
+	// Kill all the sounds
+	musicInterface_KillAll();
+}
+
 /*------------------------------------------------------------------------*/
 
-// musicInterface_CheckPlaying
+// musicInterface_Play
 // Play the specified sound
 
-void SoundManager::musicInterface_Play(uint8 soundNumber, bool isEffect, uint8 channelNumber) {
+void SoundManager::musicInterface_Play(uint8 soundNumber, uint8 channelNumber) {
+	debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "musicInterface_Play soundNumber=%d, channel=%d", 
+		soundNumber, channelNumber);
 
+	if (!_soundData)
+		error("Sound section has not been specified");
+
+	uint8 soundNum = soundNumber & 0x7f;
+	if (soundNum > _soundsTotal) 
+		error("Invalid sound index %d requested", soundNum);
+
+	if (_driver == NULL)
+		// Only play sounds if a sound driver is active
+		return;
+
+	uint32 dataOfs = READ_LE_UINT32(_soundData->data() + soundNum * 4 + 2);
+	uint8 *soundStart = _soundData->data() + dataOfs;
+	uint32 dataSize;
+
+	if (soundNumber == _soundsTotal - 1)
+		dataSize = _soundData->size() - dataOfs;
+	else {
+		uint32 nextDataOfs = READ_LE_UINT32(_soundData->data() + (soundNum + 1) * 4 + 2);
+		dataSize = nextDataOfs - dataOfs;
+	}
+
+	MidiMusic *sound = new MidiMusic(_driver, _channelsInner, channelNumber, soundNumber, 
+		soundStart, dataSize);
+	_playingSounds.push_back(sound);		
 }
 
 // musicInterface_Stop
 // Stops the specified sound from playing
 
 void SoundManager::musicInterface_Stop(uint8 soundNumber) {
-	
+	debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "musicInterface_Stop soundNumber=%d", soundNumber);
+	musicInterface_TidySounds();
+	uint8 soundNum = soundNumber & 0x7f;
+
+	ManagedList<MidiMusic *>::iterator i;
+	for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) {
+		MidiMusic *music = *i;
+		if (music->soundNumber() == soundNum) {
+			_playingSounds.erase(i);
+			return;
+		}
+	}
 }
 
 // musicInterface_CheckPlaying
-// Returns true if a sound is still player
+// Returns true if a sound is still playing
 
 bool SoundManager::musicInterface_CheckPlaying(uint8 soundNumber) {
-	return true;
+	debugC(ERROR_DETAILED, kLureDebugSounds, "musicInterface_CheckPlaying soundNumber=%d", soundNumber);
+	musicInterface_TidySounds();
+	uint8 soundNum = soundNumber & 0x7f;
+
+	ManagedList<MidiMusic *>::iterator i;
+	for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) {
+		MidiMusic *music = *i;
+		if (music->soundNumber() == soundNum) 
+			return true;
+	}
+
+	return false;
 }
 
 // musicInterface_SetVolume
 // Sets the volume of the specified channel
 
 void SoundManager::musicInterface_SetVolume(uint8 channelNum, uint8 volume) {
-	
+	debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "musicInterface_SetVolume channel=%d, volume=%d", 
+		channelNum, volume);
+	musicInterface_TidySounds();
+
+	ManagedList<MidiMusic *>::iterator i;
+	for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) {
+		MidiMusic *music = *i;
+		if (music->channelNumber() == channelNum)
+			music->setVolume(volume);
+	}
 }
 
+// musicInterface_KillAll
+// Stops all currently active sounds playing
+
 void SoundManager::musicInterface_KillAll() {
+	debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "musicInterface_KillAll");
+	musicInterface_TidySounds();
 
+	ManagedList<MidiMusic *>::iterator i;
+	for (i = _playingSounds.begin(); i != _playingSounds.end(); ++i) {
+		MidiMusic *music = *i;
+		music->stopMusic();
+	}
+
+	_playingSounds.clear();
+	_activeSounds.clear();
 }
 
+// musicInterface_ContinuePlaying
+// The original player used this method for any sound managers needing continual calls
+
 void SoundManager::musicInterface_ContinuePlaying() {
-
+	// No implementation needed
 }
 
+// musicInterface_TrashReverb
+// Trashes reverb on actively playing sounds
+
 void SoundManager::musicInterface_TrashReverb() {
+	// TODO: Handle support for trashing reverb
+	debugC(ERROR_INTERMEDIATE, kLureDebugSounds, "musicInterface_TrashReverb");
+}
 
+// musicInterface_KillAll
+// Scans all the active sounds and deallocates any objects that have finished playing
+
+void SoundManager::musicInterface_TidySounds() {
+	debugC(ERROR_DETAILED, kLureDebugSounds, "musicInterface_TidySounds");
+	ManagedList<MidiMusic *>::iterator i = _playingSounds.begin(); 
+	while (i != _playingSounds.end()) {
+		MidiMusic *music = *i;
+		if (!music->isPlaying()) 
+			i = _playingSounds.erase(i);
+		else
+			++i;
+	}
 }
 
+void SoundManager::onTimer(void *data) {
+	SoundManager *snd = (SoundManager *) data;
+
+	ManagedList<MidiMusic *>::iterator i;
+	for (i = snd->_playingSounds.begin(); i != snd->_playingSounds.end(); ++i) {
+		MidiMusic *music = *i;
+		if (music->isPlaying()) 
+			music->onTimer();
+	}
+}
+
+/*------------------------------------------------------------------------*/
+
+MidiMusic::MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS_INNER], 
+					 uint8 channelNum, uint8 soundNum, void *soundData, uint32 size) {
+
+	_driver = driver;
+	_channels = channels;
+	_soundNumber = soundNum;
+	_channelNumber = channelNum;
+	_numChannels = 8;
+	_volume = _channels[channelNum].volume;
+
+	_passThrough = false;
+
+	_parser = MidiParser::createParser_SMF();
+	_parser->setMidiDriver(this);
+	_parser->setTimerRate(_driver->getBaseTempo());
+
+	this->open();
+
+	_soundData = (uint8 *) soundData;
+	_soundSize = size;
+
+	// Check whether the music data is compressed - if so, decompress it for the duration 
+	// of playing the sound
+	
+	_decompressedSound = NULL;
+	if ((*_soundData == 'C') || (*_soundData == 'c')) {
+		uint32 packedSize = size - 0x201;
+		_decompressedSound = Memory::allocate(packedSize * 2);
+
+		uint16 *data = (uint16 *)(_soundData + 1);
+		uint16 *dataDest = (uint16 *) _decompressedSound->data();
+		byte *idx  = ((byte *)data) + 0x200;
+
+		for (uint i = 0; i < packedSize; i++)
+#if defined(SCUMM_NEED_ALIGNMENT)
+			memcpy(dataDest++, (byte*)((byte*)data + *(idx + i) * sizeof(uint16)), sizeof(uint16));
+#else
+			*dataDest++ = data[*(idx + i)];
+#endif
+
+		_soundData = _decompressedSound->data() + ((*_soundData == 'c') ? 1 : 0);
+		_soundSize = _decompressedSound->size();
+	}
+
+	playMusic();
+}
+
+MidiMusic::~MidiMusic() {
+	_parser->unloadMusic();
+	delete _parser;
+	this->close();
+	if (_decompressedSound != NULL) 
+		delete _decompressedSound;
+}
+
+void MidiMusic::setVolume(int volume) {
+	if (volume < 0)
+		volume = 0;
+	else if (volume > 255)
+		volume = 255;
+
+	if (_volume == volume)
+		return;
+
+	_volume = volume;
+
+	for (int i = 0; i < _numChannels; ++i) 
+		_channels[_channelNumber + i].midiChannel->volume(
+			_channels[_channelNumber + i].volume * _volume / 255);
+}
+
+void MidiMusic::playMusic() {
+	debugC(ERROR_DETAILED, kLureDebugSounds, "MidiMusic::PlayMusic playing sound %d", _soundNumber);
+	_parser->loadMusic(_soundData, _soundSize);
+	_parser->setTrack(0);
+	_isPlaying = true;
+}
+
+int MidiMusic::open() {
+	// Don't ever call open without first setting the output driver!
+	if (!_driver)
+		return 255;
+
+	return 0;
+}
+
+void MidiMusic::close() {
+}
+
+void MidiMusic::send(uint32 b) {
+	if (_passThrough) {
+		_driver->send(b);
+		return;
+	}
+
+	byte channel = _channelNumber + (byte)(b & 0x0F);
+	if ((channel >= NUM_CHANNELS_INNER) || (_channels[channel].midiChannel == NULL))
+		return;
+
+	if ((b & 0xFFF0) == 0x07B0) {
+		// Adjust volume changes by master volume
+		byte volume = (byte)((b >> 16) & 0x7F);
+		_channels[channel].volume = volume;
+		volume = volume * _volume / 255;
+		b = (b & 0xFF00FFFF) | (volume << 16);
+	} else if ((b & 0xF0) == 0xC0 && !_nativeMT32) {
+		b = (b & 0xFFFF00FF) | MidiDriver::_mt32ToGm[(b >> 8) & 0xFF] << 8;
+	}
+	else if ((b & 0xFFF0) == 0x007BB0) {
+		// No implementation
+	}
+
+	_channels[channel].midiChannel->send(b);
+}
+
+void MidiMusic::metaEvent(byte type, byte *data, uint16 length) {
+	//Only thing we care about is End of Track.
+	if (type != 0x2F)
+		return;
+
+	stopMusic();
+}
+
+void MidiMusic::onTimer() {
+	if (_isPlaying)
+		_parser->onTimer();
+}
+
+void MidiMusic::stopMusic() {
+	debugC(ERROR_DETAILED, kLureDebugSounds, "MidiMusic::stopMusic sound %d", _soundNumber);
+	_isPlaying = false;
+	_parser->unloadMusic();
+	close();
+}
+
 } // end of namespace Lure

Modified: scummvm/trunk/engines/lure/sound.h
===================================================================
--- scummvm/trunk/engines/lure/sound.h	2007-09-16 04:05:56 UTC (rev 28916)
+++ scummvm/trunk/engines/lure/sound.h	2007-09-16 04:06:49 UTC (rev 28917)
@@ -26,37 +26,123 @@
 #include "lure/luredefs.h"
 #include "lure/disk.h"
 #include "lure/memory.h"
+
 #include "common/singleton.h"
+#include "sound/mididrv.h"
+#include "sound/mixer.h"
 
+class MidiParser;
+
 namespace Lure {
 
-#define NUM_CHANNELS 8
+#define NUM_CHANNELS_OUTER 8
+#define NUM_CHANNELS_INNER 16
 
+struct ChannelEntry {
+	MidiChannel *midiChannel;
+	byte volume;
+};
+
+class MidiMusic: public MidiDriver {
+private:
+	uint8 _soundNumber;
+	uint8 _channelNumber;
+	uint8 _numChannels;
+	byte _volume;
+	MemoryBlock *_decompressedSound;
+	uint8 *_soundData;
+	uint8 _soundSize;
+	MidiDriver *_driver;
+	MidiParser *_parser;
+	ChannelEntry *_channels;
+	bool _isPlaying;
+	bool _nativeMT32;
+
+	void queueUpdatePos();
+	uint8 randomQueuePos();
+	uint32 songOffset(uint16 songNum) const;
+	uint32 songLength(uint16 songNum) const;
+
+	bool _passThrough;
+
+public:
+	MidiMusic(MidiDriver *driver, ChannelEntry channels[NUM_CHANNELS_INNER], 
+		uint8 channelNum, uint8 soundNum, void *soundData, uint32 size);
+	~MidiMusic();
+	void setVolume(int volume);
+	int getVolume()	{ return _volume; }
+
+	void hasNativeMT32(bool b)	{ _nativeMT32 = b; }
+	void playSong(uint16 songNum);
+	void stopSong() { stopMusic(); }
+	void playMusic();
+	void stopMusic();
+	void queueTuneList(int16 tuneList);
+	bool queueSong(uint16 songNum);
+	void setPassThrough(bool b) { _passThrough = b; }
+	void toggleVChange();
+
+	//MidiDriver interface implementation
+	int open();
+	void close();
+	void send(uint32 b);
+	void onTimer();
+
+	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; }
+
+	uint8 channelNumber() { return _channelNumber; }
+	uint8 soundNumber() { return _soundNumber; }
+	bool isPlaying() { return _isPlaying; }
+};
+
 class SoundManager: public Common::Singleton<SoundManager> {
 private:
+	// Outer sound interface properties
 	MemoryBlock *_descs;
+	MemoryBlock *_soundData;
+	uint8 _soundsTotal;
 	int _numDescs;
 	SoundDescResource *soundDescs() { return (SoundDescResource *) _descs->data(); }
+	MidiDriver *_driver;
 	ManagedList<SoundDescResource *> _activeSounds;
-	byte _channels[NUM_CHANNELS];
+	ManagedList<MidiMusic *> _playingSounds;
+	ChannelEntry _channelsInner[NUM_CHANNELS_INNER];
+	bool _channelsInUse[NUM_CHANNELS_OUTER];
+	bool _isPlaying;
+	bool _nativeMT32;
 
+	// Internal support methods
 	void bellsBodge();
+	void musicInterface_TidySounds();
+	static void onTimer(void *data);
 public:
 	SoundManager();
+	~SoundManager();
 
+	void loadSection(uint16 sectionId);
 	void killSounds();
 	void addSound(uint8 soundIndex, bool tidyFlag = true);
 	void addSound2(uint8 soundIndex);
 	void stopSound(uint8 soundIndex);
 	void killSound(uint8 soundNumber);
 	void setVolume(uint8 soundNumber, uint8 volume);
+	void setVolume(uint8 volume);
 	void tidySounds();
 	SoundDescResource *findSound(uint8 soundNumber);
 	void removeSounds();
 	void restoreSounds();
+	void fadeOut();
 
 	// The following methods implement the external sound player module
-	void musicInterface_Play(uint8 soundNumber, bool isEffect, uint8 channelNumber);
+	void musicInterface_Initialise();
+	void musicInterface_Play(uint8 soundNumber, uint8 channelNumber);
 	void musicInterface_Stop(uint8 soundNumber);
 	bool musicInterface_CheckPlaying(uint8 soundNumber);
 	void musicInterface_SetVolume(uint8 channelNum, uint8 volume);

Modified: scummvm/trunk/engines/lure/surface.cpp
===================================================================
--- scummvm/trunk/engines/lure/surface.cpp	2007-09-16 04:05:56 UTC (rev 28916)
+++ scummvm/trunk/engines/lure/surface.cpp	2007-09-16 04:06:49 UTC (rev 28917)
@@ -802,7 +802,7 @@
 	LureEngine &engine = LureEngine::getReference();
 
 	Sound.killSounds();
-	Sound.musicInterface_Play(60, true, 0);
+	Sound.musicInterface_Play(60, 0);
 	mouse.setCursorNum(CURSOR_ARROW);
 
 	// See if there are any savegames that can be restored


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