[Scummvm-cvs-logs] SF.net SVN: scummvm:[52198] scummvm/trunk

athrxx at users.sourceforge.net athrxx at users.sourceforge.net
Wed Aug 18 23:38:43 CEST 2010


Revision: 52198
          http://scummvm.svn.sourceforge.net/scummvm/?rev=52198&view=rev
Author:   athrxx
Date:     2010-08-18 21:38:43 +0000 (Wed, 18 Aug 2010)

Log Message:
-----------
SCUMM/FM-TOWNS: start rewriting audio code

- Start rewriting audio code for FM-TOWNS versions of Loom, Indy3 and Monkey Island 1 using the recently added code in towns_audio.cpp (Zak should work the same way, but I can't test, since I don't own that one).
- All sound types (pcm, euphony and cd audio) now support volume and balance control (e.g. try walking into/out of the kitchen and opening/closing the door in the Scumm Bar in Monkey Island 1 or walking into/out of the circus tent).
- Pcm sounds now support proper loop start/end and note offsets (e.g. try out the hammer sound in the forge in LOOM for example).
- some other minor improvements
- The FM-Towns versions of Indy 4 and Monkey Island 2 are not affected. I don't have Monkey Island 2, but I presume that it will work like Indy 4. Adding support for these will be a separate task, since they work quite differently.

Modified Paths:
--------------
    scummvm/trunk/engines/scumm/detection_tables.h
    scummvm/trunk/engines/scumm/imuse/imuse_player.cpp
    scummvm/trunk/engines/scumm/module.mk
    scummvm/trunk/engines/scumm/saveload.cpp
    scummvm/trunk/engines/scumm/saveload.h
    scummvm/trunk/engines/scumm/script_v5.cpp
    scummvm/trunk/engines/scumm/scumm.cpp
    scummvm/trunk/engines/scumm/scumm.h
    scummvm/trunk/engines/scumm/sound.cpp
    scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_audio.cpp
    scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_audio.h
    scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
    scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
    scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h

Added Paths:
-----------
    scummvm/trunk/engines/scumm/player_towns.cpp
    scummvm/trunk/engines/scumm/player_towns.h

Removed Paths:
-------------
    scummvm/trunk/engines/scumm/midiparser_eup.cpp

Modified: scummvm/trunk/engines/scumm/detection_tables.h
===================================================================
--- scummvm/trunk/engines/scumm/detection_tables.h	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/engines/scumm/detection_tables.h	2010-08-18 21:38:43 UTC (rev 52198)
@@ -186,6 +186,7 @@
 using Common::GUIO_NOLAUNCHLOAD;
 using Common::GUIO_NOMIDI;
 using Common::GUIO_NOSPEECH;
+using Common::GUIO_MIDITOWNS;
 
 // The following table contains information about variants of our various
 // games. We index into it with help of md5table (from scumm-md5.h), to find
@@ -217,19 +218,19 @@
 
 	{"zak", "V1",       "v1", GID_ZAK, 1, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI},
 	{"zak", "V2",       "v2", GID_ZAK, 2, 0, MDT_PCSPK | MDT_PCJR, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI},
-	{"zak", "FM-TOWNS",    0, GID_ZAK, 3, 0, MDT_TOWNS, GF_OLD256 | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI},
+	{"zak", "FM-TOWNS",    0, GID_ZAK, 3, 0, MDT_TOWNS, GF_OLD256 | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI | GUIO_MIDITOWNS},
 
 	{"indy3", "EGA",      "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB, 0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI},
 	{"indy3", "No AdLib", "ega", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR,             0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI},
 	{"indy3", "VGA",      "vga", GID_INDY3, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_ADLIB, GF_OLD256 | GF_FEW_LOCALS,                  Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI},
-	{"indy3", "FM-TOWNS",     0, GID_INDY3, 3, 0, MDT_TOWNS,             GF_OLD256 | GF_FEW_LOCALS | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI},
+	{"indy3", "FM-TOWNS",     0, GID_INDY3, 3, 0, MDT_TOWNS,             GF_OLD256 | GF_FEW_LOCALS | GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI | GUIO_MIDITOWNS},
 
 	{"loom", "EGA",      "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS | MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH},
 	{"loom", "No AdLib", "ega", GID_LOOM, 3, 0, MDT_PCSPK | MDT_PCJR | MDT_CMS,                        0, UNK, GUIO_NOSPEECH | GUIO_NOMIDI},
 #ifdef USE_RGB_COLOR
 	{"loom", "PC-Engine",    0, GID_LOOM, 3, 0, MDT_NONE,                         GF_AUDIOTRACKS | GF_OLD256 | GF_16BIT_COLOR, Common::kPlatformPCEngine, GUIO_NOSPEECH | GUIO_NOMIDI},
 #endif
-	{"loom", "FM-TOWNS",     0, GID_LOOM, 3, 0, MDT_TOWNS,                        GF_AUDIOTRACKS | GF_OLD256, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI},
+	{"loom", "FM-TOWNS",     0, GID_LOOM, 3, 0, MDT_TOWNS,                        GF_AUDIOTRACKS | GF_OLD256, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI | GUIO_MIDITOWNS},
 	{"loom", "VGA",      "vga", GID_LOOM, 4, 0, MDT_NONE,                         GF_AUDIOTRACKS,             Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI},
 
 	{"pass", 0, 0, GID_PASS, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_ADLIB, GF_16COLOR, Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI},
@@ -239,7 +240,7 @@
 	{"monkey", "No AdLib", "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR,                        GF_16COLOR,     Common::kPlatformAtariST, GUIO_NOSPEECH | GUIO_NOMIDI},
 	{"monkey", "Demo",     "ega", GID_MONKEY_EGA, 4, 0, MDT_PCSPK | MDT_PCJR | MDT_ADLIB,            GF_16COLOR,     Common::kPlatformPC, GUIO_NOSPEECH | GUIO_NOMIDI},
 	{"monkey", "CD",           0, GID_MONKEY,     5, 0, MDT_ADLIB,                        GF_AUDIOTRACKS, UNK, GUIO_NOSPEECH | GUIO_NOMIDI},
-	{"monkey", "FM-TOWNS",     0, GID_MONKEY,     5, 0, MDT_ADLIB,                        GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI},
+	{"monkey", "FM-TOWNS",     0, GID_MONKEY,     5, 0, MDT_TOWNS,                        GF_AUDIOTRACKS, Common::kPlatformFMTowns, GUIO_NOSPEECH | GUIO_NOMIDI | GUIO_MIDITOWNS},
 	{"monkey", "SEGA",         0, GID_MONKEY,     5, 0, MDT_NONE,                         GF_AUDIOTRACKS, Common::kPlatformSegaCD, GUIO_NOSPEECH | GUIO_NOMIDI},
 
 	{"monkey2",  0, 0, GID_MONKEY2,  5, 0, MDT_ADLIB | MDT_MIDI | MDT_PREFER_MT32, 0, UNK, GUIO_NOSPEECH},

Modified: scummvm/trunk/engines/scumm/imuse/imuse_player.cpp
===================================================================
--- scummvm/trunk/engines/scumm/imuse/imuse_player.cpp	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/engines/scumm/imuse/imuse_player.cpp	2010-08-18 21:38:43 UTC (rev 52198)
@@ -47,7 +47,6 @@
 #define PERCUSSION_CHANNEL 9
 
 extern MidiParser *MidiParser_createRO();
-extern MidiParser *MidiParser_createEUP();
 
 uint16 Player::_active_notes[128];
 
@@ -195,7 +194,11 @@
 		_parser = MidiParser_createRO();
 	} else if (!memcmp(ptr, "SO", 2)) {
 		// Euphony (FM-TOWNS) resource
-		_parser = MidiParser_createEUP();
+		
+		//////////// REMOVE
+		//_parser = MidiParser_createEUP();
+		///////////
+
 	} else if (!memcmp(ptr, "FORM", 4)) {
 		// Humongous Games XMIDI resource
 		_parser = MidiParser::createParser_XMIDI();

Deleted: scummvm/trunk/engines/scumm/midiparser_eup.cpp
===================================================================
--- scummvm/trunk/engines/scumm/midiparser_eup.cpp	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/engines/scumm/midiparser_eup.cpp	2010-08-18 21:38:43 UTC (rev 52198)
@@ -1,222 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
-
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
-
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * $URL$
- * $Id$
- *
- */
-
-
-#include "sound/midiparser.h"
-#include "sound/mididrv.h"
-#include "common/util.h"
-
-namespace Scumm {
-
-/**
- * The FM-TOWNS Euphony version of MidiParser.
- */
-class MidiParser_EUP : public MidiParser {
-protected:
-	byte _instruments[6][50]; // Two extra bytes for SysEx ID and channel #
-	byte *_instr_to_channel;
-	struct {
-		byte *enable;
-		int8 *channel;
-		int8 *volume;
-		int8 *transpose;
-	} _presets;
-	bool _loop;
-	byte _presend;     // Tracks which startup implied events have been sent.
-	uint32 _base_tick; // Events times are relative to this base.
-
-protected:
-	void parseNextEvent (EventInfo &info);
-	void resetTracking();
-
-public:
-	bool loadMusic (byte *data, uint32 size);
-};
-
-
-
-//////////////////////////////////////////////////
-//
-// MidiParser_EUP implementation
-//
-//////////////////////////////////////////////////
-
-void MidiParser_EUP::parseNextEvent (EventInfo &info) {
-	byte *pos = _position._play_pos;
-
-	// FIXME: The presend is for sending init events
-	// that aren't actually in the stream. This would
-	// be for, e.g., instrument setup. Right now, we
-	// don't actually use the instruments specified
-	// in the music header. We're sending fixed GM
-	// program changes to get a reasonable "one-size-
-	// fits-all" sound until we actually support the
-	// FM synthesis capabilities of FM-TOWNS.
-	for (; _presend < 12; ++_presend) {
-		if (_instr_to_channel[_presend >> 1] >= 16)
-			continue;
-		info.start = pos;
-		info.delta = 0;
-		if (_presend & 1) {
-			byte *data = &_instruments[_presend >> 1][0];
-			data[1] = _instr_to_channel[_presend >> 1];
-			info.event = 0xF0;
-			info.ext.data = data;
-			info.length = 48;
-		} else {
-			info.event = 0xB0 | (_presend >> 1);
-			info.basic.param1 = 121;
-			info.basic.param2 = 0;
-		}
-		++_presend;
-		return;
-	}
-
-	while (true) {
-		byte cmd = *pos;
-		if ((cmd & 0xF0) == 0x90) {
-			byte preset = pos[1];
-			byte channel = _presets.channel[preset];
-			if (channel >= 16)
-				channel = cmd & 0x0F;
-			uint16 tick = (pos[2] | ((uint16) pos[3] << 7)) + _base_tick;
-			int note = (int) pos[4] + _presets.transpose[preset];
-			int volume = (int) pos[5];
-			// HACK: Loom-Towns distaff tracks seem to
-			// contain zero-volume note events, so change
-			// those to full volume.
-			if (!volume)
-				volume = 127;
-			volume += _presets.volume[preset];
-			if (volume > 127)
-				volume = 127;
-			else if (volume < 0)
-				volume = 0;
-			pos += 6;
-			if (_presets.enable[preset]) {
-				uint16 duration = pos[1] | (pos[2] << 4);
-				info.start = pos;
-				uint32 last = _position._last_event_tick;
-				info.delta = (tick < last) ? 0 : (tick - last);
-				info.event = 0x90 | channel;
-				info.length = duration;
-				info.basic.param1 = note;
-				info.basic.param2 = volume;
-				pos += 6;
-				break;
-			}
-			pos += 6;
-		} else if (cmd == 0xF2) {
-			// This is a "measure marker" of sorts.
-			// It advances the "base time", to which
-			// all event times are relative.
-			_base_tick += (pos[3] << 7) | pos[2];
-			pos += 6;
-		} else if (cmd == 0xF8) {
-			// TODO: Implement this.
-			pos += 6;
-		} else if (cmd == 0xFD || cmd == 0xFE) {
-			// End of track.
-			if (_loop && false) {
-				// TODO: Implement this.
-			} else {
-				info.start = pos;
-				uint32 last = _position._last_event_tick;
-				info.delta = (_base_tick < last) ? 0 : (_base_tick - last);
-				info.event = 0xFF;
-				info.length = 0;
-				info.ext.type = 0x2F;
-				info.ext.data = pos;
-				break;
-			}
-		} else {
-			error("Unknown Euphony music event 0x%02X", (int) cmd);
-			memset(&info, 0, sizeof(info));
-			pos = 0;
-			break;
-		}
-	}
-	_position._play_pos = pos;
-}
-
-bool MidiParser_EUP::loadMusic (byte *data, uint32 size) {
-	unloadMusic();
-	byte *pos = data;
-	int i;
-
-	if (memcmp(pos, "SO", 2)) {
-		error("'SO' header expected but found '%c%c' instead.", pos[0], pos[1]);
-		return false;
-	}
-
-	byte numInstruments = pos[16];
-	pos += 16 + 2;
-	for (i = 0; i < numInstruments; ++i) {
-		_instruments[i][0] = 0x7C;
-		memcpy (&_instruments[i][2], pos, 48);
-		pos += 48;
-	}
-
-	// Load the prest pointers
-	_presets.enable = pos;
-	pos += 32;
-	_presets.channel = (int8 *) pos;
-	pos += 32;
-	_presets.volume = (int8 *) pos;
-	pos += 32;
-	_presets.transpose = (int8 *) pos;
-	pos += 32;
-
-	pos += 8; // Unknown bytes
-	_instr_to_channel = pos; // Instrument-to-channel mapping
-	pos += 6;
-	pos += 4; // Skip the music size for now.
-	pos++;    // Unknown byte
-	byte tempo = *pos++;
-	_loop = (*pos++ != 1);
-	pos++;    // Unknown byte
-
-	_num_tracks = 1;
-	_ppqn = 120;
-	_tracks[0] = pos;
-
-	// Note that we assume the original data passed in
-	// will persist beyond this call, i.e. we do NOT
-	// copy the data to our own buffer. Take warning....
-	resetTracking();
-	setTempo (1000000 * 60 / tempo);
-	setTrack (0);
-	return true;
-}
-
-void MidiParser_EUP::resetTracking() {
-	MidiParser::resetTracking();
-	_presend = 0;
-	_base_tick = 0;
-}
-
-MidiParser *MidiParser_createEUP() { return new MidiParser_EUP; }
-
-} // End of namespace Scumm

Modified: scummvm/trunk/engines/scumm/module.mk
===================================================================
--- scummvm/trunk/engines/scumm/module.mk	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/engines/scumm/module.mk	2010-08-18 21:38:43 UTC (rev 52198)
@@ -29,7 +29,6 @@
 	imuse/sysex_samnmax.o \
 	imuse/sysex_scumm.o \
 	input.o \
-	midiparser_eup.o \
 	midiparser_ro.o \
 	object.o \
 	palette.o \
@@ -37,6 +36,7 @@
 	player_nes.o \
 	player_pce.o \
 	player_sid.o \
+	player_towns.o \
 	player_v1.o \
 	player_v2.o \
 	player_v2a.o \

Added: scummvm/trunk/engines/scumm/player_towns.cpp
===================================================================
--- scummvm/trunk/engines/scumm/player_towns.cpp	                        (rev 0)
+++ scummvm/trunk/engines/scumm/player_towns.cpp	2010-08-18 21:38:43 UTC (rev 52198)
@@ -0,0 +1,557 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+
+#include "scumm/sound.h"
+#include "scumm/player_towns.h"
+
+namespace Scumm {
+
+Player_Towns::Player_Towns(ScummEngine *vm, Audio::Mixer *mixer) : _vm(vm) {
+	_cdaCurrentSound = _eupCurrentSound = _cdaNumLoops = 0;
+	_cdaForceRestart = 0;
+	memset(_pcmCurrentSound, 0, sizeof(_pcmCurrentSound));
+	_cdaVolLeft = _cdaVolRight = 0;
+
+	_eupVolLeft = _eupVolRight = 0;
+	memset(&_ovrCur, 0, sizeof(SoundOvrParameters));
+	_soundOverride = 0;
+
+	if (_vm->_game.version == 3) {
+		_soundOverride = new SoundOvrParameters[200];
+		memset(_soundOverride, 0, 200 * sizeof(SoundOvrParameters));
+	}
+
+	_eupLooping = false;
+	_unkFlags = 0x33;
+
+	_driver = new TownsEuphonyDriver(mixer);
+}
+
+Player_Towns::~Player_Towns() {
+	delete[] _soundOverride;
+	delete _driver;
+}
+
+bool Player_Towns::init() {
+	if (!_driver)
+		return false;
+	
+	if (!_driver->init())
+		return false;
+
+	_driver->reserveSoundEffectChannels(8);
+
+	// Treat all 6 fm channels and all 8 pcm channels as sound effect channels
+	// since music seems to exist as CD audio only in the games which use this
+	// MusicEngine implementation.
+	_driver->intf()->setSoundEffectChanMask(-1);
+
+	setVolumeCD(255, 255);
+
+	return true;
+}
+
+void Player_Towns::setMusicVolume(int vol) {
+	_driver->setMusicVolume(vol);
+}
+
+void Player_Towns::setSfxVolume(int vol) {
+	_driver->setSoundEffectVolume(vol);
+}
+
+void Player_Towns::startSound(int sound) {
+	uint8 *ptr = _vm->getResourceAddress(rtSound, sound);
+	if (_vm->_game.version != 3) {
+		ptr += 2;
+	} else if (_soundOverride && sound > 0 && sound < 200) {
+		memcpy(&_ovrCur, &_soundOverride[sound], sizeof(SoundOvrParameters));
+		memset(&_soundOverride[sound], 0, sizeof(SoundOvrParameters));
+	}
+
+	int type = ptr[13];
+
+	if (type == 0) {
+		playPcmTrack(sound, ptr + 6);
+	} else if (type == 1) {
+		playEuphonyTrack(sound, ptr + 6);
+	} else if (type == 2) {
+		playCdaTrack(sound, ptr + 6);
+	}
+	memset(&_ovrCur, 0, sizeof(SoundOvrParameters));
+}
+
+void Player_Towns::stopSound(int sound) {
+	if (sound != 0 && sound == _cdaCurrentSound) {
+		_cdaCurrentSound = 0;
+		_vm->_sound->stopCD();
+		_vm->_sound->stopCDTimer();
+	}
+
+	if (sound != 0 && sound == _eupCurrentSound) {
+		_eupCurrentSound = 0;
+		_eupLooping = false;
+		_driver->stopParser();
+	}
+	
+	stopPcmTrack(sound);
+}
+
+void Player_Towns::stopAllSounds() {
+	_cdaCurrentSound = 0;
+	_vm->_sound->stopCD();
+	_vm->_sound->stopCDTimer();
+
+	// Loom disasm seems to stop only CD audio and PCM sounds here
+	/*_eupCurrentSound = 0;
+	_eupLooping = false;
+	_driver->stopParser();*/
+
+	stopPcmTrack(0);
+}
+
+int Player_Towns::getSoundStatus(int sound) const {
+	if (sound == _cdaCurrentSound)
+		return _vm->_sound->pollCD();
+	if (sound == _eupCurrentSound)
+		return _driver->parserIsPlaying() ? 1 : 0;
+	for (int i = 1; i < 9; i++) {
+		if (_pcmCurrentSound[i].index == sound)
+			return _driver->soundEffectIsPlaying(i + 0x3f) ? 1 : 0;
+	}
+	return 0;
+}
+
+int32 Player_Towns::doCommand(int numargs, int args[]) {
+	int32 res = 0;
+	
+	switch (args[0]) {
+	case 2:
+		_driver->intf()->callback(73, 0);
+		break;
+
+	case 3:
+		restartLoopingSounds();
+		break;
+
+	case 8:
+		startSound(args[1]);
+		break;
+
+	case 9:
+		_vm->_sound->stopSound(args[1]);
+		break;
+
+	case 11:
+		stopPcmTrack(0);
+		break;
+
+	case 14:
+		startSoundEx(args[1], args[2], args[3], args[4]);
+		break;
+
+	case 15:
+		stopSoundSuspendLooping(args[1]);
+		break;
+
+	default:
+		warning("Player_Towns::doCommand: Unknown command %d", args[0]);
+		break;
+	}
+
+	return res;
+}
+
+void Player_Towns::setVolumeCD(int left, int right) {
+	_cdaVolLeft = left & 0xff;
+	_cdaVolRight = right & 0xff;
+	_driver->setOutputVolume(1, left >> 1, right >> 1);
+}
+
+void Player_Towns::setSoundVolume(int sound, int left, int right) {
+	if (_soundOverride && sound > 0 && sound < 200) {
+		_soundOverride[sound].vLeft = left;
+		_soundOverride[sound].vRight = right;
+	}
+}
+
+void Player_Towns::setSoundNote(int sound, int note) {
+	if (_soundOverride && sound > 0 && sound < 200)
+		_soundOverride[sound].note = note;
+}
+
+void Player_Towns::saveLoadWithSerializer(Serializer *ser) {
+	_cdaCurrentSoundTemp = (_vm->_sound->pollCD() && _cdaNumLoops > 1) ? _cdaCurrentSound & 0xff : 0;
+	_cdaNumLoopsTemp = _cdaNumLoops & 0xff;
+
+	static const SaveLoadEntry cdEntries[] = {
+		MKLINE(Player_Towns, _cdaCurrentSoundTemp, sleUint8, VER(81)),
+		MKLINE(Player_Towns, _cdaNumLoopsTemp, sleUint8, VER(81)),
+		MKLINE(Player_Towns, _cdaVolLeft, sleUint8, VER(81)),
+		MKLINE(Player_Towns, _cdaVolRight, sleUint8, VER(81)),
+		MKEND()
+	};
+
+	ser->saveLoadEntries(this, cdEntries);
+
+	if (!_eupLooping && !_driver->parserIsPlaying())
+		_eupCurrentSound = 0;
+
+	static const SaveLoadEntry eupEntries[] = {
+		MKLINE(Player_Towns, _eupCurrentSound, sleUint8, VER(81)),
+		MKLINE(Player_Towns, _eupLooping, sleUint8, VER(81)),
+		MKLINE(Player_Towns, _eupVolLeft, sleUint8, VER(81)),
+		MKLINE(Player_Towns, _eupVolRight, sleUint8, VER(81)),
+		MKEND()
+	};
+
+	ser->saveLoadEntries(this, eupEntries);
+
+	static const SaveLoadEntry pcmEntries[] = {
+		MKLINE(PcmCurrentSound, index, sleInt16, VER(81)),
+		MKLINE(PcmCurrentSound, chan, sleInt16, VER(81)),
+		MKLINE(PcmCurrentSound, note, sleUint8, VER(81)),
+		MKLINE(PcmCurrentSound, velo, sleUint8, VER(81)),
+		MKLINE(PcmCurrentSound, pan, sleUint8, VER(81)),
+		MKLINE(PcmCurrentSound, paused, sleUint8, VER(81)),
+		MKLINE(PcmCurrentSound, looping, sleUint8, VER(81)),
+		MKLINE(PcmCurrentSound, priority, sleUint32, VER(81)),
+		MKEND()
+	};
+
+	for (int i = 1; i < 9; i++) {
+		if (!_pcmCurrentSound[i].index)
+			continue;
+
+		if (_driver->soundEffectIsPlaying(i + 0x3f))
+			continue;
+
+		_driver->stopSoundEffect(i + 0x3f);
+
+		_pcmCurrentSound[i].index = 0;
+	}
+
+	ser->saveLoadArrayOf(_pcmCurrentSound, 9, sizeof(PcmCurrentSound), pcmEntries);
+}
+
+void Player_Towns::restoreAfterLoad() {
+	setVolumeCD(_cdaVolLeft, _cdaVolRight);
+	
+	if (_cdaCurrentSoundTemp) {
+		uint8 *ptr = _vm->getResourceAddress(rtSound, _cdaCurrentSoundTemp) + 6;
+		if (_vm->_game.version != 3)
+			ptr += 2;
+		
+		if (ptr[7] == 2) {
+			playCdaTrack(_cdaCurrentSoundTemp, ptr, true);
+			_cdaCurrentSound = _cdaCurrentSoundTemp;
+			_cdaNumLoops = _cdaNumLoopsTemp;
+		}
+	}
+
+	if (_eupCurrentSound) {
+		uint8 *ptr = _vm->getResourceAddress(rtSound, _eupCurrentSound) + 6;
+		if (_vm->_game.version != 3)
+			ptr += 2;
+		
+		if (ptr[7] == 1) {
+			setSoundVolume(_eupCurrentSound, _eupVolLeft, _eupVolRight);
+			playEuphonyTrack(_eupCurrentSound, ptr);
+		}
+	}
+
+	for (int i = 1; i < 9; i++) {
+		if (!_pcmCurrentSound[i].index)
+			continue;
+
+		uint8 *ptr = _vm->getResourceAddress(rtSound, _pcmCurrentSound[i].index);
+		if (!ptr)
+			continue;
+
+		if (_vm->_game.version != 3)
+			ptr += 2;
+
+		if (ptr[13])
+			continue;
+
+		playPcmTrack(_pcmCurrentSound[i].index, ptr + 6, _pcmCurrentSound[i].velo, _pcmCurrentSound[i].pan, _pcmCurrentSound[i].note);
+	}
+}
+
+int Player_Towns::getNextFreePcmChannel(int sound, int sfxChanRelIndex) {
+	int chan = 0;
+	for (int i = 8; i; i--) {
+		if (!_pcmCurrentSound[i].index) {
+			chan = i;
+			continue;
+		}
+
+		if (_driver->soundEffectIsPlaying(i + 0x3f))
+			continue;
+
+		chan = i;
+		_vm->_sound->stopSound(_pcmCurrentSound[chan].index);
+	}
+
+	if (!chan) {
+		uint16 l = 0xffff;
+		uint8 *ptr = 0;
+		for (int i = 8; i; i--) {
+			ptr = _vm->getResourceAddress(rtSound, _pcmCurrentSound[i].index) + 6;
+			uint16 a = READ_LE_UINT16(ptr + 10);
+			if (a <= l) {
+				chan = i;
+				l = a;
+			}
+		}
+
+		ptr = _vm->getResourceAddress(rtSound, sound) + 6;
+		if (l <= READ_LE_UINT16(ptr + 10))
+			_vm->_sound->stopSound(_pcmCurrentSound[chan].index);
+		else
+			chan = 0;
+	}
+
+	if (chan) {
+		_pcmCurrentSound[chan].index = sound;
+		_pcmCurrentSound[chan].chan = sfxChanRelIndex;
+	}
+
+	return chan;
+}
+
+void Player_Towns::restartLoopingSounds() {
+	if (_cdaNumLoops && !_cdaForceRestart)
+		_cdaForceRestart = 1;
+
+	for (int i = 1; i < 9; i++) {
+		if (!_pcmCurrentSound[i].paused)
+			continue;
+
+		_pcmCurrentSound[i].paused = 0;
+
+		uint8 *ptr = _vm->getResourceAddress(rtSound, _pcmCurrentSound[i].index);
+		if (!ptr)
+			continue;
+		ptr += 24;
+
+		int c = 1;
+		while (_pcmCurrentSound[i].chan != c) {
+			ptr = ptr + READ_LE_UINT32(&ptr[12]) + 32;
+			c++;
+		}
+
+		_driver->playSoundEffect(i + 0x3f, _pcmCurrentSound[i].note, _pcmCurrentSound[i].velo, ptr);
+	}
+
+	_driver->intf()->callback(73, 1);
+}
+
+void Player_Towns::startSoundEx(int sound, int velo, int pan, int note) {
+	uint8 *ptr = _vm->getResourceAddress(rtSound, sound) + 2;
+
+	if (pan > 99)
+		pan = 99;
+
+	velo = velo ? (velo * ptr[14] + 50) / 100 : ptr[14];
+	velo = CLIP(velo, 1, 255);
+
+	if (ptr[13] == 0) {
+		velo >>= 1;
+
+		if (!velo)
+			velo = 1;
+
+		pan = pan ? (((pan << 7) - pan) + 50) / 100 : 64;
+
+		playPcmTrack(sound, ptr + 6, velo, pan, note);
+
+	} else if (ptr[13] == 2) {
+		int volLeft = velo;
+		int volRight = velo;
+		
+		if (pan < 50)
+			volRight = ((pan * 2 + 1) * velo + 50) / 100;
+		else if (pan > 50)
+			volLeft = (((99 - pan) * 2 + 1) * velo + 50) / 100;
+
+		setVolumeCD(volLeft, volRight);
+
+		if (!_cdaForceRestart && sound == _cdaCurrentSound)
+			return;
+
+		playCdaTrack(sound, ptr + 6, true);
+	}
+}
+
+void Player_Towns::stopSoundSuspendLooping(int sound) {
+	if (!sound) {
+		return;
+	} else if (sound == _cdaCurrentSound) {
+		if (_cdaNumLoops && _cdaForceRestart)
+			_cdaForceRestart = 1;		
+	} else {
+		for (int i = 1; i < 9; i++) {
+			if (sound == _pcmCurrentSound[i].index) {
+				if (!_driver->soundEffectIsPlaying(i + 0x3f))
+					continue;
+				_driver->stopSoundEffect(i + 0x3f);
+				if (_pcmCurrentSound[i].looping)
+					_pcmCurrentSound[i].paused = 1;
+				else 
+					_pcmCurrentSound[i].index = 0;
+			}
+		}
+	}
+}
+
+void Player_Towns::playEuphonyTrack(int sound, const uint8 *data) {
+	const uint8 *pos = data + 16;
+	const uint8 *src = pos + data[14] * 48;
+	const uint8 *trackData = src + 150;
+
+	for (int i = 0; i < 32; i++)
+		_driver->chanEnable(i, *src++);
+	for (int i = 0; i < 32; i++)
+		_driver->chanMode(i, 0xff);
+	for (int i = 0; i < 32; i++)
+		_driver->chanOrdr(i, *src++);
+	for (int i = 0; i < 32; i++)
+		_driver->chanVolumeShift(i, *src++);
+	for (int i = 0; i < 32; i++)
+		_driver->chanNoteShift(i, *src++);
+
+	src += 8;
+	for (int i = 0; i < 6; i++)
+		_driver->assignChannel(i, *src++);
+
+	for (int i = 0; i < data[14]; i++) {
+		_driver->loadInstrument(i, i, pos + i * 48);
+		_driver->intf()->callback(4, i, i);
+	}
+
+	_eupVolLeft = _ovrCur.vLeft;
+	_eupVolRight = _ovrCur.vRight;
+	int lvl = _ovrCur.vLeft + _ovrCur.vRight;
+	if (!lvl)
+		lvl = data[8] + data[9];
+	lvl >>= 2;
+
+	for (int i = 0; i < 6; i++)
+		_driver->chanVolume(i, lvl);
+
+	uint32 trackSize = READ_LE_UINT32(src);
+	src += 4;
+	uint8 startTick = *src++;
+	
+	_driver->setMusicTempo(*src++);
+	_driver->startMusicTrack(trackData, trackSize, startTick);
+
+	_eupLooping = (*src != 1) ? 1 : 0;
+	_driver->setMusicLoop(_eupLooping != 0);
+	_driver->continueParsing();
+	_eupCurrentSound = sound;
+}
+
+void Player_Towns::playPcmTrack(int sound, const uint8 *data, int velo, int pan, int note) {
+	const uint8 *ptr = data;
+	const uint8 *sfxData = ptr + 16;
+	
+	int note2, velocity;
+
+	if (velo)
+		velocity = velo;
+	else if (_ovrCur.vLeft + _ovrCur.vRight)
+		velocity = (_ovrCur.vLeft + _ovrCur.vRight) >> 2;
+	else
+		velocity = ptr[8] >> 1;
+
+	int numChan = ptr[14];
+	for (int i = 0; i < numChan; i++) {
+		int chan = getNextFreePcmChannel(sound, i);
+		if (!chan)
+			return;
+		
+		_driver->intf()->callback(70, _unkFlags);
+		_driver->chanPanPos(chan + 0x3f, pan);
+		
+		if (note)
+			note2 = note;
+		else if (_ovrCur.note)
+			note2 = _ovrCur.note;
+		else
+			note2 = sfxData[28];
+		
+		_driver->playSoundEffect(chan + 0x3f, note2, velocity, sfxData);
+		
+		_pcmCurrentSound[chan].note = note2;
+		_pcmCurrentSound[chan].velo = velocity;
+		_pcmCurrentSound[chan].pan = pan;
+		_pcmCurrentSound[chan].paused = 0;
+		_pcmCurrentSound[chan].looping = READ_LE_UINT32(&sfxData[20]) ? 1 : 0;
+
+		sfxData += (READ_LE_UINT32(&sfxData[12]) + 32);
+	}
+}
+
+void Player_Towns::playCdaTrack(int sound, const uint8 *data, bool skipTrackVelo) {
+	const uint8 *ptr = data;
+
+	if (!sound)
+		return;
+
+	if (!skipTrackVelo) {
+		if (_ovrCur.vLeft + _ovrCur.vRight)
+			setVolumeCD(_ovrCur.vLeft, _ovrCur.vRight);
+		else
+			setVolumeCD(ptr[8], ptr[9]);
+	}
+
+	if (sound == _cdaCurrentSound && _vm->_sound->pollCD() == 1)			
+		return;
+
+	ptr += 16;
+
+	int track = ptr[0];
+	_cdaNumLoops = ptr[1];
+	int start = (ptr[2] * 60 + ptr[3]) * 75 + ptr[4];
+	int end = (ptr[5] * 60 + ptr[6]) * 75 + ptr[7];
+
+	_vm->_sound->playCDTrack(track, _cdaNumLoops == 0xff ? -1 : _cdaNumLoops, start, end <= start ? 0 : end - start);
+	_cdaForceRestart = 0;
+	_cdaCurrentSound = sound;
+}
+
+void Player_Towns::stopPcmTrack(int sound) {
+	for (int i = 1; i < 9; i++) {
+		if (sound == _pcmCurrentSound[i].index || !sound) {
+			_driver->stopSoundEffect(i + 0x3f);
+			_pcmCurrentSound[i].index = 0;
+		}
+	}
+}
+
+} // End of namespace Scumm
+


Property changes on: scummvm/trunk/engines/scumm/player_towns.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/scumm/player_towns.h
===================================================================
--- scummvm/trunk/engines/scumm/player_towns.h	                        (rev 0)
+++ scummvm/trunk/engines/scumm/player_towns.h	2010-08-18 21:38:43 UTC (rev 52198)
@@ -0,0 +1,120 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SCUMM_PLAYER_TOWNS_H
+#define SCUMM_PLAYER_TOWNS_H
+
+#include "scumm/scumm.h"
+#include "scumm/music.h"
+#include "sound/softsynth/fmtowns_pc98/towns_euphony.h"
+
+namespace Scumm {
+
+class Player_Towns : public MusicEngine {
+public:
+	Player_Towns(ScummEngine *vm, Audio::Mixer *mixer);
+	virtual ~Player_Towns();
+
+	bool init();
+
+	void setMusicVolume(int vol);
+	void setSfxVolume(int vol);
+	void startSound(int sound);
+	void stopSound(int sound);
+	void stopAllSounds();
+
+	int getSoundStatus(int sound) const;
+	int getCurrentCdaSound() { return _cdaCurrentSound; } 
+	int getCurrentCdaVolume() { return (_cdaVolLeft + _cdaVolRight + 1) >> 1; } 
+
+	virtual int32 doCommand(int numargs, int args[]);
+
+	void setVolumeCD(int left, int right);
+	void setSoundVolume(int sound, int left, int right);
+	void setSoundNote(int sound, int note);
+
+	void saveLoadWithSerializer(Serializer *ser);
+	void restoreAfterLoad();
+
+	TownsEuphonyDriver *driver() { return _driver; }
+
+protected:
+	virtual int getNextFreePcmChannel(int sound, int sfxChanRelIndex);
+
+private:
+	void restartLoopingSounds();
+	void startSoundEx(int sound, int velo, int pan, int note);
+	void stopSoundSuspendLooping(int sound);
+
+	void playEuphonyTrack(int sound, const uint8 *data);
+	void playPcmTrack(int sound, const uint8 *data, int velo = 0, int pan = 64, int note = 0);
+	void playCdaTrack(int sound, const uint8 *data, bool skipTrackVelo = false);
+
+	void stopPcmTrack(int sound);
+
+	uint8 _cdaVolLeft;
+	uint8 _cdaVolRight;
+
+	struct SoundOvrParameters {
+		uint8 vLeft;
+		uint8 vRight;
+		uint8 note;
+	};
+
+	SoundOvrParameters *_soundOverride;
+	SoundOvrParameters _ovrCur;
+	
+	uint8 _unkFlags;
+
+	struct PcmCurrentSound {
+		uint16 index;
+		uint16 chan;
+		uint8 note;
+		uint8 velo;
+		uint8 pan;
+		uint8 paused;
+		uint8 looping;
+		uint32 priority;
+	} _pcmCurrentSound[9];
+
+	uint8 _eupCurrentSound;
+	uint8 _eupLooping;
+	uint8 _eupVolLeft;
+	uint8 _eupVolRight;
+
+	uint8 _cdaCurrentSound;
+	uint8 _cdaNumLoops;
+	uint8 _cdaForceRestart;
+
+	uint8 _cdaCurrentSoundTemp;
+	uint8 _cdaNumLoopsTemp;
+
+	TownsEuphonyDriver *_driver;
+	ScummEngine *_vm;
+};
+
+} // End of namespace Scumm
+
+#endif


Property changes on: scummvm/trunk/engines/scumm/player_towns.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: scummvm/trunk/engines/scumm/saveload.cpp
===================================================================
--- scummvm/trunk/engines/scumm/saveload.cpp	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/engines/scumm/saveload.cpp	2010-08-18 21:38:43 UTC (rev 52198)
@@ -32,6 +32,7 @@
 #include "scumm/charset.h"
 #include "scumm/imuse_digi/dimuse.h"
 #include "scumm/imuse/imuse.h"
+#include "player_towns.h"
 #include "scumm/he/intern_he.h"
 #include "scumm/object.h"
 #include "scumm/resource.h"
@@ -447,6 +448,9 @@
 	// Update volume settings
 	syncSoundSettings();
 
+	if (_townsPlayer && (hdr.ver >= VER(81)))
+		_townsPlayer->restoreAfterLoad();
+
 	// Init NES costume data
 	if (_game.platform == Common::kPlatformNES) {
 		if (hdr.ver < VER(47))
@@ -1394,6 +1398,11 @@
 		_imuse->save_or_load(s, this);
 	}
 
+
+	// Save/load FM-Towns audio status
+	if (_townsPlayer)
+		_townsPlayer->saveLoadWithSerializer(s);
+
 	//
 	// Save/load the charset renderer state
 	//

Modified: scummvm/trunk/engines/scumm/saveload.h
===================================================================
--- scummvm/trunk/engines/scumm/saveload.h	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/engines/scumm/saveload.h	2010-08-18 21:38:43 UTC (rev 52198)
@@ -50,7 +50,7 @@
  * only saves/loads those which are valid for the version of the savegame
  * which is being loaded/saved currently.
  */
-#define CURRENT_VER 80
+#define CURRENT_VER 81
 
 /**
  * An auxillary macro, used to specify savegame versions. We use this instead

Modified: scummvm/trunk/engines/scumm/script_v5.cpp
===================================================================
--- scummvm/trunk/engines/scumm/script_v5.cpp	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/engines/scumm/script_v5.cpp	2010-08-18 21:38:43 UTC (rev 52198)
@@ -29,6 +29,7 @@
 #include "scumm/scumm_v3.h"
 #include "scumm/scumm_v5.h"
 #include "scumm/sound.h"
+#include "scumm/player_towns.h"
 #include "scumm/util.h"
 #include "scumm/verbs.h"
 
@@ -1595,21 +1596,18 @@
 		debug(0, "o5_resourceRoutines %d not yet handled (script %d)", op, vm.slot[_currentScript].number);
 		break;
 	case 35:
-		// TODO: Might be used to set CD volume in FM-TOWNS Loom
-		foo = getVarOrDirectByte(PARAM_2);
-		debug(0, "o5_resourceRoutines %d not yet handled (script %d)", op, vm.slot[_currentScript].number);
+		if (_townsPlayer)
+			_townsPlayer->setVolumeCD(getVarOrDirectByte(PARAM_2), resid);
 		break;
 	case 36:
-		// TODO: Sets the loudness of a sound resource. Used in Indy3 and Zak.
 		foo = getVarOrDirectByte(PARAM_2);
 		bar = fetchScriptByte();
-		debug(0, "o5_resourceRoutines %d not yet handled (script %d)", op, vm.slot[_currentScript].number);
+		if (_townsPlayer)
+			_townsPlayer->setSoundVolume(resid, foo, bar);		
 		break;
 	case 37:
-		// TODO: Sets the pitch of a sound resource (pitch = foo - center semitones.
-		// "center" is at 0x32 in the sfx resource (always 0x3C in zak256, but sometimes different in Indy3).
-		foo = getVarOrDirectByte(PARAM_2);
-		debug(0, "o5_resourceRoutines %d not yet handled (script %d)", op, vm.slot[_currentScript].number);
+		if (_townsPlayer)
+			_townsPlayer->setSoundNote(resid, getVarOrDirectByte(PARAM_2));
 		break;
 
 	default:
@@ -1981,6 +1979,7 @@
 			break;
 		case 0xFF:
 			// TODO: Might return current CD volume in FM-TOWNS Loom. See also bug #805691.
+			result = _townsPlayer->getCurrentCdaVolume();
 			break;
 		default:
 			// TODO: return track length in seconds. We'll have to extend Sound and OSystem for this.

Modified: scummvm/trunk/engines/scumm/scumm.cpp
===================================================================
--- scummvm/trunk/engines/scumm/scumm.cpp	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/engines/scumm/scumm.cpp	2010-08-18 21:38:43 UTC (rev 52198)
@@ -48,6 +48,7 @@
 #include "scumm/imuse_digi/dimuse.h"
 #include "scumm/smush/smush_mixer.h"
 #include "scumm/smush/smush_player.h"
+#include "scumm/player_towns.h"
 #include "scumm/insane/insane.h"
 #include "scumm/he/animation_he.h"
 #include "scumm/he/intern_he.h"
@@ -146,6 +147,7 @@
 	_imuse = NULL;
 	_imuseDigital = NULL;
 	_musicEngine = NULL;
+	_townsPlayer = NULL;
 	_verbs = NULL;
 	_objs = NULL;
 	_sound = NULL;
@@ -1757,6 +1759,10 @@
 		_musicEngine = new Player_V2CMS(this, _mixer);
 	} else if (_game.platform == Common::kPlatform3DO && _game.heversion <= 62) {
 		// 3DO versions use digital music and sound samples.
+	} else if (_game.platform == Common::kPlatformFMTowns && (_game.version == 3 || _game.id == GID_MONKEY)) {
+		_musicEngine = _townsPlayer = new Player_Towns(this, _mixer);
+		if (!_townsPlayer->init())
+			error("Failed to initialize FM-Towns audio driver.");
 	} else if (_game.version >= 3 && _game.heversion <= 62) {
 		MidiDriver *nativeMidiDriver = 0;
 		MidiDriver *adlibMidiDriver = 0;
@@ -1806,6 +1812,10 @@
 		_musicEngine->setMusicVolume(soundVolumeMusic);
 	}
 
+	if (_townsPlayer) {
+		_townsPlayer->setSfxVolume(soundVolumeSfx);
+	}
+
 	_mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, soundVolumeSfx);
 	_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, soundVolumeMusic);
 	_mixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, soundVolumeSpeech);

Modified: scummvm/trunk/engines/scumm/scumm.h
===================================================================
--- scummvm/trunk/engines/scumm/scumm.h	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/engines/scumm/scumm.h	2010-08-18 21:38:43 UTC (rev 52198)
@@ -70,6 +70,7 @@
 class IMuse;
 class IMuseDigital;
 class MusicEngine;
+class Player_Towns;
 class ScummEngine;
 class ScummDebugger;
 class Serializer;
@@ -426,6 +427,7 @@
 	IMuse *_imuse;
 	IMuseDigital *_imuseDigital;
 	MusicEngine *_musicEngine;
+	Player_Towns *_townsPlayer;
 	Sound *_sound;
 
 	VerbSlot *_verbs;

Modified: scummvm/trunk/engines/scumm/sound.cpp
===================================================================
--- scummvm/trunk/engines/scumm/sound.cpp	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/engines/scumm/sound.cpp	2010-08-18 21:38:43 UTC (rev 52198)
@@ -31,6 +31,7 @@
 #include "scumm/file.h"
 #include "scumm/imuse/imuse.h"
 #include "scumm/imuse_digi/dimuse.h"
+#include "scumm/player_towns.h"
 #include "scumm/scumm.h"
 #include "scumm/sound.h"
 #include "scumm/util.h"
@@ -150,9 +151,10 @@
 						data[0] >> 8, data[0] & 0xFF,
 						data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
 
-			if (_vm->_imuse) {
+			if (_vm->_townsPlayer)
+				_vm->VAR(_vm->VAR_SOUNDRESULT) = (short)_vm->_townsPlayer->doCommand(num, data);
+			else if (_vm->_imuse)
 				_vm->VAR(_vm->VAR_SOUNDRESULT) = (short)_vm->_imuse->doCommand(num, data);
-			}
 		}
 	}
 	_soundQuePos = 0;
@@ -312,91 +314,6 @@
 		stream = Audio::makeRawStream(sound, size, rate, Audio::FLAG_UNSIGNED);
 		_mixer->playStream(Audio::Mixer::kSFXSoundType, NULL, stream, soundID);
 	}
-	else if ((_vm->_game.platform == Common::kPlatformFMTowns && _vm->_game.version == 3) || READ_BE_UINT32(ptr) == MKID_BE('SOUN') || READ_BE_UINT32(ptr) == MKID_BE('TOWS')) {
-
-		bool tows = READ_BE_UINT32(ptr) == MKID_BE('TOWS');
-		if (_vm->_game.version == 3) {
-			size = READ_LE_UINT32(ptr);
-		} else {
-			size = READ_BE_UINT32(ptr + 4) - 2;
-			if (tows)
-				size += 8;
-			ptr += 2;
-		}
-
-		rate = 11025;
-		int type = *(ptr + 0x0D);
-		int numInstruments;
-
-		if (tows)
-			type = 0;
-
-		switch (type) {
-		case 0:	// Sound effect
-			numInstruments = *(ptr + 0x14);
-			if (tows)
-				numInstruments = 1;
-			ptr += 0x16;
-			size -= 0x16;
-
-			while (numInstruments--) {
-				int waveSize = READ_LE_UINT32(ptr + 0x0C);
-				int loopStart = READ_LE_UINT32(ptr + 0x10) * 2;
-				int loopEnd = READ_LE_UINT32(ptr + 0x14) - 1;
-				rate = READ_LE_UINT32(ptr + 0x18) * 1000 / 0x62;
-				ptr += 0x20;
-				size -= 0x20;
-				if (size < waveSize) {
-					warning("Wrong wave size in sound #%i: %i", soundID, waveSize);
-					waveSize = size;
-				}
-				sound = (byte *)malloc(waveSize);
-				for (int x = 0; x < waveSize; x++) {
-					byte b = *ptr++;
-					if (b < 0x80)
-						sound[x] = 0x7F - b;
-					else
-						sound[x] = b;
-				}
-				size -= waveSize;
-
-				if (loopEnd > 0) {
-					Audio::SeekableAudioStream *s = Audio::makeRawStream(sound, waveSize, rate, Audio::FLAG_UNSIGNED);
-					stream = new Audio::SubLoopingAudioStream(s, 0, Audio::Timestamp(0, loopStart, rate), Audio::Timestamp(0, loopEnd, rate));
-				} else {
-					stream = Audio::makeRawStream(sound, waveSize, rate, Audio::FLAG_UNSIGNED);
-				}
-				_mixer->playStream(Audio::Mixer::kSFXSoundType, NULL, stream, soundID, 255, 0);
-			}
-			break;
-		case 1:
-			// Music (Euphony format)
-			if (_vm->_musicEngine)
-				_vm->_musicEngine->startSound(soundID);
-			break;
-		case 2: // CD track resource
-			ptr += 0x16;
-
-			if (soundID == _currentCDSound && pollCD() == 1) {
-				return;
-			}
-
-			{
-				int track = ptr[0];
-				int loops = ptr[1];
-				int start = (ptr[2] * 60 + ptr[3]) * 75 + ptr[4];
-				int end = (ptr[5] * 60 + ptr[6]) * 75 + ptr[7];
-
-				playCDTrack(track, loops == 0xff ? -1 : loops, start, end <= start ? 0 : end - start);
-			}
-
-			_currentCDSound = soundID;
-			break;
-		default:
-			// All other sound types are ignored
-			break;
-		}
-	}
 	else if ((_vm->_game.id == GID_LOOM) && (_vm->_game.platform == Common::kPlatformMacintosh))  {
 		// Mac version of Loom uses yet another sound format
 		/*
@@ -480,6 +397,9 @@
 		if (_vm->_musicEngine) {
 			_vm->_musicEngine->startSound(soundID);
 		}
+
+		if (_vm->_townsPlayer)
+			_currentCDSound = _vm->_townsPlayer->getCurrentCdaSound();
 	}
 }
 

Modified: scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_audio.cpp
===================================================================
--- scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_audio.cpp	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_audio.cpp	2010-08-18 21:38:43 UTC (rev 52198)
@@ -200,9 +200,9 @@
 		INTCB(notImpl),
 		// 72
 		INTCB(notImpl),
+		INTCB(cdaToggle),
 		INTCB(notImpl),
 		INTCB(notImpl),
-		INTCB(notImpl),
 		// 76
 		INTCB(notImpl),
 		INTCB(notImpl),
@@ -222,9 +222,19 @@
 
 	_timerBase = (uint32)(_baserate * 1000000.0f);
 	_tickLength = 2 * _timerBase;
+
+	setTimerCallbackA((ChipTimerProc)&TownsAudioInterface::timerCallbackA);
+	setTimerCallbackB((ChipTimerProc)&TownsAudioInterface::timerCallbackB);
 }
 
 TownsAudioInterface::~TownsAudioInterface() {
+	Common::StackLock lock(_mutex);
+	reset();
+	_ready = false;
+
+	setTimerCallbackA();
+	setTimerCallbackB();
+
 	delete[] _fmSaveReg[0];
 	delete[] _fmSaveReg[1];
 	delete[] _fmInstruments;
@@ -759,6 +769,12 @@
 	return 0;
 }
 
+int TownsAudioInterface::intf_cdaToggle(va_list &args) {
+	//int mode = va_arg(args, int);
+	//_unkMask = mode ? 0x7f : 0x3f;
+	return 0;
+}
+
 int TownsAudioInterface::intf_pcmUpdateEnvelopeGenerator(va_list &args) {
 	for (int i = 0; i < 8; i++)
 		pcmUpdateEnvelopeGenerator(i);

Modified: scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_audio.h
===================================================================
--- scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_audio.h	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_audio.h	2010-08-18 21:38:43 UTC (rev 52198)
@@ -95,6 +95,7 @@
 	int intf_setOutputVolume(va_list &args);
 	int intf_resetOutputVolume(va_list &args);
 	int intf_updateOutputVolume(va_list &args);
+	int intf_cdaToggle(va_list &args);
 	int intf_pcmUpdateEnvelopeGenerator(va_list &args);
 
 	int intf_notImpl(va_list &args);

Modified: scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp
===================================================================
--- scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_pc98_driver.cpp	2010-08-18 21:38:43 UTC (rev 52198)
@@ -1037,11 +1037,21 @@
 	_musicPlaying(false), _sfxPlaying(false), _fading(false), _looping(0), _ready(false) {
 
 	_sfxOffsets[0] = _sfxOffsets[1] = 0;
+
+	setTimerCallbackA((ChipTimerProc)&TownsPC98_AudioDriver::timerCallbackA);
+	setTimerCallbackB((ChipTimerProc)&TownsPC98_AudioDriver::timerCallbackB);
 }
 
 TownsPC98_AudioDriver::~TownsPC98_AudioDriver() {
+	Common::StackLock lock(_mutex);
+
 	reset();
 
+	_ready = false;
+
+	setTimerCallbackA();
+	setTimerCallbackB();
+
 	if (_channels) {
 		for (int i = 0; i < _numChan; i++)
 			delete _channels[i];

Modified: scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp
===================================================================
--- scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.cpp	2010-08-18 21:38:43 UTC (rev 52198)
@@ -835,6 +835,7 @@
 
 	memset(&_timers[0], 0, sizeof(ChipTimer));
 	memset(&_timers[1], 0, sizeof(ChipTimer));
+
 	_timers[0].cb = &TownsPC98_FmSynth::timerCallbackA;
 	_timers[1].cb = &TownsPC98_FmSynth::timerCallbackB;
 	_timerbase = (uint32)(_baserate * 1000000.0f);	
@@ -842,6 +843,9 @@
 
 TownsPC98_FmSynth::~TownsPC98_FmSynth() {
 	Common::StackLock lock(_mutex);
+	
+	_ready = false;
+
 	_mixer->stopHandle(_soundHandle);
 	delete _ssg;
 	delete _prc;
@@ -1154,6 +1158,14 @@
 	return numSamples;
 }
 
+void TownsPC98_FmSynth::setTimerCallbackA(ChipTimerProc proc) {
+	_timers[0].cb = proc;
+}
+
+void TownsPC98_FmSynth::setTimerCallbackB(ChipTimerProc proc) {
+	_timers[1].cb = proc;
+}
+
 uint8 TownsPC98_FmSynth::readSSGStatus() {
 	return _ssg->chanEnable();
 }

Modified: scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h
===================================================================
--- scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h	2010-08-18 20:41:03 UTC (rev 52197)
+++ scummvm/trunk/sound/softsynth/fmtowns_pc98/towns_pc98_fmsynth.h	2010-08-18 21:38:43 UTC (rev 52198)
@@ -71,6 +71,10 @@
 	}
 
 protected:
+	typedef void (TownsPC98_FmSynth::*ChipTimerProc)();
+	void setTimerCallbackA(ChipTimerProc proc = &TownsPC98_FmSynth::timerCallbackA);
+	void setTimerCallbackB(ChipTimerProc proc = &TownsPC98_FmSynth::timerCallbackB);
+
 	// Implement this in your inherited class if your driver generates
 	// additional output that has to be inserted into the buffer.
 	virtual void nextTickEx(int32 *buffer, uint32 bufferSize) {}
@@ -80,8 +84,8 @@
 	}
 	uint8 readSSGStatus();
 
-	virtual void timerCallbackA() = 0;
-	virtual void timerCallbackB() = 0;
+	virtual void timerCallbackA() {}
+	virtual void timerCallbackB() {}
 
 	// The audio driver can store and apply two different audio settings
 	// (usually for music and sound effects). The channel mask will determine
@@ -139,8 +143,6 @@
 
 	bool _regProtectionFlag;
 
-	typedef void (TownsPC98_FmSynth::*ChipTimerProc)();
-
 	struct ChipTimer {
 		bool enabled;
 		uint16 value;


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