[Scummvm-cvs-logs] SF.net SVN: scummvm: [29881] scummvm/trunk/engines/kyra

lordhoto at users.sourceforge.net lordhoto at users.sourceforge.net
Sun Dec 16 19:48:44 CET 2007


Revision: 29881
          http://scummvm.svn.sourceforge.net/scummvm/?rev=29881&view=rev
Author:   lordhoto
Date:     2007-12-16 10:48:43 -0800 (Sun, 16 Dec 2007)

Log Message:
-----------
Commit of patch #1848147 "KYRA: SoundTowns Update" with some changes. Thanks to Florian for the patch.

Modified Paths:
--------------
    scummvm/trunk/engines/kyra/detection.cpp
    scummvm/trunk/engines/kyra/kyra.cpp
    scummvm/trunk/engines/kyra/kyra_v2.cpp
    scummvm/trunk/engines/kyra/kyra_v2.h
    scummvm/trunk/engines/kyra/sequences_v2.cpp
    scummvm/trunk/engines/kyra/sound.h
    scummvm/trunk/engines/kyra/sound_towns.cpp

Modified: scummvm/trunk/engines/kyra/detection.cpp
===================================================================
--- scummvm/trunk/engines/kyra/detection.cpp	2007-12-16 17:28:52 UTC (rev 29880)
+++ scummvm/trunk/engines/kyra/detection.cpp	2007-12-16 18:48:43 UTC (rev 29881)
@@ -51,6 +51,8 @@
 
 #define KYRA2_CD_FLAGS FLAGS(false, false, true, false, Kyra::GI_KYRA2)
 #define KYRA2_DEMO_FLAGS FLAGS(true, false, false, false, Kyra::GI_KYRA2)
+#define KYRA2_TOWNS_FLAGS FLAGS(false, false, false, false, Kyra::GI_KYRA2)
+#define KYRA2_TOWNS_SJIS_FLAGS FLAGS(false, false, false, true, Kyra::GI_KYRA2)
 
 #define KYRA3_CD_FLAGS FLAGS(false, false, true, false, Kyra::GI_KYRA3)
 
@@ -176,7 +178,11 @@
 		{
 			"kyra1",
 			0,
-			AD_ENTRY1("TWMUSIC.PAK", "e53bca3a3e3fb49107d59463ec387a59"),
+			{
+				{ "EMC.PAK", 0, "a046bb0b422061aab8e4c4689400343a", -1 },
+				{ "TWMUSIC.PAK", 0, "e53bca3a3e3fb49107d59463ec387a59", -1 },
+				{ NULL, 0, NULL, 0 }
+			},
 			Common::EN_ANY,
 			Common::kPlatformFMTowns,
 			Common::ADGF_NO_FLAGS
@@ -187,7 +193,11 @@
 		{
 			"kyra1",
 			0,
-			AD_ENTRY1("TWMUSIC.PAK", "e53bca3a3e3fb49107d59463ec387a59"),
+			{
+				{ "JMC.PAK", 0, "9c5707a2a478e8167e44283246612d2c", -1 },
+				{ "TWMUSIC.PAK", 0, "e53bca3a3e3fb49107d59463ec387a59", -1 },
+				{ NULL, 0, NULL, 0 }
+			},
 			Common::JA_JPN,
 			Common::kPlatformFMTowns,
 			Common::ADGF_NO_FLAGS
@@ -330,8 +340,31 @@
 		KYRA2_DEMO_FLAGS
 	},
 
+	{ // FM-Towns
+		{
+			"kyra2",
+			0,
+			AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"),
+			Common::EN_ANY,
+			Common::kPlatformFMTowns,
+			Common::ADGF_NO_FLAGS
+		},
+		KYRA2_TOWNS_FLAGS
+	},
 	{
 		{
+			"kyra2",
+			0,
+			AD_ENTRY1("WSCORE.PAK", "c44de1302b67f27d4707409987b7a685"),
+			Common::JA_JPN,
+			Common::kPlatformFMTowns,
+			Common::ADGF_NO_FLAGS
+		},
+		KYRA2_TOWNS_SJIS_FLAGS
+	},
+
+	{
+		{
 			"kyra3",
 			0,
 			AD_ENTRY1("ONETIME.PAK", "3833ff312757b8e6147f464cca0a6587"),
@@ -402,7 +435,7 @@
 	bool res = true;
 
 	Kyra::GameFlags flags = gd->flags;
-	
+
 	flags.lang = gd->desc.language;
 	flags.platform = gd->desc.platform;
 
@@ -440,3 +473,4 @@
 
 REGISTER_PLUGIN(KYRA, "Legend of Kyrandia Engine", "The Legend of Kyrandia (C) Westwood Studios");
 
+

Modified: scummvm/trunk/engines/kyra/kyra.cpp
===================================================================
--- scummvm/trunk/engines/kyra/kyra.cpp	2007-12-16 17:28:52 UTC (rev 29880)
+++ scummvm/trunk/engines/kyra/kyra.cpp	2007-12-16 18:48:43 UTC (rev 29881)
@@ -92,15 +92,31 @@
 		// for now we prefer Adlib over native MIDI
 	int midiDriver = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB/* | MDT_PREFER_MIDI*/);
 
-	if (_flags.platform == Common::kPlatformFMTowns) {
-		// TODO: later on here should be a usage of MixedSoundDriver
-		_sound = new SoundTowns(this, _mixer);
-	} else if (_flags.platform == Common::kPlatformPC98) {
+	if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) {
 		// TODO: currently we don't support the PC98 sound data,
 		// but since it has the FM-Towns data files, we just use the
 		// FM-Towns driver
-		// TODO: later on here should be a usage of MixedSoundDriver
-		_sound = new SoundTowns(this, _mixer);
+
+		// Since we handle the volume internally for our FM-Towns driver we set the global
+		// volume for those sound types to the maximum.
+		_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, Audio::Mixer::kMaxMixerVolume);
+		_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, Audio::Mixer::kMaxMixerVolume);
+
+		if (_flags.gameID == GI_KYRA1) {
+			SoundTowns *snd = new SoundTowns(this, _mixer);
+
+			snd->setMusicVolume(ConfMan.getInt("music_volume"));
+			snd->setSoundEffectsVolume(ConfMan.getInt("sfx_volume"));
+
+			_sound = snd;
+		} else {
+			SoundTowns_v2 *snd = new SoundTowns_v2(this, _mixer);
+
+			snd->setMusicVolume(ConfMan.getInt("music_volume"));
+			snd->setSoundEffectsVolume(ConfMan.getInt("sfx_volume"));
+
+			_sound = snd;
+		}
 	} else if (midiDriver == MD_ADLIB) {
 		_sound = new SoundAdlibPC(this, _mixer);
 		assert(_sound);
@@ -232,3 +248,4 @@
 
 } // End of namespace Kyra
 
+

Modified: scummvm/trunk/engines/kyra/kyra_v2.cpp
===================================================================
--- scummvm/trunk/engines/kyra/kyra_v2.cpp	2007-12-16 17:28:52 UTC (rev 29880)
+++ scummvm/trunk/engines/kyra/kyra_v2.cpp	2007-12-16 18:48:43 UTC (rev 29881)
@@ -127,6 +127,9 @@
 	_screen->setAnimBlockPtr(3504);
 	_screen->setScreenDim(0);
 
+	if (!_sound->init())
+		error("Couldn't init sound");
+
 	_abortIntroFlag = false;
 
 	// temporary solution until staticres manager support (kyra.dat) is added for kyra 2
@@ -145,7 +148,7 @@
 	}
 
 	for (int i = 0; i < 33; i++)
-		_sequenceStringsDuration[i] = strlen(_sequenceStrings[i]) * 8;
+		_sequenceStringsDuration[i] = (int) strlen(_sequenceStrings[i]) * 8;
 
 	// No mouse display in demo
 	if (_flags.isDemo)
@@ -164,10 +167,8 @@
 }
 
 int KyraEngine_v2::go() {
-	// Temporary measure to work around the fact that there's
-	// several WSA files with identical names in different PAK files.
-	_res->unloadPakFile("OUTFARM.PAK");
-	_res->unloadPakFile("FLYTRAP.PAK");
+	if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)
+		seq_showStarcraftLogo();
 
 	seq_playSequences(kSequenceVirgin, kSequenceZanfaun);
 	//seq_playSequences(kSequenceFunters, kSequenceFrash);
@@ -175,7 +176,26 @@
 	if (_menuChoice == 1) {
 		// load just the pak files needed for ingame
 		_res->unloadAllPakFiles();
-		_res->loadFileList("FILEDATA.FDT");
+		if (_flags.platform == Common::kPlatformPC && (_flags.isTalkie || _flags.isDemo)) {
+			_res->loadFileList("FILEDATA.FDT");
+		} else if (_flags.platform == Common::kPlatformPC) {
+			//TODO
+		} else if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98) {
+			char tmpfilename[13];
+			static const char * pakfiles [] = { "KYRA.DAT", "AUDIO.PAK", "CAULDRON.PAK",
+				"MISC_CPS.PAK", "MISC_EMC.PAK", "OTHER.PAK", "VOC.PAK", "WSCORE.PAK" };
+			for (int i = 0; i < 8; i++)
+				_res->loadPakFile(pakfiles[i]);
+			for (int i = 1; i < 10; i++) {
+				sprintf(tmpfilename, "COST%d_SH.PAK", i);
+				_res->loadPakFile(tmpfilename);
+			}
+			for (int i = 1; i < 6; i++) {
+				sprintf(tmpfilename, "HOFCH_%d.PAK", i);
+				_res->loadPakFile(tmpfilename);
+			}
+		}
+
 		startup();
 		runLoop();
 		cleanup();
@@ -187,7 +207,9 @@
 }
 
 void KyraEngine_v2::startup() {
-	_sound->setSoundFileList(_dosSoundFileList, _dosSoundFileListSize);
+	snd_assignMusicData(kMusicIngame);
+	// The track map is exactly the same
+	// for FM-TOWNS and DOS
 	_trackMap = _dosTrackMap;
 	_trackMapSize = _dosTrackMapSize;
 
@@ -306,7 +328,7 @@
 		//	waitTicks(5);
 		//	sub_270A0();
 		//}
-		
+
 		if (_system->getMillis() > _nextIdleAnim)
 			showIdleAnim();
 
@@ -1540,6 +1562,19 @@
 	_sound->loadSoundFile(file);
 }
 
+void KyraEngine_v2::snd_assignMusicData(kMusicDataID id) {
+	if (_flags.platform == Common::kPlatformPC) {
+		if (id == kMusicIntro)
+			_sound->setSoundFileList(_dosSoundFileListIntro, 1);
+		else if (id == kMusicFinale)
+			_sound->setSoundFileList(_dosSoundFileListFinale, 1);
+		else
+			_sound->setSoundFileList(_dosSoundFileList, _dosSoundFileListSize);
+	} else {
+		_sound->assignData(id);
+	}
+}
+
 void KyraEngine_v2::playVoice(int high, int low) {
 	int vocFile = high * 10000 + low * 10;
 	snd_playVoiceFile(vocFile);
@@ -1632,7 +1667,7 @@
 		case 48:
 			snd_playSoundEffect(0x38);
 			break;
-		
+
 		default:
 			break;
 		}
@@ -1904,4 +1939,3 @@
 
 } // end of namespace Kyra
 
-

Modified: scummvm/trunk/engines/kyra/kyra_v2.h
===================================================================
--- scummvm/trunk/engines/kyra/kyra_v2.h	2007-12-16 17:28:52 UTC (rev 29880)
+++ scummvm/trunk/engines/kyra/kyra_v2.h	2007-12-16 18:48:43 UTC (rev 29881)
@@ -74,6 +74,7 @@
 	kSequenceHand4
 };
 
+
 class WSAMovieV2;
 class KyraEngine_v2;
 class TextDisplayer_v2;
@@ -143,6 +144,12 @@
 	uint16 unk1;
 };
 
+enum kMusicDataID {
+	kMusicIntro = 0,
+	kMusicIngame,
+	kMusicFinale
+};
+
 class KyraEngine_v2 : public KyraEngine {
 friend class Debugger_v2;
 friend class TextDisplayer_v2;
@@ -225,6 +232,8 @@
 	void seq_printCreditsString(uint16 strIndex, int x, int y, uint8 * colorMap, uint8 textcolor);
 	void seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, int textColor, int x, int y, int width,
 		WSAMovieV2 * wsa, int firstframe, int lastframe, int wsaXpos, int wsaYpos);
+	int seq_generateFixedRandomValue(int rangeFirst, int rangeLast);
+	void seq_showStarcraftLogo();
 
 	void seq_init();
 	void seq_uninit();
@@ -246,13 +255,6 @@
 	static const int8 _dosTrackMap[];
 	static const int _dosTrackMapSize;
 
-	static const char *_introSoundList[];
-	static const int _introSoundListSize;
-	static const char *_introStrings[];
-	static const int _introStringsSize;
-
-	int _introStringsDuration[21];
-
 protected:
 	// game initialization
 	void startup();
@@ -628,6 +630,7 @@
 
 	virtual void snd_playVoiceFile(int id);
 	void snd_loadSoundFile(int id);
+	void snd_assignMusicData(kMusicDataID id);
 
 	void playVoice(int high, int low);
 
@@ -639,7 +642,7 @@
 	void timerFunc6(int);
 
 	void setTimer1DelaySecs(int secs);
-	
+
 	uint32 _nextIdleAnim;
 	int _lastIdleScript;
 
@@ -846,6 +849,8 @@
 	static const int _sequenceStringsSize_TOWNS_EN;
 	static const char *_sequenceStrings_PC_EN[];
 	static const int _sequenceStringsSize_PC_EN;
+	static const char _actorScreenStrings_PC_EN[];
+	static const int _actorScreenStringsSize_PC_EN;
 
 	int _sequenceStringsDuration[33];
 
@@ -861,6 +866,7 @@
 	int _seqFrameCounter;
 	int _seqWsaCurrentFrame;
 	bool _seqSpecialFlag;
+	int _seqRandomizeBase;
 	bool _seqSubframePlaying;
 	uint8 _seqTextColor[2];
 	uint8 _seqTextColorMap[16];
@@ -883,3 +889,4 @@
 #endif
 
 
+

Modified: scummvm/trunk/engines/kyra/sequences_v2.cpp
===================================================================
--- scummvm/trunk/engines/kyra/sequences_v2.cpp	2007-12-16 17:28:52 UTC (rev 29880)
+++ scummvm/trunk/engines/kyra/sequences_v2.cpp	2007-12-16 18:48:43 UTC (rev 29881)
@@ -53,9 +53,7 @@
 		};
 		_sound->setSoundFileList(soundFileList, 2);
 	} else {
-		const char *const *soundFileList =
-			(startSeq > kSequenceZanfaun) ?	_dosSoundFileListFinale : _dosSoundFileListIntro;
-		_sound->setSoundFileList(soundFileList, 1);
+		snd_assignMusicData((startSeq > kSequenceZanfaun) ?	kMusicFinale : kMusicIntro);
 	}
 	_sound->loadSoundFile(0);
 
@@ -1445,7 +1443,6 @@
 }
 
 int KyraEngine_v2::seq_finaleFrash(WSAMovieV2 *wsaObj, int x, int y, int frm) {
-	//uint32 endtime = 0;
 	int tmp = 0;
 
 	switch (frm) {
@@ -1462,7 +1459,8 @@
 		case -1:
 			// if (_flags.isTalkie)
 			//	 seq_finaleActorScreen();
-			_seqSpecialFlag = true;
+			_seqSpecialFlag = _flags.isTalkie;
+			_seqRandomizeBase = 1;
 			break;
 
 		case 0:
@@ -1480,7 +1478,7 @@
 			if (_seqFrameCounter < 20 && _seqSpecialFlag) {
 				_seqWsaCurrentFrame = 0;
 			} else {
-				_seqFrameDelay = 500;
+				_seqFrameDelay = _flags.isTalkie ? 500 : (300 + seq_generateFixedRandomValue(1, 300));
 				seq_playTalkText(_flags.isTalkie ? 26 : 22);
 				if (_seqSpecialFlag) {
 					_seqFrameCounter = 3;
@@ -1495,7 +1493,7 @@
 
 		case 3:
 			seq_playTalkText(_flags.isTalkie ? 27 : 23);
-			_seqFrameDelay = 500;
+			_seqFrameDelay = _flags.isTalkie ? 500 : (300 + seq_generateFixedRandomValue(1, 300));
 			break;
 
 		case 4:
@@ -1506,9 +1504,9 @@
 			seq_playTalkText(_flags.isTalkie ? 27 : 23);
 			tmp = _seqFrameCounter / 6;
 			if (tmp == 2)
-				_seqFrameDelay = 7;
+				_seqFrameDelay = _flags.isTalkie ? 7 : (1 + seq_generateFixedRandomValue(1, 10));
 			else if (tmp < 2)
-				_seqFrameDelay = 500;
+				_seqFrameDelay = _flags.isTalkie ? 500 : (300 + seq_generateFixedRandomValue(1, 300));
 			break;
 
 		case 6:
@@ -1543,7 +1541,7 @@
 	_screen->loadBitmap("finale.cps", 3, 3, _screen->_currentPalette);
 	_screen->setFont(Screen::FID_GOLDFONT_FNT);
 
-	_sound->setSoundFileList(_dosSoundFileList, _dosSoundFileListSize);
+	snd_assignMusicData(kMusicIngame);
 	_sound->loadSoundFile(3);
 	_sound->playTrack(3);
 
@@ -1552,7 +1550,7 @@
 
 	// TODO
 
-	_sound->setSoundFileList(_dosSoundFileListFinale, 1);
+	snd_assignMusicData(kMusicFinale);
 	_sound->loadSoundFile(0);
 }
 
@@ -2098,7 +2096,7 @@
 }
 
 void KyraEngine_v2::seq_playWsaSyncDialogue(uint16 strIndex, uint16 vocIndex, int textColor, int x, int y, int width, WSAMovieV2 * wsa, int firstframe, int lastframe, int wsaXpos, int wsaYpos) {
-	int dur = strlen(_sequenceStrings[strIndex]) * (_flags.isTalkie ? 7 : 15);
+	int dur = int(strlen(_sequenceStrings[strIndex])) * (_flags.isTalkie ? 7 : 15);
 	int entry = seq_setTextEntry(strIndex, x, y, dur, width);
 	_activeText[entry].textcolor = textColor;
 	uint32 chatTimeout = _system->getMillis() + dur * _tickLength;
@@ -2139,8 +2137,6 @@
 		curframe++;
 	}
 
-
-
 	if (lastframe < 0) {
 		int t = ABS(lastframe);
 		if (t < curframe)
@@ -2153,11 +2149,81 @@
 	_seqWsaCurrentFrame = curframe;
 }
 
+int KyraEngine_v2::seq_generateFixedRandomValue(int rangeFirst, int rangeLast) {
+	int result = 0;
+	if (rangeFirst > rangeFirst)
+		SWAP(rangeFirst, rangeLast);
+	int range = (rangeLast - rangeFirst) + 1;
+
+	do {
+		_seqRandomizeBase = _seqRandomizeBase * 1103515245 + 12345;
+		result = ((range * ((_seqRandomizeBase % 0x7fffffff) & 0x7fff)) / 32768) + rangeFirst;
+	} while (rangeLast < result);
+
+	return result;
+}
+
+void KyraEngine_v2::seq_showStarcraftLogo() {
+	WSAMovieV2 * ci = new WSAMovieV2(this);
+	assert(ci);
+	_screen->clearPage(2);
+	_res->loadPakFile("INTROGEN.PAK");
+	int endframe = ci->open("ci.wsa", 0, _screen->_currentPalette);
+	_res->unloadPakFile("INTROGEN.PAK");
+	if (!ci->opened()) {
+		delete ci;
+		return;
+	}
+	_screen->hideMouse();
+	ci->setX(0);
+	ci->setY(0);
+	ci->setDrawPage(2);
+	ci->displayFrame(0, 0);
+	_screen->copyPage(2, 0);
+	_screen->fadeFromBlack();
+	for (int i = 1; i < endframe; i++) {
+		if (_skipFlag)
+			break;
+		ci->displayFrame(i, 0);
+		_screen->copyPage(2, 0);
+		_screen->updateScreen();
+		delay(50);
+	}
+	if(!_skipFlag) {
+		ci->displayFrame(0, 0);
+		_screen->copyPage(2, 0);
+		_screen->updateScreen();
+		delay(50);
+	}
+	_screen->fadeToBlack();
+	_screen->showMouse();
+
+	_skipFlag = false;
+	delete ci;
+}
+
 void KyraEngine_v2::seq_init() {
 	_seqProcessedString = new char[200];
 	_seqWsa = new WSAMovieV2(this);
 	_activeWSA = new ActiveWSA[8];
 	_activeText = new ActiveText[10];
+
+	_res->unloadAllPakFiles();
+	_res->loadPakFile("KYRA.DAT");
+	_res->loadPakFile("AUDIO.PAK");
+	_res->loadPakFile("INTROGEN.PAK");
+	_res->loadPakFile("OTHER.PAK");
+	_res->loadPakFile("VOC.PAK");
+	if (_flags.isTalkie) {
+		_res->loadPakFile("TALKENG.PAK");
+		_res->loadPakFile("TALKGER.PAK");
+		_res->loadPakFile("TALKFRE.PAK");
+		_res->loadPakFile("INTROTLK.PAK");
+	} else {
+		_res->loadPakFile("INTROVOC.PAK");
+		if (_flags.platform == Common::kPlatformFMTowns || _flags.platform == Common::kPlatformPC98)
+			_res->loadPakFile("WSCORE.PAK");
+	}
 }
 
 void KyraEngine_v2::seq_uninit() {
@@ -2181,7 +2247,7 @@
 void KyraEngine_v2::seq_makeBookOrCauldronAppear(int type) {
 	_screen->hideMouse();
 	showMessage(0, 0xCF);
-	
+
 	if (type == 1) {
 		seq_makeBookAppear();
 	} else if (type == 2) {
@@ -2190,7 +2256,7 @@
 
 	_screen->copyRegionToBuffer(2, 0, 0, 320, 200, _screenBuffer);
 	_screen->loadBitmap("_PLAYALL.CPS", 3, 3, 0);
-	
+
 	static int16 bookCauldronRects[] = {
 		0x46, 0x90, 0x7F, 0x2B,	// unknown rect (maybe unused?)
 		0xCE, 0x90, 0x2C, 0x2C,	// book rect
@@ -2215,16 +2281,16 @@
 
 void KyraEngine_v2::seq_makeBookAppear() {
 	_screen->hideMouse();
-	
+
 	displayInvWsaLastFrame();
-	
+
 	showMessage(0, 0xCF);
 
 	loadInvWsa("BOOK2.WSA", 0, 4, 2, -1, -1, 0);
-	
+
 	uint8 *rect = new uint8[_screen->getRectSize(_invWsa.w, _invWsa.h)];
 	assert(rect);
-	
+
 	_screen->copyRegionToBuffer(_invWsa.page, _invWsa.x, _invWsa.y, _invWsa.w, _invWsa.h, rect);
 
 	_invWsa.running = false;
@@ -2236,19 +2302,19 @@
 
 	while (true) {
 		_invWsa.timer = _system->getMillis() + _invWsa.delay * _tickLength;
-		
+
 		_screen->copyBlockToPage(_invWsa.page, _invWsa.x, _invWsa.y, _invWsa.w, _invWsa.h, rect);
 
 		_invWsa.wsa->displayFrame(_invWsa.curFrame, 0x4000, 0, 0);
 
 		if (_invWsa.page)
 			_screen->copyRegion(_invWsa.x, _invWsa.y, _invWsa.x, _invWsa.y, _invWsa.w, _invWsa.h, _invWsa.page, 0, Screen::CR_NO_P_CHECK);
-		
+
 		++_invWsa.curFrame;
 
 		if (_invWsa.curFrame >= _invWsa.lastFrame && !_quitFlag)
 			break;
-		
+
 		switch (_invWsa.curFrame) {
 		case 39:
 			snd_playSoundEffect(0xCA);
@@ -2384,3 +2450,4 @@
 
 } // end of namespace Kyra
 
+

Modified: scummvm/trunk/engines/kyra/sound.h
===================================================================
--- scummvm/trunk/engines/kyra/sound.h	2007-12-16 17:28:52 UTC (rev 29880)
+++ scummvm/trunk/engines/kyra/sound.h	2007-12-16 18:48:43 UTC (rev 29881)
@@ -52,6 +52,7 @@
 #include "sound/softsynth/ym2612.h"
 
 #include "kyra/kyra.h"
+#include "kyra/kyra_v2.h"
 
 namespace Audio {
 class AudioStream;
@@ -59,7 +60,7 @@
 
 namespace Kyra {
 
-/** 
+/**
  * Analog audio output device API for Kyrandia games.
  * It countains functionallity to play music tracks,
  * sound effects and voices.
@@ -109,6 +110,20 @@
 	virtual void setSoundFileList(const char * const *list, uint s) { _soundFileList = list; _soundFileListSize = s; }
 
 	/**
+	 * Selects preset bundles of music files
+	 * and cd audio tracks the output device will use
+	 * when playing a track and/or sound effect.
+	 *
+	 * TODO: this is just needed for Kyrandia 2 FM-Towns version,
+	 * and is similar to what setSoundFileList is used for, so we
+	 * should think of a better solution than this.
+	 * @see setSoundFileList
+	 *
+	 * @param id	kMusicIntro, kMusicIngame or kMusicFinale
+	 */	
+	virtual void assignData(kMusicDataID id) { _currentTheme = id; }
+
+	/**
 	 * Load a specifc sound file for use of
 	 * playing music and sound effects.
 	 */
@@ -161,7 +176,7 @@
 	 *
 	 * @param file	file to be played
 	 */
-	void voicePlay(const char *file);
+	virtual void voicePlay(const char *file);
 
 	/**
 	 * Checks if a voice is being played.
@@ -180,6 +195,8 @@
 	int _musicEnabled;
 	bool _sfxEnabled;
 
+	int _currentTheme;
+
 	KyraEngine *_vm;
 	Audio::Mixer *_mixer;
 
@@ -213,7 +230,7 @@
  * Dune II, Kyrandia 1 and 2. While Dune II and
  * Kyrandia 1 are using exact the same format, the
  * one of Kyrandia 2 slightly differs.
- * 
+ *
  * See AdlibDriver for more information.
  * @see AdlibDriver
  */
@@ -268,7 +285,7 @@
  *
  * Currently it does not initialize the MT-32 output properly,
  * so MT-32 output does sound a bit odd in some cases.
- * 
+ *
  * TODO: this code needs some serious cleanup and rework
  * to support MT-32 and GM properly.
  */
@@ -341,7 +358,7 @@
 	Common::Mutex _mutex;
 };
 
-class FMT_EuphonyDriver;
+class SoundTowns_EuphonyDriver;
 class SoundTowns : public MidiDriver, public Sound {
 public:
 	SoundTowns(KyraEngine *vm, Audio::Mixer *mixer);
@@ -350,9 +367,15 @@
 	bool init();
 	void process();
 
-	void setVolume(int) { /* TODO */ }
-	int getVolume() { return 255; /* TODO */ }
+	void setVolume(int) {}
+	int getVolume() { return 255; }
 
+	// TODO: this should be moved to Sound or at least
+	// supplied by Sound as a pure virtual method.
+	// TODO: define ranges for those two functions
+	void setMusicVolume(int volume);
+	void setSoundEffectsVolume(int volume) { _sfxVolume = CLIP(volume, 0, 255); }
+
 	void loadSoundFile(uint file);
 
 	void playTrack(uint8 track);
@@ -387,22 +410,67 @@
 	Audio::AudioStream *_currentSFX;
 	Audio::SoundHandle _sfxHandle;
 
-	int _currentTrackTable;
 	uint _sfxFileIndex;
 	uint8 *_sfxFileData;
+	uint8 _sfxVolume;
 
-	FMT_EuphonyDriver * _driver;
+	SoundTowns_EuphonyDriver * _driver;
 	MidiParser * _parser;
-	uint8 *_musicTrackData;
 
 	Common::Mutex _mutex;
 
-	static const char *_sfxFiles[];
-	static const int _sfxFilenum;
 	static const uint8 _sfxBTTable[256];
 	const uint8 *_sfxWDTable;
 };
 
+//class SoundTowns_v2_TwnDriver;
+class SoundTowns_v2 : public Sound {
+public:
+	SoundTowns_v2(KyraEngine *vm, Audio::Mixer *mixer);
+	~SoundTowns_v2();
+
+	bool init();
+	void process();
+
+	void setVolume(int) {}
+	int getVolume() { return 255; }
+
+	// TODO: this should be moved to Sound or at least
+	// supplied by Sound as a pure virtual method.
+	// TODO: define ranges for those two functions
+	void setMusicVolume(int volume);
+	void setSoundEffectsVolume(int volume) { _sfxVolume = CLIP(volume, 0, 255); }
+
+	void loadSoundFile(uint file) {}
+
+	void playTrack(uint8 track);
+	void haltTrack();
+	void beginFadeOut();
+
+	void voicePlay(const char *file);
+	void playSoundEffect(uint8) {}
+
+private:
+	int _lastTrack;
+
+	Audio::AudioStream *_currentSFX;
+	Audio::SoundHandle _sfxHandle;
+	uint8 _sfxVolume;
+
+	//SoundTowns_v2_TwnDriver * _driver;
+	uint8 * _twnTrackData;
+
+	static const uint8 _cdaTrackTableK2Intro[];
+	static const uint8 _cdaTrackTableK2Ingame[];
+	static const uint8 _cdaTrackTableK2Finale[];
+
+	static const struct Kyra2AudioThemes {
+		const uint8 * cdaTable;
+		const uint8 cdaTableSize;
+		const char * twnFilename;
+	} _themes[];
+};
+
 class MixedSoundDriver : public Sound {
 public:
 	MixedSoundDriver(KyraEngine *vm, Audio::Mixer *mixer, Sound *music, Sound *sfx) : Sound(vm, mixer), _music(music), _sfx(sfx) {}

Modified: scummvm/trunk/engines/kyra/sound_towns.cpp
===================================================================
--- scummvm/trunk/engines/kyra/sound_towns.cpp	2007-12-16 17:28:52 UTC (rev 29880)
+++ scummvm/trunk/engines/kyra/sound_towns.cpp	2007-12-16 18:48:43 UTC (rev 29881)
@@ -33,11 +33,14 @@
 #include "sound/audiostream.h"
 
 #include "common/util.h"
+
 #include <math.h>
 
+#define		EUPHONY_FADEOUT_TICKS		600
+
 namespace Kyra {
 
-enum EuD_ChannelState { _s_ready, _s_attacking, _s_decaying, _s_sustaining, _s_releasing };
+enum ChannelState { _s_ready, _s_attacking, _s_decaying, _s_sustaining, _s_releasing };
 
 class MidiChannel_EuD : public MidiChannel {
 public:
@@ -125,7 +128,7 @@
 			const int8 *_samples;
 		} * _snd[8];
 		struct Env {
-			EuD_ChannelState state;
+			ChannelState state;
 			int32 currentLevel;
 			int32 rate;
 			int32 tickCount;
@@ -142,16 +145,43 @@
 	} * _voice;
 };
 
+class SoundTowns_EuphonyTrackQueue {
+public:
+	SoundTowns_EuphonyTrackQueue(SoundTowns_EuphonyDriver *driver, SoundTowns_EuphonyTrackQueue *last);
+	~SoundTowns_EuphonyTrackQueue() {}
+
+	void release();
+	void initDriver();
+	void loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop = 0);
+	void loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop = 0);
+	void setPlayBackStatus(bool playing);
+	SoundTowns_EuphonyTrackQueue * reset();
+	bool isPlaying() {return _playing; }
+	uint8 * trackData() {return _trackData; }
+
+	bool _loop;
+	SoundTowns_EuphonyTrackQueue * _next;
+
+private:
+	uint8 * _trackData;
+	uint8 * _used;
+	uint8 * _fchan;
+	uint8 * _wchan;
+	bool _playing;
+	SoundTowns_EuphonyDriver * _driver;
+	SoundTowns_EuphonyTrackQueue * _last;
+};
+
 class MidiParser_EuD : public MidiParser {
 public:
-	MidiParser_EuD();
-
-	bool loadMusic (byte *data, uint32 unused = 0);
+	MidiParser_EuD(SoundTowns_EuphonyTrackQueue * queue);
+	bool loadMusic (byte *data, uint32 size);
 	int32 calculateTempo(int16 val);
 
 protected:
 	void parseNextEvent (EventInfo &info);
 	void resetTracking();
+	void setup();
 
 	byte * _enable;
 	byte * _mode;
@@ -159,18 +189,19 @@
 	byte * _adjVelo;
 	int8 * _adjNote;
 
-	byte _tempo[3];
-
 	uint8 _firstBaseTickStep;
 	uint8 _nextBaseTickStep;
 	uint32 _initialTempo;
 	uint32 _baseTick;
+
+	byte _tempo[3];
+	SoundTowns_EuphonyTrackQueue * _queue;
 };
 
-class FMT_EuphonyDriver : public MidiDriver_Emulated {
+class SoundTowns_EuphonyDriver : public MidiDriver_Emulated {
 public:
-	FMT_EuphonyDriver(Audio::Mixer *mixer);
-	virtual ~FMT_EuphonyDriver();
+	SoundTowns_EuphonyDriver(Audio::Mixer *mixer);
+	virtual ~SoundTowns_EuphonyDriver();
 
 	int open();
 	void close();
@@ -179,10 +210,11 @@
 	uint32 property(int prop, uint32 param) { return 0; }
 
 	void setPitchBendRange(byte channel, uint range) { }
-	//void sysEx(const byte *msg, uint16 length);
 	void loadFmInstruments(const byte *instr);
 	void loadWaveInstruments(const byte *instr);
 
+	SoundTowns_EuphonyTrackQueue * queue() { return _queue; }
+
 	MidiChannel *allocateChannel() { return 0; }
 	MidiChannel *getPercussionChannel() { return 0; }
 
@@ -190,6 +222,9 @@
 	void assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber);
 	void removeChannel(uint8 midiChannelNumber);
 
+	void setVolume(int val = -1) { if (val >= 0) _volume = val; }
+	int getVolume(int val = -1) { return _volume; }
+
 	// AudioStream API
 	bool isStereo() const { return true; }
 	int getRate() const { return _mixer->getOutputRate(); }
@@ -198,7 +233,6 @@
 
 protected:
 	void nextTick(int16 *buf1, int buflen);
-	int volume(int val = -1) { if (val >= 0) _volume = val; return _volume; }
 	void rate(uint16 r);
 
 	void generateSamples(int16 *buf, int len);
@@ -206,6 +240,7 @@
 	MidiChannel_EuD_FM *_fChannel[6];
 	MidiChannel_EuD_WAVE *_wChannel[8];
 	MidiChannel_EuD * _channel[16];
+	SoundTowns_EuphonyTrackQueue * _queue;
 
 	int _volume;
 	bool _fading;
@@ -532,11 +567,11 @@
 	_velocity = velo;
 }
 
-FMT_EuphonyDriver::FMT_EuphonyDriver(Audio::Mixer *mixer)
-: MidiDriver_Emulated(mixer) {
-
+SoundTowns_EuphonyDriver::SoundTowns_EuphonyDriver(Audio::Mixer *mixer)
+	: MidiDriver_Emulated(mixer) {
 	_volume = 255;
-	_fadestate = 300;
+	_fadestate = EUPHONY_FADEOUT_TICKS;
+	_queue = 0;
 
 	MidiDriver_YM2612::createLookupTables();
 
@@ -551,9 +586,11 @@
 
 	rate(getRate());
 	fading(0);
+
+	_queue = new SoundTowns_EuphonyTrackQueue(this, 0);
 }
 
-FMT_EuphonyDriver::~FMT_EuphonyDriver() {
+SoundTowns_EuphonyDriver::~SoundTowns_EuphonyDriver() {
 	for (int i = 0; i < 6; i++)
 		delete _fChannel[i];
 	for (int i = 0; i < 8; i++)
@@ -577,33 +614,37 @@
 			_waveSounds[i] = 0;
 		}
 	}
+
+	if (_queue) {
+		_queue->release();
+		delete _queue;
+		_queue = 0;
+	}
 }
 
-int FMT_EuphonyDriver::open() {
+int SoundTowns_EuphonyDriver::open() {
 	if (_isOpen)
 		return MERR_ALREADY_OPEN;
-
 	MidiDriver_Emulated::open();
 
 	_mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_mixerSoundHandle,
 		this, -1, Audio::Mixer::kMaxChannelVolume, 0, false, true);
+
 	return 0;
 }
 
-void FMT_EuphonyDriver::close() {
+void SoundTowns_EuphonyDriver::close() {
 	if (!_isOpen)
 		return;
 	_isOpen = false;
 	_mixer->stopHandle(_mixerSoundHandle);
 }
 
-void FMT_EuphonyDriver::send(uint32 b) {
+void SoundTowns_EuphonyDriver::send(uint32 b) {
 	send(b & 0xF, b & 0xFFFFFFF0);
 }
 
-void FMT_EuphonyDriver::send(byte chan, uint32 b) {
-	//byte param3 = (byte) ((b >> 24) & 0xFF);
-
+void SoundTowns_EuphonyDriver::send(byte chan, uint32 b) {
 	byte param2 = (byte) ((b >> 16) & 0xFF);
 	byte param1 = (byte) ((b >>  8) & 0xFF);
 	byte cmd    = (byte) (b & 0xF0);
@@ -662,18 +703,18 @@
 			_channel[chan]->pitchBend((param1 | (param2 << 7)) - 0x2000);
 		break;
 	default:
-		warning("FMT_EuphonyDriver: Unknown send() command 0x%02X", cmd);
+		warning("SoundTowns_EuphonyDriver: Unknown send() command 0x%02X", cmd);
 	}
 }
 
-void FMT_EuphonyDriver::loadFmInstruments(const byte *instr) {
+void SoundTowns_EuphonyDriver::loadFmInstruments(const byte *instr) {
 	if (_fmInstruments)
 		delete [] _fmInstruments;
 	_fmInstruments = new uint8[0x1800];
 	memcpy(_fmInstruments, instr, 0x1800);
 }
 
-void FMT_EuphonyDriver::loadWaveInstruments(const byte *instr) {
+void SoundTowns_EuphonyDriver::loadWaveInstruments(const byte *instr) {
 	if (_waveInstruments)
 		delete [] _waveInstruments;
 	_waveInstruments = new uint8[0x1000];
@@ -698,24 +739,24 @@
 }
 
 
-void FMT_EuphonyDriver::assignFmChannel(uint8 midiChannelNumber, uint8 fmChannelNumber) {
+void SoundTowns_EuphonyDriver::assignFmChannel(uint8 midiChannelNumber, uint8 fmChannelNumber) {
 	_channel[midiChannelNumber] = _fChannel[fmChannelNumber];
 }
 
-void FMT_EuphonyDriver::assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber) {
+void SoundTowns_EuphonyDriver::assignWaveChannel(uint8 midiChannelNumber, uint8 waveChannelNumber) {
 	_channel[midiChannelNumber] = _wChannel[waveChannelNumber];
 }
 
-void FMT_EuphonyDriver::removeChannel(uint8 midiChannelNumber) {
+void SoundTowns_EuphonyDriver::removeChannel(uint8 midiChannelNumber) {
 	_channel[midiChannelNumber] = 0;
 }
 
-void FMT_EuphonyDriver::generateSamples(int16 *data, int len) {
+void SoundTowns_EuphonyDriver::generateSamples(int16 *data, int len) {
 	memset(data, 0, 2 * sizeof(int16) * len);
 	nextTick(data, len);
 }
 
-void FMT_EuphonyDriver::nextTick(int16 *buf1, int buflen) {
+void SoundTowns_EuphonyDriver::nextTick(int16 *buf1, int buflen) {
 	int32 *buf0 = (int32 *)buf1;
 
 	for (int i = 0; i < ARRAYSIZE(_channel); i++) {
@@ -724,39 +765,63 @@
 	}
 
 	for (int i = 0; i < buflen; ++i) {
-		int s = int( float(buf0[i] * volume()) * float((float)_fadestate / 300) );
+		int s = int( float(buf0[i] * _volume) * float((float)_fadestate / EUPHONY_FADEOUT_TICKS) );
 		buf1[i*2] = buf1[i*2+1] = (s >> 9) & 0xffff;
 	}
 
 	if (_fading) {
-		if (_fadestate)
+		if (_fadestate) {
 			_fadestate--;
-		else
+		} else {
 			_fading = false;
+			_queue->setPlayBackStatus(false);
+		}
 	}
 }
 
-void FMT_EuphonyDriver::rate(uint16 r) {
+void SoundTowns_EuphonyDriver::rate(uint16 r) {
 	for (uint8 i = 0; i < 16; i++) {
 		if (_channel[i])
 			_channel[i]->rate(r);
 	}
 }
 
-void FMT_EuphonyDriver::fading(bool status) {
+void SoundTowns_EuphonyDriver::fading(bool status) {
 	_fading = status;
 	if (!_fading)
-		_fadestate = 300;
+		_fadestate = EUPHONY_FADEOUT_TICKS;
 }
 
-MidiParser_EuD::MidiParser_EuD() : MidiParser(),
+MidiParser_EuD::MidiParser_EuD(SoundTowns_EuphonyTrackQueue * queue) : MidiParser(),
 	_firstBaseTickStep(0x33), _nextBaseTickStep(0x33) {
 		_initialTempo = calculateTempo(0x5a);
+		_queue = queue;
 }
 
 void MidiParser_EuD::parseNextEvent(EventInfo &info) {
 	byte *pos = _position._play_pos;
 
+	if (_queue->_next) {
+		if (info.ext.type == 0x2F) {
+			unloadMusic();
+			memset(&info, 0, sizeof(EventInfo));
+			pos = _position._play_pos = _tracks[0] = _queue->trackData() + 0x806;
+		} else if (_active_track == 255) {
+			_queue = _queue->_next;
+			setup();
+			setTrack(0);
+			_queue->setPlayBackStatus(true);
+			return;
+		} else if (!_queue->isPlaying()) {
+			unloadMusic();
+			_queue = _queue->_next;
+			setup();
+			setTrack(0);
+			_queue->setPlayBackStatus(true);
+			return;
+		}
+	}
+
 	while (true) {
 		byte cmd = *pos;
 		byte evt = (cmd & 0xF0);
@@ -830,10 +895,13 @@
 			break;
 		} else if (cmd == 0xFD || cmd == 0xFE) {
 			// End of track.
-			if (_autoLoop)
+			if (_autoLoop) {
+				unloadMusic();
+				_queue->setPlayBackStatus(true);
 				pos = info.start = _tracks[0];
-			else
+			} else {
 				info.start = pos;
+			}
 
 			uint32 last = _position._last_event_tick;
 			uint16 tick = (pos[2] | ((uint16) pos[3] << 7)) + _baseTick;
@@ -852,25 +920,20 @@
 	_position._play_pos = pos;
 }
 
-bool MidiParser_EuD::loadMusic(byte *data, uint32) {
-	unloadMusic();
+bool MidiParser_EuD::loadMusic(byte *data, uint32 size) {
+	bool loop = _autoLoop;
 
-	_enable = data + 0x354;
-	_mode = data + 0x374;
-	_channel = data + 0x394;
-	_adjVelo = data + 0x3B4;
-	_adjNote = (int8*) data + 0x3D4;
-
-	_firstBaseTickStep = data[0x804];
-	_initialTempo = calculateTempo((data[0x805] > 0xfc) ? 0x5a : data[0x805]);
-
-	_num_tracks = 1;
-	_ppqn = 120;
-	_tracks[0] = data + 0x806;
-
-	resetTracking();
-	setTrack (0);
-
+	if (_queue->isPlaying() && !_queue->_loop) {
+		_queue->loadDataToEndOfQueue(data, size, loop);
+	} else {
+		unloadMusic();
+		_queue = _queue->reset();
+		_queue->release();
+		_queue->loadDataToCurrentPosition(data, size, loop);
+		setup();
+		setTrack(0);
+		_queue->setPlayBackStatus(true);
+	}
 	return true;
 }
 
@@ -892,15 +955,139 @@
 
 void MidiParser_EuD::resetTracking() {
 	MidiParser::resetTracking();
+
 	_nextBaseTickStep = _firstBaseTickStep;
 	_baseTick = 0;
 	setTempo(_initialTempo);
+	_queue->setPlayBackStatus(false);
 }
 
+void MidiParser_EuD::setup() {
+	uint8 *data = _queue->trackData();
+	if (!data)
+		return;
+	_queue->initDriver();
+
+	_enable = data + 0x354;
+	_mode = data + 0x374;
+	_channel = data + 0x394;
+	_adjVelo = data + 0x3B4;
+	_adjNote = (int8*) data + 0x3D4;
+
+	_nextBaseTickStep = _firstBaseTickStep = data[0x804];
+	_initialTempo = calculateTempo((data[0x805] > 0xfc) ? 0x5a : data[0x805]);
+
+	property(MidiParser::mpAutoLoop, _queue->_loop);
+
+	_num_tracks = 1;
+	_ppqn = 120;
+	_tracks[0] = data + 0x806;
+}
+
+SoundTowns_EuphonyTrackQueue::SoundTowns_EuphonyTrackQueue(SoundTowns_EuphonyDriver * driver, SoundTowns_EuphonyTrackQueue * last) {
+	_trackData = 0;
+	_next = 0;
+	_driver = driver;
+	_last = last;
+	_used = _fchan = _wchan = 0;
+	_playing = false;
+}
+
+void SoundTowns_EuphonyTrackQueue::setPlayBackStatus(bool playing) {
+	SoundTowns_EuphonyTrackQueue * i = this;
+	do {
+		i->_playing = playing;
+		i = i->_next;
+	} while (i);
+}
+
+SoundTowns_EuphonyTrackQueue * SoundTowns_EuphonyTrackQueue::reset() {
+	SoundTowns_EuphonyTrackQueue * i = this;
+	while (i->_last)
+		i = i->_last;
+	return i;
+}
+
+void SoundTowns_EuphonyTrackQueue::loadDataToCurrentPosition(uint8 * trackdata, uint32 size, bool loop) {
+	if (_trackData)
+		delete [] _trackData;
+	_trackData = new uint8[0xC58A];
+	memset(_trackData, 0, 0xC58A);
+	Screen::decodeFrame4(trackdata, _trackData, size);
+
+	_used = _trackData + 0x374;
+	_fchan = _trackData + 0x6d4;
+	_wchan = _trackData + 0x6dA;
+	_loop = loop;
+	_playing = false;
+}
+
+void SoundTowns_EuphonyTrackQueue::loadDataToEndOfQueue(uint8 * trackdata, uint32 size, bool loop) {
+	if (!_trackData) {
+		loadDataToCurrentPosition(trackdata, size, loop);
+		return;
+	}
+
+	SoundTowns_EuphonyTrackQueue * i = this;
+	while (i->_next)
+		i = i->_next;
+
+	i = i->_next = new SoundTowns_EuphonyTrackQueue(_driver, i);
+	i->_trackData = new uint8[0xC58A];
+	memset(i->_trackData, 0, 0xC58A);
+	Screen::decodeFrame4(trackdata, i->_trackData, size);
+
+	i->_used = i->_trackData + 0x374;
+	i->_fchan = i->_trackData + 0x6d4;
+	i->_wchan = i->_trackData + 0x6dA;
+	i->_loop = loop;
+	i->_playing = _playing;
+}
+
+void SoundTowns_EuphonyTrackQueue::release() {
+	SoundTowns_EuphonyTrackQueue * i = _next;
+	_next = 0;
+	_playing = false;
+	_used = _fchan = _wchan = 0;
+
+	if (_trackData) {
+		delete [] _trackData;
+		_trackData = 0;
+	}
+
+	while (i) {
+		if (i->_trackData) {
+			delete [] i->_trackData;
+			i->_trackData = 0;
+		}
+		i = i->_next;
+		if (i)
+			delete i->_last;
+	}
+}
+
+void SoundTowns_EuphonyTrackQueue::initDriver() {
+	for (uint8 i = 0; i < 6; i++) {
+		if (_used[_fchan[i]])
+			_driver->assignFmChannel(_fchan[i], i);
+	}
+
+	for (uint8 i = 0; i < 8; i++) {
+		if (_used[_wchan[i]])
+			_driver->assignWaveChannel(_wchan[i], i);
+	}
+
+	for (uint8 i = 0; i < 16; i++) {
+		if (!_used[i])
+			_driver->removeChannel(i);
+	}
+	_driver->send(0x79B0);
+}
+
 SoundTowns::SoundTowns(KyraEngine *vm, Audio::Mixer *mixer) : Sound(vm, mixer), _lastTrack(-1),
-	 _currentSFX(0), _sfxFileData(0), _sfxFileIndex((uint)-1), _sfxWDTable(0), _parser(0), _musicTrackData(0) {
+	 _currentSFX(0), _sfxFileData(0), _sfxFileIndex((uint)-1), _sfxWDTable(0), _parser(0), _sfxVolume(255) {
 
-	_driver = new FMT_EuphonyDriver(_mixer);
+	_driver = new SoundTowns_EuphonyDriver(_mixer);
 	int ret = open();
 	if (ret != MERR_ALREADY_OPEN && ret != 0) {
 		error("couldn't open midi driver");
@@ -916,9 +1103,6 @@
 	_driver->setTimerCallback(0, 0);
 	close();
 
-	if (_musicTrackData)
-		delete [] _musicTrackData;
-
 	_driver = 0;
 }
 
@@ -950,65 +1134,26 @@
 	track -= 2;
 
 	static const CDTrackTable tTable[] = {
-		{ 0x04000, 1,  0 },
-		{ 0x05480, 1,  6 },
-		{ 0x05E70, 0,  1 },
-		{ 0x06D90, 1,  3 },
-		{ 0x072C0, 0, -1 },
-		{ 0x075F0, 1, -1 },
-		{ 0x07880, 1, -1 },
-		{ 0x089C0, 0, -1 },
-		{ 0x09080, 0, -1 },
-		{ 0x091D0, 1,  4 },
-		{ 0x0A880, 1,  5 },
-		{ 0x0AF50, 0, -1 },
-		{ 0x0B1A0, 1, -1 },
-		{ 0x0B870, 0, -1 },
-		{ 0x0BCF0, 1, -1 },
-		{ 0x0C5D0, 1,  7 },
-		{ 0x0D3E0, 1,  8 },
-		{ 0x0e7b0, 1,  2 },
-		{ 0x0edc0, 0, -1 },
-		{ 0x0eef0, 1,  9 },
-		{ 0x10540, 1, 10 },
-		{ 0x10d80, 0, -1 },
-		{ 0x10E30, 0, -1 },
-		{ 0x10FC0, 0, -1 },
-		{ 0x11310, 1, -1 },
-		{ 0x11A20, 1, -1 },
-		{ 0x12380, 0, -1 },
-		{ 0x12540, 1, -1 },
-		{ 0x12730, 1, -1 },
-		{ 0x12A90, 1, 11 },
-		{ 0x134D0, 0, -1 },
-		{ 0x00000, 0, -1 },
-		{ 0x13770, 0, -1 },
-		{ 0x00000, 0, -1 },
-		{ 0x00000, 0, -1 },
-		{ 0x00000, 0, -1 },
-		{ 0x00000, 0, -1 },
-		{ 0x14710, 1, 12 },
-		{ 0x15DF0, 1, 13 },
-		{ 0x16030, 1, 14 },
-		{ 0x17030, 0, -1 },
-		{ 0x17650, 0, -1 },
-		{ 0x134D0, 0, -1 },
-		{ 0x178E0, 1, -1 },
-		{ 0x18200, 0, -1 },
-		{ 0x18320, 0, -1 },
-		{ 0x184A0, 0, -1 },
-		{ 0x18BB0, 0, -1 },
-		{ 0x19040, 0, 19 },
-		{ 0x19B50, 0, 20 },
-		{ 0x17650, 0, -1 },
-		{ 0x1A730, 1, 21 },
-		{ 0x00000, 0, -1 },
-		{ 0x12380, 0, -1 },
-		{ 0x1B810, 0, -1 },
-		{ 0x1BA50, 0, 15 },
-		{ 0x1C190, 0, 16 },
-		{ 0x1CA50, 0, 17 },
-		{ 0x1D100, 0, 18 },
+		{ 0x04000, 1,  0 },	{ 0x05480, 1,  6 },	{ 0x05E70, 0,  1 },
+		{ 0x06D90, 1,  3 },	{ 0x072C0, 0, -1 },	{ 0x075F0, 1, -1 },
+		{ 0x07880, 1, -1 },	{ 0x089C0, 0, -1 },	{ 0x09080, 0, -1 },
+		{ 0x091D0, 1,  4 },	{ 0x0A880, 1,  5 },	{ 0x0AF50, 0, -1 },
+		{ 0x0B1A0, 1, -1 },	{ 0x0B870, 0, -1 },	{ 0x0BCF0, 1, -1 },
+		{ 0x0C5D0, 1,  7 },	{ 0x0D3E0, 1,  8 },	{ 0x0e7b0, 1,  2 },
+		{ 0x0edc0, 0, -1 },	{ 0x0eef0, 1,  9 },	{ 0x10540, 1, 10 },
+		{ 0x10d80, 0, -1 },	{ 0x10E30, 0, -1 },	{ 0x10FC0, 0, -1 },
+		{ 0x11310, 1, -1 },	{ 0x11A20, 1, -1 },	{ 0x12380, 0, -1 },
+		{ 0x12540, 1, -1 },	{ 0x12730, 1, -1 },	{ 0x12A90, 1, 11 },
+		{ 0x134D0, 0, -1 },	{ 0x00000, 0, -1 },	{ 0x13770, 0, -1 },
+		{ 0x00000, 0, -1 },	{ 0x00000, 0, -1 },	{ 0x00000, 0, -1 },
+		{ 0x00000, 0, -1 },	{ 0x14710, 1, 12 },	{ 0x15DF0, 1, 13 },
+		{ 0x16030, 1, 14 },	{ 0x17030, 0, -1 },	{ 0x17650, 0, -1 },
+		{ 0x134D0, 0, -1 },	{ 0x178E0, 1, -1 },	{ 0x18200, 0, -1 },
+		{ 0x18320, 0, -1 },	{ 0x184A0, 0, -1 },	{ 0x18BB0, 0, -1 },
+		{ 0x19040, 0, 19 },	{ 0x19B50, 0, 20 },	{ 0x17650, 0, -1 },
+		{ 0x1A730, 1, 21 },	{ 0x00000, 0, -1 },	{ 0x12380, 0, -1 },
+		{ 0x1B810, 0, -1 },	{ 0x1BA50, 0, 15 },	{ 0x1C190, 0, 16 },
+		{ 0x1CA50, 0, 17 },	{ 0x1D100, 0, 18 }
 	};
 
 	int trackNum = tTable[track].track;
@@ -1017,7 +1162,7 @@
 	if (track == _lastTrack && _musicEnabled)
 		return;
 
-	haltTrack();
+	beginFadeOut();
 
 	if (_musicEnabled == 2 && trackNum != -1) {
 		AudioCD.play(trackNum+1, loop ? -1 : 1, 0, 0);
@@ -1035,18 +1180,23 @@
 	AudioCD.updateCD();
 	if (_parser) {
 		Common::StackLock lock(_mutex);
-
 		_parser->setTrack(0);
 		_parser->jumpToTick(0);
-
 		_parser->unloadMusic();
 		delete _parser;
 		_parser = 0;
-
 		setVolume(255);
 	}
+	_driver->queue()->release();
 }
 
+void SoundTowns::setMusicVolume(int volume) {
+	volume = CLIP<int>(volume, 0, Audio::Mixer::kMaxMixerVolume);
+
+	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, volume);
+	_driver->setVolume(255);
+}
+
 void SoundTowns::loadSoundFile(uint file) {
 	if (_sfxFileIndex == file)
 		return;
@@ -1143,7 +1293,7 @@
 
 	_currentSFX = Audio::makeLinearInputStream(sfxPlaybackBuffer, playbackBufferSize,
 		outputRate, Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_LITTLE_ENDIAN | Audio::Mixer::FLAG_AUTOFREE, 0, 0);
-	_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, _currentSFX);
+	_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, _currentSFX, -1, _sfxVolume);
 }
 
 void SoundTowns::beginFadeOut() {
@@ -1181,65 +1331,33 @@
 }
 
 bool SoundTowns::loadInstruments() {
-	if (!_musicTrackData)
-		_musicTrackData = new uint8[0xC58A];
-
-	memset(_musicTrackData, 0, 0xC58A);
 	uint8 * twm = _vm->resource()->fileData("twmusic.pak", 0);
 	if (!twm)
 		return false;
-	Screen::decodeFrame4(twm, _musicTrackData, 0x8BF0);
-	_driver->loadFmInstruments(_musicTrackData + 8);
+	_driver->queue()->loadDataToCurrentPosition(twm, 0x8BF0);
+	_driver->loadFmInstruments(_driver->queue()->trackData() + 8);
 
-	memset (_musicTrackData, 0, 0xC58A);
-	Screen::decodeFrame4(twm + 0x0CA0, _musicTrackData, 0xC58A);
+	_driver->queue()->loadDataToCurrentPosition(twm + 0x0CA0, 0xC58A);
+	_driver->loadWaveInstruments(_driver->queue()->trackData() + 8);
 	delete [] twm;
-	_driver->loadWaveInstruments(_musicTrackData + 8);
+	_driver->queue()->release();
 
 	return true;
 }
 
 void SoundTowns::playEuphonyTrack(uint32 offset, int loop) {
-	if (!_musicTrackData)
-		_musicTrackData = new uint8[0xC58A];
-
-	memset(_musicTrackData, 0, 0xC58A);
 	uint8 * twm = _vm->resource()->fileData("twmusic.pak", 0);
-	Screen::decodeFrame4(twm + 0x4b70 + offset, _musicTrackData, 0xC58A);
-	delete [] twm;
 
-	Common::StackLock lock(_mutex);
-
-	uint8 * used = _musicTrackData + 0x374;
-	uint8 * fchan = _musicTrackData + 0x6d4;
-	uint8 * wchan = _musicTrackData + 0x6dA;
-
-	for (uint8 i = 0; i < 6; i++) {
-		if (used[fchan[i]])
-			_driver->assignFmChannel(fchan[i], i);
+	if (!_parser) {
+		_parser = new MidiParser_EuD(_driver->queue());
+		_parser->setMidiDriver(this);
+		_parser->setTimerRate(getBaseTempo());
 	}
 
-	for (uint8 i = 0; i < 8; i++) {
-		if (used[wchan[i]])
-			_driver->assignWaveChannel(wchan[i], i);
-	}
-
-	for (uint8 i = 0; i < 16; i++) {
-		if (!used[i])
-			_driver->removeChannel(i);
-	}
-	_driver->send(0x79B0);
-
-	if (_parser)
-		delete _parser;
-
-	_parser = new MidiParser_EuD;
 	_parser->property(MidiParser::mpAutoLoop, loop);
-	_parser->loadMusic(_musicTrackData, 0);
-	_parser->jumpToTick(0);
+	_parser->loadMusic(twm + 0x4b70 + offset, 0xC58A);
 
-	_parser->setMidiDriver(this);
-	_parser->setTimerRate(getBaseTempo());
+	delete [] twm;
 }
 
 void SoundTowns::onTimer(void * data) {
@@ -1302,5 +1420,165 @@
 	0x10, 0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01
 };
 
+//	KYRA 2
+
+SoundTowns_v2::SoundTowns_v2(KyraEngine *vm, Audio::Mixer *mixer) :
+	 Sound(vm, mixer), _lastTrack(-1), _currentSFX(0), /*_driver(0),*/
+	 _twnTrackData(0), _sfxVolume(255) {
+}
+
+SoundTowns_v2::~SoundTowns_v2() {
+	/*if (_driver)
+		delete _driver;*/
+	if (_twnTrackData)
+		delete [] _twnTrackData;
+}
+
+bool SoundTowns_v2::init() {
+	//_driver = new SoundTowns_v2_TwnDriver(_mixer);
+	_vm->checkCD();
+	Common::File f;
+	if (_musicEnabled && (f.exists("track1.mp3") ||
+		f.exists("track1.ogg") || f.exists("track1.flac")  || f.exists("track1.fla")))
+			_musicEnabled = 2;
+	return true;//_driver->init();
+}
+
+void SoundTowns_v2::process() {
+	AudioCD.updateCD();
+}
+
+void SoundTowns_v2::setMusicVolume(int volume) {
+	/* TODO */
+}
+
+void SoundTowns_v2::playTrack(uint8 track) {
+	if (track == _lastTrack && _musicEnabled)
+		return;
+
+	int trackNum = -1;
+	for (int i = 0; i < _themes[_currentTheme].cdaTableSize; i++) {
+		if (track == _themes[_currentTheme].cdaTable[i * 2]) {
+			trackNum = _themes[_currentTheme].cdaTable[i * 2 + 1] - 1;
+			break;
+		}
+	}
+
+	haltTrack();
+
+	// TODO: figure out when to loop and when not for CD Audio
+	bool loop = false;
+
+	if (_musicEnabled == 2 && trackNum != -1) {
+		AudioCD.play(trackNum+1, loop ? -1 : 1, 0, 0);
+		AudioCD.updateCD();
+	} else if (_musicEnabled) {
+		char musicfile[13];
+		sprintf(musicfile, "%s%d.twn", _themes[_currentTheme].twnFilename, track);
+		if (_twnTrackData)
+			delete [] _twnTrackData;
+		_twnTrackData = _vm->resource()->fileData(musicfile, 0);
+		//_driver->loadData(_twnTrackData);
+	}
+
+	_lastTrack = track;
+}
+
+void SoundTowns_v2::haltTrack() {
+	_lastTrack = -1;
+	AudioCD.stop();
+	AudioCD.updateCD();
+	//_driver->reset();
+}
+
+void SoundTowns_v2::voicePlay(const char *file) {
+	static const uint16 rates[] =	{ 0x10E1, 0x0CA9, 0x0870, 0x0654, 0x0438, 0x032A, 0x021C, 0x0194 };
+
+	uint8 * data = _vm->resource()->fileData(file, 0);
+	uint8 * src = data;
+
+	uint16 sfxRate = rates[READ_LE_UINT16(src)];
+	src += 2;
+	bool compressed = (READ_LE_UINT16(src) & 1) ? true : false;
+	src += 2;
+	uint32 outsize = READ_LE_UINT32(src);
+	uint8 *sfx = (uint8*) malloc(outsize);
+	uint8 *dst = sfx;
+	src += 4;
+
+	if (compressed) {
+		for (uint32 i = outsize; i;) {
+			uint8 cnt = *src++;
+			if (cnt & 0x80) {
+				cnt &= 0x7F;
+				memset(dst, *src++, cnt);
+			} else {
+				memcpy(dst, src, cnt);
+				src += cnt;
+			}
+			dst += cnt;
+			i -= cnt;
+		}
+	} else {
+		memcpy(dst, src, outsize);
+	}
+
+	for (uint32 i = 0; i < outsize; i++) {
+		uint8 cmd = sfx[i];
+		if (cmd & 0x80) {
+			cmd = ~cmd;
+		} else {
+			cmd |= 0x80;
+			if (cmd == 0xff)
+				cmd--;
+		}
+		if (cmd < 0x80)
+			cmd = 0x80 - cmd;
+		sfx[i] = cmd;
+	}
+
+	uint32 outputRate = uint32(11025 * SoundTowns::semitoneAndSampleRate_to_sampleStep(0x3c, 0x3c, sfxRate, 11025, 0x2000));
+
+	_currentSFX = Audio::makeLinearInputStream(sfx, outsize, outputRate,
+		Audio::Mixer::FLAG_UNSIGNED | Audio::Mixer::FLAG_LITTLE_ENDIAN | Audio::Mixer::FLAG_AUTOFREE, 0, 0);
+	_mixer->playInputStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, _currentSFX, -1, _sfxVolume);
+
+	delete [] data;
+}
+
+void SoundTowns_v2::beginFadeOut() {
+	//_driver->fadeOut();
+	haltTrack();
+}
+
+const uint8 SoundTowns_v2::_cdaTrackTableK2Intro[] =	{
+	0x03, 0x01, 0x04, 0x02, 0x05, 0x03, 0x06, 0x04, 0x07, 0x05, 0x08, 0x06
+};
+
+const uint8 SoundTowns_v2::_cdaTrackTableK2Ingame[] =	{
+	0x02, 0x07, 0x03, 0x08, 0x04, 0x09, 0x07, 0x0A, 0x0C, 0x0B, 0x0D, 0x0C, 0x0E, 0x0D, 0x0F, 0x0E,
+	0x10, 0x0F, 0x12, 0x10, 0x13, 0x11, 0x15, 0x12,	0x17, 0x13, 0x18, 0x14, 0x19, 0x15, 0x1A, 0x16,
+	0x1B, 0x17, 0x1C, 0x18,	0x1D, 0x19, 0x1E, 0x1A, 0x1F, 0x1B, 0x21, 0x1C, 0x22, 0x1D, 0x23, 0x1E,
+	0x24, 0x1F, 0x25, 0x20, 0x26, 0x21, 0x27, 0x22, 0x28, 0x23, 0x29, 0x24,	0x2A, 0x25, 0x2B, 0x26,
+	0x2C, 0x27, 0x2D, 0x28, 0x2E, 0x29, 0x2F, 0x2A,	0x30, 0x2B, 0x31, 0x2C, 0x32, 0x2D, 0x33, 0x2E,
+	0x34, 0x2F, 0x35, 0x30,	0x36, 0x31, 0x37, 0x32, 0x38, 0x33, 0x39, 0x34, 0x3A, 0x35, 0x3B, 0x36,
+	0x3C, 0x37, 0x3D, 0x38, 0x3E, 0x39, 0x3F, 0x3A, 0x40, 0x3B, 0x41, 0x3C,	0x42, 0x3D, 0x43, 0x3E,
+	0x44, 0x3F, 0x45, 0x40, 0x46, 0x41, 0x47, 0x42,	0x48, 0x43, 0x49, 0x44, 0x4A, 0x45, 0x4B, 0x46,
+	0x4C, 0x47, 0x4D, 0x48,	0x4E, 0x49, 0x4F, 0x4A, 0x50, 0x4B, 0x51, 0x4C, 0x52, 0x4D, 0x53, 0x4E,
+	0x54, 0x4F, 0x55, 0x50, 0x56, 0x51, 0x57, 0x52
+};
+
+const uint8 SoundTowns_v2::_cdaTrackTableK2Finale[] =	{
+	0x03, 0x53, 0x04, 0x54
+};
+
+const SoundTowns_v2::Kyra2AudioThemes SoundTowns_v2::_themes[] = {
+	{ _cdaTrackTableK2Intro,	ARRAYSIZE(_cdaTrackTableK2Intro) >> 1,	"intro"		},
+	{ _cdaTrackTableK2Ingame,	ARRAYSIZE(_cdaTrackTableK2Ingame) >> 1,	"k2"		},
+	{ _cdaTrackTableK2Finale,	ARRAYSIZE(_cdaTrackTableK2Finale) >> 1,	"finale"	}
+};
+
 } // end of namespace Kyra
 
+#undef EUPHONY_FADEOUT_TICKS
+


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