[Scummvm-git-logs] scummvm master -> b69027cf1549443cd9ce25aa01e2a29dde03fba3

dreammaster noreply at scummvm.org
Sun Jul 5 07:55:05 UTC 2026


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
b69027cf15 MADS: DRAGONSPHERE: Added support for demo


Commit: b69027cf1549443cd9ce25aa01e2a29dde03fba3
    https://github.com/scummvm/scummvm/commit/b69027cf1549443cd9ce25aa01e2a29dde03fba3
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-07-05T17:54:54+10:00

Commit Message:
MADS: DRAGONSPHERE: Added support for demo

Changed paths:
    engines/mads/madsv2/animview/functions.cpp
    engines/mads/madsv2/dragonsphere/asound.cpp
    engines/mads/madsv2/dragonsphere/dragonsphere.cpp
    engines/mads/madsv2/dragonsphere/global.cpp
    engines/mads/madsv2/dragonsphere/global.h
    engines/mads/madsv2/dragonsphere/main.cpp
    engines/mads/madsv2/dragonsphere/rooms/room106.cpp
    engines/mads/madsv2/dragonsphere/rooms/room110.cpp
    engines/mads/madsv2/dragonsphere/rooms/room113.cpp
    engines/mads/madsv2/dragonsphere/rooms/section1.cpp
    engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
    engines/mads/madsv2/dragonsphere/sound_dragonsphere.h


diff --git a/engines/mads/madsv2/animview/functions.cpp b/engines/mads/madsv2/animview/functions.cpp
index 84631ecc5ee..237e6f4a4bb 100644
--- a/engines/mads/madsv2/animview/functions.cpp
+++ b/engines/mads/madsv2/animview/functions.cpp
@@ -79,11 +79,16 @@ void add_anim(const char *name) {
  * Parses a flag from an animation line in the resource file
  */
 void flag_parse(const char *param) {
-	switch (tolower(*param++)) {
+	char c = tolower(*param++);
+	switch (c) {
 	case 'j':
 		wait_for_music_at_end = true;
 		break;
 
+	case 'k':
+		// Toggle whether keypress jumps to end. Not implemented in ScummVM
+		break;
+
 	case 'o':
 		// Specify opening special effect
 		assert(anim_count < MAX_ANIM);
@@ -133,7 +138,7 @@ void flag_parse(const char *param) {
 		break;
 
 	default:
-		error("Unsupported animview flag - %c", *param);
+		error("Unsupported animview flag - %c", c);
 		break;
 	}
 }
diff --git a/engines/mads/madsv2/dragonsphere/asound.cpp b/engines/mads/madsv2/dragonsphere/asound.cpp
index 3c4e099e593..1d8ae58e587 100644
--- a/engines/mads/madsv2/dragonsphere/asound.cpp
+++ b/engines/mads/madsv2/dragonsphere/asound.cpp
@@ -1261,8 +1261,8 @@ op2_set_vol:
 			}
 
 			default:
-				/* Unknown sub-opcode: no _pSrc advance (def_10EAC). */
-				goto dispatch;
+				/* Unknown sub-opcode */
+				goto note_event;
 			}
 		}
 
@@ -1642,7 +1642,7 @@ op2_set_vol:
 		}
 
 		/* Unknown group: skip. */
-		goto dispatch;
+		goto note_event;
 	}
 
 note_event:
diff --git a/engines/mads/madsv2/dragonsphere/dragonsphere.cpp b/engines/mads/madsv2/dragonsphere/dragonsphere.cpp
index 3a0d4b998e6..3540d8b7801 100644
--- a/engines/mads/madsv2/dragonsphere/dragonsphere.cpp
+++ b/engines/mads/madsv2/dragonsphere/dragonsphere.cpp
@@ -72,7 +72,7 @@ Common::Error DragonsphereEngine::run() {
 	}
 
 	// Set up sound manager
-	_soundManager = new DragonSoundManager(_mixer, _soundFlag);
+	_soundManager = new DragonSoundManager(_mixer, _soundFlag, isDemo());
 	_soundManager->validate();
 
 	// Run the game
diff --git a/engines/mads/madsv2/dragonsphere/global.cpp b/engines/mads/madsv2/dragonsphere/global.cpp
index 77981cc1a84..f1de965acd9 100644
--- a/engines/mads/madsv2/dragonsphere/global.cpp
+++ b/engines/mads/madsv2/dragonsphere/global.cpp
@@ -107,6 +107,8 @@ extern void room_909_synchronize(Common::Serializer &s);
 
 } // namespace Rooms
 
+const char *DEMO_MSG = "NOT AVAILABLE IN DEMO VERSION";
+
 void global_section_constructor() {
 	section_preload_code_pointer = NULL;
 	section_room_constructor = NULL;
diff --git a/engines/mads/madsv2/dragonsphere/global.h b/engines/mads/madsv2/dragonsphere/global.h
index 05b560c1598..edd4a44685e 100644
--- a/engines/mads/madsv2/dragonsphere/global.h
+++ b/engines/mads/madsv2/dragonsphere/global.h
@@ -257,6 +257,8 @@ enum {
 #define GRAPES_GROWING                  1  /* is for global[grapes_have_grown] in 411 */
 #define GRAPES_GROWN                    2
 
+extern const char *DEMO_MSG;
+
 extern void global_section_constructor();
 extern void sync_room(Common::Serializer &s);
 
diff --git a/engines/mads/madsv2/dragonsphere/main.cpp b/engines/mads/madsv2/dragonsphere/main.cpp
index 1ce6679b43a..f89dd548ab8 100644
--- a/engines/mads/madsv2/dragonsphere/main.cpp
+++ b/engines/mads/madsv2/dragonsphere/main.cpp
@@ -122,6 +122,7 @@ static void main_cold_data_init() {
 	game_menu_init = global_menu_system_init;
 	game_menu_exit = global_menu_system_shutdown;
 	game_emergency_save = global_emergency_save;
+	game.difficulty = g_engine->isDemo() ? 0 : -1;
 
 	Common::strcpy_s(config_file_name, "config.dra");
 	Common::strcpy_s(save_game_key, "drag");
@@ -149,7 +150,7 @@ static void game_main(int argc, const char **argv) {
 	mads_mode = env_verify();
 
 	new_section = 1;
-	new_room = 101;
+	new_room = g_engine->isDemo() ? 110 : 101;
 	player.x = 160;
 	player.y = 78;
 
@@ -220,6 +221,8 @@ void dragonsphere_main() {
 
 	if (ConfMan.getBool("start_game") || ConfMan.hasKey("save_slot"))
 		selected_item = 0;
+	else if (g_engine->isDemo())
+		selected_item = 5;
 	else if (ConfMan.getBool("start_intro"))
 		selected_item = 3;
 	else
@@ -257,13 +260,19 @@ void dragonsphere_main() {
 
 		case 3:
 			AnimView::animview_main("@dragon");
-			selected_item = -1;
+			selected_item = g_engine->isDemo() ? 0 : -1;
 			break;
 
 		case 4:
 			// Exit
 			return;
 
+		case 5:
+			// Demo
+			AnimView::animview_main("@demodisk");
+			selected_item = 0;
+			break;
+
 		default:
 			// Credits
 			TextView::textview_main("credits");
diff --git a/engines/mads/madsv2/dragonsphere/rooms/room106.cpp b/engines/mads/madsv2/dragonsphere/rooms/room106.cpp
index aad02665cb0..5e8b8463903 100644
--- a/engines/mads/madsv2/dragonsphere/rooms/room106.cpp
+++ b/engines/mads/madsv2/dragonsphere/rooms/room106.cpp
@@ -34,6 +34,7 @@
 #include "mads/madsv2/dragonsphere/global.h"
 #include "mads/madsv2/dragonsphere/rooms/section1.h"
 #include "mads/madsv2/dragonsphere/rooms/room106.h"
+#include "mads/madsv2/engine.h"
 
 namespace MADS {
 namespace MADSV2 {
@@ -229,8 +230,8 @@ static void room_106_init() {
 
 		seq[fx_fire_sconce] = kernel_seq_forward(ss[fx_fire_sconce], false, 7, 0, 0, 0);
 
-		if (previous_room == 107 || previous_room == 118 ||
-			previous_room == 111) {
+		if (previous_room == 107 || previous_room == 118 || previous_room == 111 ||
+				previous_room == 110) {
 			seq[fx_door_104] = kernel_seq_stamp(ss[fx_door_104], false, KERNEL_FIRST);
 			kernel_seq_depth(seq[fx_door_104], 8);
 			seq[fx_door_105] = kernel_seq_stamp(ss[fx_door_105], false, KERNEL_FIRST);
@@ -241,7 +242,8 @@ static void room_106_init() {
 			kernel_seq_depth(seq[fx_door_104], 8);
 		}
 
-		if (previous_room == 105) {      /* Player comes from Ballroom  */
+		if (previous_room == 105) {
+			/* Player comes from Ballroom  */
 			seq[fx_door_104] = kernel_seq_stamp(ss[fx_door_104], false, KERNEL_FIRST);
 			kernel_seq_depth(seq[fx_door_104], 8);
 			seq[fx_door_105] = kernel_seq_stamp(ss[fx_door_105], false, KERNEL_LAST);
@@ -262,7 +264,8 @@ static void room_106_init() {
 				player_walk(MAC_CONV_X, MAC_CONV_Y, FACING_NORTHWEST);
 			}
 
-		} else if (previous_room == 118) {      /* Player comes from Courtyard */
+		} else if (previous_room == 118 || previous_room == 110) {
+			/* Player comes from Courtyard, or Outside Castle in the demo */
 			local->prevent = true;
 
 			if (player.been_here_before) {
@@ -277,12 +280,14 @@ static void room_106_init() {
 					MAC_CONV_X, MAC_CONV_Y, FACING_NORTHWEST, true);
 			}
 
-		} else if (previous_room == 107) {      /* Player comes from Council Chamber */
+		} else if (previous_room == 107) {
+			/* Player comes from Council Chamber */
 			player.x = START_X_ROOM_107;
 			player.y = START_Y_ROOM_107;
 			player.facing = FACING_NORTHWEST;
 
-		} else if (previous_room == 614) {      /* Cut scene */
+		} else if (previous_room == 614) {
+			/* Cut scene */
 			conv_get(CONV_34_CUT_SCENE);
 
 			kernel_init_dialog();  /* clear interface */
@@ -333,7 +338,8 @@ static void room_106_init() {
 				player.facing = FACING_NORTHEAST;
 			}
 
-		} else if (previous_room != KERNEL_RESTORING_GAME) { /* Player comes from Meeting Chamber rm104 */
+		} else if (previous_room != KERNEL_RESTORING_GAME) {
+			/* Player comes from Meeting Chamber rm104 */
 			seq[fx_door_105] = kernel_seq_stamp(ss[fx_door_105], false, KERNEL_FIRST);
 			kernel_seq_depth(seq[fx_door_105], 8);
 			player_walk(WALK_TO_X_FROM_104, WALK_TO_Y_FROM_104, FACING_SOUTH);
@@ -1089,7 +1095,7 @@ static void room_106_pre_parser() {
 
 	if (player_said_2(walk_through, door_to_courtyard) || player_said_2(open, door_to_courtyard) ||
 		player_said_2(pull, door_to_courtyard)) {
-		player.walk_off_edge_to_room = 118;
+		player.walk_off_edge_to_room = g_engine->isDemo() ? 110 : 118;
 	}
 
 	if ((player_said_1(look_at) || player_said_1(look)) && player_said_1(Dragonsphere)) {
@@ -1163,6 +1169,11 @@ static void room_106_parser() {
 
 	if (player_said_2(walk_through, door_to_meeting_room) || player_said_2(open, door_to_meeting_room) ||
 		player_said_2(pull, door_to_meeting_room)) {
+		if (g_engine->isDemo()) {
+			popup_alert(24, DEMO_MSG, nullptr);
+			goto handled;
+		}
+
 		switch (kernel.trigger) {
 		case 0:
 			player.commands_allowed = false;
@@ -1228,6 +1239,11 @@ static void room_106_parser() {
 
 	if (player_said_2(walk_through, door_to_ballroom) || player_said_2(open, door_to_ballroom) ||
 		player_said_2(pull, door_to_ballroom)) {
+		if (g_engine->isDemo()) {
+			popup_alert(24, DEMO_MSG, nullptr);
+			goto handled;
+		}
+
 		switch (kernel.trigger) {
 		case 0:
 			player.commands_allowed = false;
@@ -1293,6 +1309,11 @@ static void room_106_parser() {
 
 	if (player_said_2(walk_through, door_to_council_room) || player_said_2(open, door_to_council_room) ||
 		player_said_2(pull, door_to_council_room)) {
+		if (g_engine->isDemo()) {
+			popup_alert(24, DEMO_MSG, nullptr);
+			goto handled;
+		}
+
 		new_room = 107;
 		goto handled;
 	}
diff --git a/engines/mads/madsv2/dragonsphere/rooms/room110.cpp b/engines/mads/madsv2/dragonsphere/rooms/room110.cpp
index 9c07d58a970..a5fa4807270 100644
--- a/engines/mads/madsv2/dragonsphere/rooms/room110.cpp
+++ b/engines/mads/madsv2/dragonsphere/rooms/room110.cpp
@@ -34,6 +34,7 @@
 #include "mads/madsv2/dragonsphere/global.h"
 #include "mads/madsv2/dragonsphere/rooms/section1.h"
 #include "mads/madsv2/dragonsphere/rooms/room110.h"
+#include "mads/madsv2/engine.h"
 
 namespace MADS {
 namespace MADSV2 {
@@ -2240,6 +2241,7 @@ static void room_110_pre_parser() {
 		player_cancel_command();
 		local->activate_timer = false;
 		global[pre_room] = 110;
+
 		if (global[dragon_my_scene] < global[dragon_high_scene]) {
 			global[dragon_my_scene]++;
 			new_room = 111;
@@ -2256,10 +2258,13 @@ static void room_110_pre_parser() {
 				conv_run(CONV_GUARD_CASTLE);
 				player_cancel_command();
 			} else {
-				player.walk_off_edge_to_room = 118;
+				player.walk_off_edge_to_room = g_engine->isDemo() ? 106 : 118;
 			}
 		}
 
+		if (g_engine->isDemo() && player_said_2(walk_down, road_to_east))
+			return;
+
 		if (!player_said_2(walk_down, road_to_east) && local->cut_scene) {
 			local->cut_scene = false;
 			global[dragon_my_scene]--;
@@ -2391,6 +2396,11 @@ static void room_110_parser() {
 		goto handled;
 	}
 
+	if (g_engine->isDemo() && player_said_2(walk_down, road_to_east)) {
+		popup_alert(24, DEMO_MSG, nullptr);
+		goto handled;
+	}
+
 	if (player_said_2(jump_down, well)) {
 		if (global[player_persona] == PLAYER_IS_KING) {
 			switch (kernel.trigger) {
diff --git a/engines/mads/madsv2/dragonsphere/rooms/room113.cpp b/engines/mads/madsv2/dragonsphere/rooms/room113.cpp
index 5a2790ede59..33c223a17ba 100644
--- a/engines/mads/madsv2/dragonsphere/rooms/room113.cpp
+++ b/engines/mads/madsv2/dragonsphere/rooms/room113.cpp
@@ -34,6 +34,7 @@
 #include "mads/madsv2/dragonsphere/global.h"
 #include "mads/madsv2/dragonsphere/rooms/section1.h"
 #include "mads/madsv2/dragonsphere/rooms/room113.h"
+#include "mads/madsv2/engine.h"
 
 namespace MADS {
 namespace MADSV2 {
@@ -418,7 +419,9 @@ static void room_113_daemon() {
 	}
 
 	if (kernel.trigger == ROOM_113_RESTART) {
-		if (game.difficulty == EASY_MODE) {
+		if (g_engine->isDemo()) {
+			// Demo doesn't have any text display
+		} else if (game.difficulty == EASY_MODE) {
 			text_show(11336);
 		} else {
 			text_show(45);
diff --git a/engines/mads/madsv2/dragonsphere/rooms/section1.cpp b/engines/mads/madsv2/dragonsphere/rooms/section1.cpp
index 442250081ec..dfe2ba12a99 100644
--- a/engines/mads/madsv2/dragonsphere/rooms/section1.cpp
+++ b/engines/mads/madsv2/dragonsphere/rooms/section1.cpp
@@ -30,6 +30,7 @@
 #include "mads/madsv2/dragonsphere/global.h"
 #include "mads/madsv2/dragonsphere/rooms/section1.h"
 #include "mads/madsv2/dragonsphere/mads/sounds.h"
+#include "mads/madsv2/engine.h"
 
 namespace MADS {
 namespace MADSV2 {
@@ -126,7 +127,10 @@ void section_1_walker() {
 void section_1_interface() {
 	int interface;
 
-	if (new_room == 116) {
+	if (g_engine->isDemo()) {
+		interface = 0;
+
+	} else if (new_room == 116) {
 		interface = 2;
 
 	} else if (new_room == 110) {
diff --git a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
index 1b8c68e42b5..ecdd2ab4f5a 100644
--- a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
+++ b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.cpp
@@ -42,17 +42,26 @@ void DragonSoundManager::validate() {
 		nullptr,
 		"379fcc9af2142f15a3e7166eee6dd49d"
 	};
+	static const char *const MD5_DEMO[] = {
+		"c4fc9e9d7e2392c69ea7b3ca997e832d",
+		nullptr, nullptr, nullptr, nullptr,
+		nullptr, nullptr, nullptr,
+		"21432c2dd055d0d505ede8fecc77b29a"
+	};
 
 	for (int i = 1; i <= 9; ++i) {
 		if (i == 7 || i == 8)
 			continue;
+		if (_isDemo && i != 1 && i != 9)
+			continue;
+
 		Common::Path filename(Common::String::format("asound.dr%d", i));
 		if (!f.open(filename))
 			error("Could not process - %s", filename.toString().c_str());
 		Common::String md5str = Common::computeStreamMD5AsString(f, 8192);
 		f.close();
 
-		if (md5str != MD5[i - 1])
+		if (md5str != (_isDemo ? MD5_DEMO[i - 1] : MD5[i - 1]))
 			error("Invalid sound file - %s", filename.toString().c_str());
 	}
 }
@@ -60,7 +69,10 @@ void DragonSoundManager::validate() {
 void DragonSoundManager::loadDriver(int sectionNumber) {
 	switch (sectionNumber) {
 	case 1:
-		_driver = new ASound1(_mixer, _opl);
+		if (_isDemo)
+			_driver = new ASoundDemo1(_mixer, _opl);
+		else
+			_driver = new ASound1(_mixer, _opl);
 		break;
 	case 2:
 		_driver = new ASound2(_mixer, _opl);
@@ -78,7 +90,10 @@ void DragonSoundManager::loadDriver(int sectionNumber) {
 		_driver = new ASound6(_mixer, _opl);
 		break;
 	case 9:
-		_driver = new ASound9(_mixer, _opl);
+		if (_isDemo)
+			_driver = new ASoundDemo9(_mixer, _opl);
+		else
+			_driver = new ASound9(_mixer, _opl);
 		break;
 	default:
 		_driver = nullptr;
@@ -3058,6 +3073,872 @@ int ASound9::command63() {
 	return 0;
 }
 
+/*-----------------------------------------------------------------------*/
+/* ASoundDemo1  (asound.dr1 [demo])                                       *
+ *-----------------------------------------------------------------------*/
+
+const ASoundDemo1::CommandPtr ASoundDemo1::_commandList[93] = {
+	// commands 0-8  (commands0)
+	&ASoundDemo1::command0,  &ASoundDemo1::command1,  &ASoundDemo1::command2,  &ASoundDemo1::command3,
+	&ASoundDemo1::command4,  &ASoundDemo1::command5,  &ASoundDemo1::command6,  &ASoundDemo1::command7,
+	&ASoundDemo1::command8,
+	// 9-15 absent
+	nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+	// command 16  (commands16)
+	&ASoundDemo1::command16,
+	// 17-23 absent
+	nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+	// commands 24-27, 28-29 = no-op, commands 30-43, 44 = no-op  (commands24)
+	&ASoundDemo1::command24, &ASoundDemo1::command25, &ASoundDemo1::command26, &ASoundDemo1::command27,
+	nullptr,                 nullptr,
+	&ASoundDemo1::command30, &ASoundDemo1::command31, &ASoundDemo1::command32, &ASoundDemo1::command33,
+	&ASoundDemo1::command34, &ASoundDemo1::command35, &ASoundDemo1::command36, &ASoundDemo1::command37,
+	&ASoundDemo1::command38, &ASoundDemo1::command39, &ASoundDemo1::command40, &ASoundDemo1::command41,
+	&ASoundDemo1::command42, &ASoundDemo1::command43,
+	nullptr,
+	// 45-63 absent
+	nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+	nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+	nullptr, nullptr, nullptr, nullptr, nullptr,
+	// commands 64-89 = no-op, commands 90-92  (commands64)
+	nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+	nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+	nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+	nullptr, nullptr, nullptr, nullptr, nullptr,
+	&ASoundDemo1::command90, &ASoundDemo1::command91, &ASoundDemo1::command92
+};
+
+ASoundDemo1::ASoundDemo1(Audio::Mixer *mixer, OPL::OPL *opl)
+		: ASound(mixer, opl, "asound.dr1", 0x23e0, 0x4900) {
+	auto samplesStream = getDataStream(0x1dc);
+	for (int i = 0; i < 182; ++i)
+		_samples.push_back(AdlibSample(samplesStream));
+}
+
+int ASoundDemo1::command(int commandId, int param) {
+	if (commandId > 92 || !_commandList[commandId])
+		return 0;
+	return (this->*_commandList[commandId])();
+}
+
+// commands 0-8: delegate to base ASound
+int ASoundDemo1::command0() { return ASound::command0(); }
+int ASoundDemo1::command1() { return ASound::command1(); }
+int ASoundDemo1::command2() { return ASound::command2(); }
+int ASoundDemo1::command3() { return ASound::command3(); }
+int ASoundDemo1::command4() { return ASound::command4(); }
+int ASoundDemo1::command5() { return ASound::command5(); }
+int ASoundDemo1::command6() { return ASound::command6(); }
+int ASoundDemo1::command7() { return ASound::command7(); }
+int ASoundDemo1::command8() { return ASound::command8(); }
+
+// ---------------------------------------------------------------------------
+// command16 - no isSoundActive guard; if music channels are busy, defer via
+// callback, otherwise load immediately. Loads channels 0-6.
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand16() {
+	resetCallbackTimer(0x90);
+	ASound::command1();
+	_channels[0]->load(loadData(0x2BC6));
+	_channels[1]->load(loadData(0x2C74));
+	_channels[2]->load(loadData(0x2CEC));
+	_channels[3]->load(loadData(0x2D68));
+	_channels[4]->load(loadData(0x2DC0));
+	_channels[5]->load(loadData(0x2DE7));
+	_channels[6]->load(loadData(0x2E07));
+}
+
+int ASoundDemo1::command16() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand16));
+	else
+		loadCommand16();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 25-27 - sound effects via findFreeChannelFull
+// ---------------------------------------------------------------------------
+int ASoundDemo1::command25() {
+	findFreeChannelFull(loadData(0x4575));
+	findFreeChannelFull(loadData(0x45A1));
+	return 0;
+}
+
+int ASoundDemo1::command26() {
+	findFreeChannelFull(loadData(0x45CF));
+	return 0;
+}
+
+int ASoundDemo1::command27() {
+	findFreeChannelFull(loadData(0x45DB));
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command30 - isMusicChannelsActive guard, deferred callback, load ch0-5
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand30() {
+	resetCallbackTimer(0xB0);
+	ASound::command1();
+	_channels[0]->load(loadData(0x2F2A));
+	_channels[1]->load(loadData(0x2F73));
+	_channels[2]->load(loadData(0x2FD5));
+	_channels[3]->load(loadData(0x2FFF));
+	_channels[4]->load(loadData(0x302F));
+	_channels[5]->load(loadData(0x303E));
+}
+
+int ASoundDemo1::command30() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand30));
+	else
+		loadCommand30();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command31 - isMusicChannelsActive guard, deferred callback, load ch0-5.
+// Note: command1() is called before resetCallbackTimer here (reversed order
+// vs command30/command16).
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand31() {
+	ASound::command1();
+	resetCallbackTimer(0xB0);
+	_channels[0]->load(loadData(0x304E));
+	_channels[1]->load(loadData(0x30F4));
+	_channels[2]->load(loadData(0x3156));
+	_channels[3]->load(loadData(0x3191));
+	_channels[4]->load(loadData(0x3210));
+	_channels[5]->load(loadData(0x3228));
+}
+
+int ASoundDemo1::command31() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand31));
+	else
+		loadCommand31();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command32 - isMusicChannelsActive guard, deferred callback, load ch0-5
+// (channels 3-5 load from non-sequential data offsets)
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand32() {
+	resetCallbackTimer(0x50);
+	ASound::command1();
+	_channels[0]->load(loadData(0x32AC));
+	_channels[1]->load(loadData(0x32FE));
+	_channels[2]->load(loadData(0x3387));
+	_channels[3]->load(loadData(0x32EF));
+	_channels[4]->load(loadData(0x3371));
+	_channels[5]->load(loadData(0x3448));
+}
+
+int ASoundDemo1::command32() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand32));
+	else
+		loadCommand32();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command33 - isMusicChannelsActive guard, deferred callback, load ch0-5
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand33() {
+	resetCallbackTimer(0x60);
+	ASound::command1();
+	_channels[0]->load(loadData(0x3A7E));
+	_channels[1]->load(loadData(0x3B16));
+	_channels[2]->load(loadData(0x3B9C));
+	_channels[3]->load(loadData(0x3BE7));
+	_channels[4]->load(loadData(0x3C1E));
+	_channels[5]->load(loadData(0x3C34));
+}
+
+int ASoundDemo1::command33() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand33));
+	else
+		loadCommand33();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command34 - isMusicChannelsActive guard, deferred callback, load ch0-5
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand34() {
+	resetCallbackTimer(0x80);
+	ASound::command1();
+	_channels[0]->load(loadData(0x40FE));
+	_channels[1]->load(loadData(0x41C2));
+	_channels[2]->load(loadData(0x42B1));
+	_channels[3]->load(loadData(0x4345));
+	_channels[4]->load(loadData(0x43B5));
+	_channels[5]->load(loadData(0x43C4));
+}
+
+int ASoundDemo1::command34() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand34));
+	else
+		loadCommand34();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command35 - isMusicChannelsActive guard, deferred callback, load ch0-5
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand35() {
+	resetCallbackTimer(0xC0);
+	ASound::command1();
+	_channels[0]->load(loadData(0x43E8));
+	_channels[1]->load(loadData(0x444B));
+	_channels[2]->load(loadData(0x44B6));
+	_channels[3]->load(loadData(0x44C5));
+	_channels[4]->load(loadData(0x44D6));
+	_channels[5]->load(loadData(0x44E0));
+}
+
+int ASoundDemo1::command35() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand35));
+	else
+		loadCommand35();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command36 - isMusicChannelsActive guard, deferred callback, load ch0-5.
+// Note: command1() is called before resetCallbackTimer here (reversed order
+// vs command33-35).
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand36() {
+	ASound::command1();
+	resetCallbackTimer(0x60);
+	_channels[0]->load(loadData(0x1906));
+	_channels[1]->load(loadData(0x19ED));
+	_channels[2]->load(loadData(0x1AC8));
+	_channels[3]->load(loadData(0x1BF8));
+	_channels[4]->load(loadData(0x1CE4));
+	_channels[5]->load(loadData(0x1CFC));
+}
+
+int ASoundDemo1::command36() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand36));
+	else
+		loadCommand36();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command37 - isMusicChannelsActive guard, deferred callback, load ch0-5
+// (command1() before resetCallbackTimer, as in command36)
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand37() {
+	ASound::command1();
+	resetCallbackTimer(0xB0);
+	_channels[0]->load(loadData(0x1D40));
+	_channels[1]->load(loadData(0x1D95));
+	_channels[2]->load(loadData(0x1DF7));
+	_channels[3]->load(loadData(0x1E51));
+	_channels[4]->load(loadData(0x1E60));
+	_channels[5]->load(loadData(0x1E6F));
+}
+
+int ASoundDemo1::command37() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand37));
+	else
+		loadCommand37();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command38 - isMusicChannelsActive guard, deferred callback, load ch0-5
+// (resetCallbackTimer before command1(), as in command33-35)
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand38() {
+	resetCallbackTimer(0xA8);
+	ASound::command1();
+	_channels[0]->load(loadData(0x1E7E));
+	_channels[1]->load(loadData(0x1FF7));
+	_channels[2]->load(loadData(0x21AD));
+	_channels[3]->load(loadData(0x2476));
+	_channels[4]->load(loadData(0x269E));
+	_channels[5]->load(loadData(0x293B));
+}
+
+int ASoundDemo1::command38() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand38));
+	else
+		loadCommand38();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command39 - isMusicChannelsActive guard, deferred callback, load ch0-5
+// (channels 2-5 load from non-sequential data offsets)
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand39() {
+	resetCallbackTimer(0x90);
+	ASound::command1();
+	_channels[0]->load(loadData(0x2972));
+	_channels[1]->load(loadData(0x29DF));
+	_channels[2]->load(loadData(0x2BB7));
+	_channels[3]->load(loadData(0x2A56));
+	_channels[4]->load(loadData(0x2B36));
+	_channels[5]->load(loadData(0x2B8A));
+}
+
+int ASoundDemo1::command39() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand39));
+	else
+		loadCommand39();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command40 - isMusicChannelsActive guard, deferred callback, load ch0-6
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand40() {
+	resetCallbackTimer(0x90);
+	ASound::command1();
+	_channels[0]->load(loadData(0x17D6));
+	_channels[1]->load(loadData(0x180C));
+	_channels[2]->load(loadData(0x183F));
+	_channels[3]->load(loadData(0x1880));
+	_channels[4]->load(loadData(0x18B2));
+	_channels[5]->load(loadData(0x18CD));
+	_channels[6]->load(loadData(0x18E3));
+}
+
+int ASoundDemo1::command40() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand40));
+	else
+		loadCommand40();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command41 - isMusicChannelsActive guard, deferred callback, load ch0-5
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand41() {
+	resetCallbackTimer(0x50);
+	ASound::command1();
+	_channels[0]->load(loadData(0x3C44));
+	_channels[1]->load(loadData(0x3CB1));
+	_channels[2]->load(loadData(0x3CCD));
+	_channels[3]->load(loadData(0x3CE9));
+	_channels[4]->load(loadData(0x3CF6));
+	_channels[5]->load(loadData(0x3D03));
+}
+
+int ASoundDemo1::command41() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand41));
+	else
+		loadCommand41();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command42 - isMusicChannelsActive guard, deferred callback, load ch0-5.
+// Uses resetCallbackTimerEx: counter=0x60, period=0xE0 (asymmetric).
+// (channels 2 and 5 load from non-sequential data offsets)
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand42() {
+	resetCallbackTimerEx(0x60, 0xE0);
+	ASound::command1();
+	_channels[0]->load(loadData(0x3D10));
+	_channels[1]->load(loadData(0x3D66));
+	_channels[2]->load(loadData(0x40EE));
+	_channels[3]->load(loadData(0x3DED));
+	_channels[4]->load(loadData(0x3F7C));
+	_channels[5]->load(loadData(0x4053));
+}
+
+int ASoundDemo1::command42() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand42));
+	else
+		loadCommand42();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command43 - isMusicChannelsActive guard, deferred callback, load ch0-5
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand43() {
+	resetCallbackTimer(0x60);
+	ASound::command1();
+	_channels[0]->load(loadData(0x347A));
+	_channels[1]->load(loadData(0x35BB));
+	_channels[2]->load(loadData(0x36A8));
+	_channels[3]->load(loadData(0x37B5));
+	_channels[4]->load(loadData(0x38A5));
+	_channels[5]->load(loadData(0x3A4D));
+}
+
+int ASoundDemo1::command43() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand43));
+	else
+		loadCommand43();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command24 - sound effects via findFreeChannelFull
+// ---------------------------------------------------------------------------
+int ASoundDemo1::command24() {
+	findFreeChannelFull(loadData(0x4514));
+	findFreeChannelFull(loadData(0x4547));
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 90-91 - sound effects via findFreeChannelFull
+// ---------------------------------------------------------------------------
+int ASoundDemo1::command90() {
+	findFreeChannelFull(loadData(0x3236));
+	findFreeChannelFull(loadData(0x3260));
+	return 0;
+}
+
+int ASoundDemo1::command91() {
+	findFreeChannelFull(loadData(0x326B));
+	findFreeChannelFull(loadData(0x32A1));
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command92 - isMusicChannelsActive guard, deferred callback, load ch0-5
+// ---------------------------------------------------------------------------
+void ASoundDemo1::loadCommand92() {
+	resetCallbackTimer(0x54);
+	ASound::command1();
+	_channels[0]->load(loadData(0x2E16));
+	_channels[1]->load(loadData(0x2E62));
+	_channels[2]->load(loadData(0x2EA9));
+	_channels[3]->load(loadData(0x2ED2));
+	_channels[4]->load(loadData(0x2EF5));
+	_channels[5]->load(loadData(0x2F1C));
+}
+
+int ASoundDemo1::command92() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo1, loadCommand92));
+	else
+		loadCommand92();
+	return 0;
+}
+
+/*-----------------------------------------------------------------------*/
+/* ASoundDemo9  (asound.dr9 [demo])                                       *
+ *-----------------------------------------------------------------------*/
+
+const ASoundDemo9::CommandPtr ASoundDemo9::_commandList[51] = {
+	// commands 0-8  (commands0)
+	&ASoundDemo9::command0,  &ASoundDemo9::command1,  &ASoundDemo9::command2,  &ASoundDemo9::command3,
+	&ASoundDemo9::command4,  &ASoundDemo9::command5,  &ASoundDemo9::command6,  &ASoundDemo9::command7,
+	&ASoundDemo9::command8,
+	// 9-15 absent
+	nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+	// command 16  (commands16_24)
+	&ASoundDemo9::command16,
+	// 17-23 absent
+	nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr,
+	// command 24 = shared with command16
+	&ASoundDemo9::command16,
+	// commands 25-29  (commands24)
+	&ASoundDemo9::command25, &ASoundDemo9::command26, &ASoundDemo9::command27,
+	&ASoundDemo9::command28_32, &ASoundDemo9::command29_33,
+	// 30-31 absent
+	nullptr, nullptr,
+	// commands 32-33 = shared with commands 28/29
+	&ASoundDemo9::command28_32, &ASoundDemo9::command29_33,
+	// commands 34-50
+	&ASoundDemo9::command34, &ASoundDemo9::command35, &ASoundDemo9::command36, &ASoundDemo9::command37,
+	&ASoundDemo9::command38, &ASoundDemo9::command39, &ASoundDemo9::command40, &ASoundDemo9::command41,
+	&ASoundDemo9::command42, &ASoundDemo9::command43, &ASoundDemo9::command44, &ASoundDemo9::command45,
+	&ASoundDemo9::command46, &ASoundDemo9::command47, &ASoundDemo9::command48, &ASoundDemo9::command49,
+	&ASoundDemo9::command50
+};
+
+ASoundDemo9::ASoundDemo9(Audio::Mixer *mixer, OPL::OPL *opl)
+		: ASound(mixer, opl, "asound.dr9", 0x23a0, 0x62b0) {
+	auto samplesStream = getDataStream(0x1dc);
+	for (int i = 0; i < 182; ++i)
+		_samples.push_back(AdlibSample(samplesStream));
+}
+
+int ASoundDemo9::command(int commandId, int param) {
+	if (commandId > 50 || !_commandList[commandId])
+		return 0;
+	return (this->*_commandList[commandId])();
+}
+
+// commands 0-8: delegate to base ASound
+int ASoundDemo9::command0() { return ASound::command0(); }
+int ASoundDemo9::command1() { return ASound::command1(); }
+int ASoundDemo9::command2() { return ASound::command2(); }
+int ASoundDemo9::command3() { return ASound::command3(); }
+int ASoundDemo9::command4() { return ASound::command4(); }
+int ASoundDemo9::command5() { return ASound::command5(); }
+int ASoundDemo9::command6() { return ASound::command6(); }
+int ASoundDemo9::command7() { return ASound::command7(); }
+int ASoundDemo9::command8() { return ASound::command8(); }
+
+// ---------------------------------------------------------------------------
+// commands 16, 25-27 - sound effects via findFreeChannelFull
+// ---------------------------------------------------------------------------
+int ASoundDemo9::command16() {
+	findFreeChannelFull(loadData(0x5EC6));
+	findFreeChannelFull(loadData(0x5EF9));
+	return 0;
+}
+
+int ASoundDemo9::command25() {
+	findFreeChannelFull(loadData(0x5F27));
+	findFreeChannelFull(loadData(0x5F53));
+	return 0;
+}
+
+int ASoundDemo9::command26() { findFreeChannelFull(loadData(0x5F81)); return 0; }
+int ASoundDemo9::command27() { findFreeChannelFull(loadData(0x5F8D)); return 0; }
+
+// ---------------------------------------------------------------------------
+// command28_32 - isMusicChannelsActive guard, deferred callback, load ch0-5,8
+// (shared handler for commands 28 and 32)
+// ---------------------------------------------------------------------------
+void ASoundDemo9::loadCommand28() {
+	ASound::command1();
+	resetCallbackTimerEx(0x62, 0x54);
+	_channels[0]->load(loadData(0x1938));
+	_channels[1]->load(loadData(0x1972));
+	_channels[2]->load(loadData(0x1A2C));
+	_channels[3]->load(loadData(0x1A64));
+	_channels[4]->load(loadData(0x1B9E));
+	_channels[5]->load(loadData(0x1D5C));
+	_channels[8]->load(loadData(0x1C90));
+}
+
+int ASoundDemo9::command28_32() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo9, loadCommand28));
+	else
+		loadCommand28();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command29_33 - isMusicChannelsActive guard, deferred callback, load ch0-8
+// (shared handler for commands 29 and 33; non-sequential channel order)
+// ---------------------------------------------------------------------------
+void ASoundDemo9::loadCommand29() {
+	ASound::command1();
+	resetCallbackTimerEx(0x62, 0x54);
+	_channels[0]->load(loadData(0x2B10));
+	_channels[1]->load(loadData(0x2B7F));
+	_channels[2]->load(loadData(0x2BC5));
+	_channels[4]->load(loadData(0x2D3F));
+	_channels[5]->load(loadData(0x2D9F));
+	_channels[6]->load(loadData(0x2F0A));
+	_channels[3]->load(loadData(0x2FF3));
+	_channels[7]->load(loadData(0x3000));
+	_channels[8]->load(loadData(0x2C83));
+}
+
+int ASoundDemo9::command29_33() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo9, loadCommand29));
+	else
+		loadCommand29();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command34 - isMusicChannelsActive guard, deferred callback, load ch0-2,8,4-6
+// ---------------------------------------------------------------------------
+void ASoundDemo9::loadCommand34() {
+	ASound::command1();
+	resetCallbackTimer(0x38);
+	_channels[0]->load(loadData(0x300E));
+	_channels[1]->load(loadData(0x3204));
+	_channels[2]->load(loadData(0x3409));
+	_channels[8]->load(loadData(0x360A));
+	_channels[4]->load(loadData(0x3789));
+	_channels[5]->load(loadData(0x388C));
+	_channels[6]->load(loadData(0x38D7));
+}
+
+int ASoundDemo9::command34() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo9, loadCommand34));
+	else
+		loadCommand34();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command35 - isMusicChannelsActive guard, deferred callback, load ch0-3,8,5-6
+// ---------------------------------------------------------------------------
+void ASoundDemo9::loadCommand35() {
+	ASound::command1();
+	resetCallbackTimer(0x50);
+	_channels[0]->load(loadData(0x3924));
+	_channels[1]->load(loadData(0x396F));
+	_channels[2]->load(loadData(0x39B6));
+	_channels[3]->load(loadData(0x3A7A));
+	_channels[8]->load(loadData(0x3AEA));
+	_channels[5]->load(loadData(0x3C01));
+	_channels[6]->load(loadData(0x3C97));
+}
+
+int ASoundDemo9::command35() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo9, loadCommand35));
+	else
+		loadCommand35();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command36 - isMusicChannelsActive guard, deferred callback, load ch0-5,8
+// ---------------------------------------------------------------------------
+void ASoundDemo9::loadCommand36() {
+	ASound::command1();
+	resetCallbackTimer(0x28);
+	_channels[0]->load(loadData(0x3DFE));
+	_channels[1]->load(loadData(0x3E8F));
+	_channels[2]->load(loadData(0x3F0B));
+	_channels[3]->load(loadData(0x3F41));
+	_channels[4]->load(loadData(0x422F));
+	_channels[5]->load(loadData(0x42F1));
+	_channels[8]->load(loadData(0x4299));
+}
+
+int ASoundDemo9::command36() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo9, loadCommand36));
+	else
+		loadCommand36();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command37 - isMusicChannelsActive guard, deferred callback, load ch0-4,8,5
+// ---------------------------------------------------------------------------
+void ASoundDemo9::loadCommand37() {
+	ASound::command1();
+	resetCallbackTimer(0x50);
+	_channels[0]->load(loadData(0x4334));
+	_channels[1]->load(loadData(0x43C3));
+	_channels[2]->load(loadData(0x4453));
+	_channels[3]->load(loadData(0x449A));
+	_channels[4]->load(loadData(0x452E));
+	_channels[8]->load(loadData(0x453C));
+	_channels[5]->load(loadData(0x4618));
+}
+
+int ASoundDemo9::command37() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo9, loadCommand37));
+	else
+		loadCommand37();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command38 - isMusicChannelsActive guard, deferred callback, load ch0-4,8,6
+// (ch3 reuses the same data offset as command36's ch3)
+// ---------------------------------------------------------------------------
+void ASoundDemo9::loadCommand38() {
+	ASound::command1();
+	resetCallbackTimer(0x28);
+	_channels[0]->load(loadData(0x476C));
+	_channels[1]->load(loadData(0x47F9));
+	_channels[2]->load(loadData(0x4879));
+	_channels[3]->load(loadData(0x3F41));
+	_channels[4]->load(loadData(0x48AF));
+	_channels[8]->load(loadData(0x4911));
+	_channels[6]->load(loadData(0x495D));
+}
+
+int ASoundDemo9::command38() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo9, loadCommand38));
+	else
+		loadCommand38();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command39 - isMusicChannelsActive guard, deferred callback, load ch0-5,8
+// ---------------------------------------------------------------------------
+void ASoundDemo9::loadCommand39() {
+	ASound::command1();
+	resetCallbackTimer(0x28);
+	_channels[0]->load(loadData(0x499A));
+	_channels[1]->load(loadData(0x4A2F));
+	_channels[2]->load(loadData(0x4AC3));
+	_channels[3]->load(loadData(0x4BBF));
+	_channels[4]->load(loadData(0x5059));
+	_channels[5]->load(loadData(0x511B));
+	_channels[8]->load(loadData(0x50F1));
+}
+
+int ASoundDemo9::command39() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo9, loadCommand39));
+	else
+		loadCommand39();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command40 - isMusicChannelsActive guard, deferred callback, load ch0-2,8,4-6
+// (ch0-2 reuse the same data offsets as command34's ch0-2)
+// ---------------------------------------------------------------------------
+void ASoundDemo9::loadCommand40() {
+	ASound::command1();
+	resetCallbackTimer(0x38);
+	_channels[0]->load(loadData(0x300E));
+	_channels[1]->load(loadData(0x3204));
+	_channels[2]->load(loadData(0x3409));
+	_channels[8]->load(loadData(0x521A));
+	_channels[4]->load(loadData(0x5327));
+	_channels[5]->load(loadData(0x53DF));
+	_channels[6]->load(loadData(0x5439));
+}
+
+int ASoundDemo9::command40() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo9, loadCommand40));
+	else
+		loadCommand40();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command41 - isMusicChannelsActive guard, deferred callback, load ch0-2,8,4-6
+// ---------------------------------------------------------------------------
+void ASoundDemo9::loadCommand41() {
+	ASound::command1();
+	resetCallbackTimer(0x54);
+	_channels[0]->load(loadData(0x1D6A));
+	_channels[1]->load(loadData(0x1E74));
+	_channels[2]->load(loadData(0x22ED));
+	_channels[8]->load(loadData(0x2465));
+	_channels[4]->load(loadData(0x25C2));
+	_channels[5]->load(loadData(0x26A2));
+	_channels[6]->load(loadData(0x292C));
+}
+
+int ASoundDemo9::command41() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo9, loadCommand41));
+	else
+		loadCommand41();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command42 - isMusicChannelsActive guard, deferred callback, load ch0-3,8,4-6
+// ---------------------------------------------------------------------------
+void ASoundDemo9::loadCommand42() {
+	ASound::command1();
+	resetCallbackTimerEx(0xA8, 0x50);
+	_channels[0]->load(loadData(0x1DBC));
+	_channels[1]->load(loadData(0x1EBF));
+	_channels[2]->load(loadData(0x2366));
+	_channels[3]->load(loadData(0x1E1E));
+	_channels[8]->load(loadData(0x250E));
+	_channels[4]->load(loadData(0x25F9));
+	_channels[5]->load(loadData(0x2785));
+	_channels[6]->load(loadData(0x29C9));
+}
+
+int ASoundDemo9::command42() {
+	if (isMusicChannelsActive())
+		scheduleCallback(MAKE_CALLBACK(ASoundDemo9, loadCommand42));
+	else
+		loadCommand42();
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command44 - cancels any pending deferred callback (no loads, no fade)
+// ---------------------------------------------------------------------------
+int ASoundDemo9::command44() {
+	scheduleCallback(nullptr);
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command43 - no isMusicChannelsActive guard; always loads immediately.
+// load ch0-7 (no ch8)
+// ---------------------------------------------------------------------------
+int ASoundDemo9::command43() {
+	ASound::command1();
+	resetCallbackTimer(0x60);
+	_channels[0]->load(loadData(0x55EE));
+	_channels[1]->load(loadData(0x564D));
+	_channels[2]->load(loadData(0x5699));
+	_channels[3]->load(loadData(0x596B));
+	_channels[4]->load(loadData(0x5981));
+	_channels[5]->load(loadData(0x598E));
+	_channels[6]->load(loadData(0x599B));
+	_channels[7]->load(loadData(0x59A6));
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 45-46 - sound effects via findFreeChannel (lower pool)
+// ---------------------------------------------------------------------------
+int ASoundDemo9::command45() {
+	findFreeChannel(loadData(0x5498));
+	findFreeChannel(loadData(0x54F8));
+	return 0;
+}
+
+int ASoundDemo9::command46() {
+	findFreeChannel(loadData(0x5543));
+	findFreeChannel(loadData(0x5598));
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// command47 - no guard, no callback reset; load ch0-8 (all 9 channels)
+// ---------------------------------------------------------------------------
+int ASoundDemo9::command47() {
+	ASound::command1();
+	_channels[0]->load(loadData(0x59B4));
+	_channels[1]->load(loadData(0x5A3B));
+	_channels[2]->load(loadData(0x5A87));
+	_channels[3]->load(loadData(0x5BAE));
+	_channels[4]->load(loadData(0x5C95));
+	_channels[5]->load(loadData(0x5D57));
+	_channels[6]->load(loadData(0x5E69));
+	_channels[7]->load(loadData(0x5E76));
+	_channels[8]->load(loadData(0x5DB5));
+	return 0;
+}
+
+// ---------------------------------------------------------------------------
+// commands 48-50 - sound effects via findFreeChannel (lower pool)
+// ---------------------------------------------------------------------------
+int ASoundDemo9::command48() { findFreeChannel(loadData(0x5E84)); return 0; }
+int ASoundDemo9::command49() { findFreeChannel(loadData(0x5E8E)); return 0; }
+int ASoundDemo9::command50() { findFreeChannel(loadData(0x5E98)); return 0; }
+
 } // namespace Dragonsphere
 } // namespace MADSV2
 } // namespace MADS
diff --git a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h
index 0d2bcc0ad2e..60e0186dca3 100644
--- a/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h
+++ b/engines/mads/madsv2/dragonsphere/sound_dragonsphere.h
@@ -29,11 +29,15 @@ namespace MADSV2 {
 namespace Dragonsphere {
 
 class DragonSoundManager : public SoundManager {
+private:
+	bool _isDemo;
+
 protected:
 	void loadDriver(int sectionNum) override;
 
 public:
-	DragonSoundManager(Audio::Mixer *mixer, bool &soundFlag) : SoundManager(mixer, soundFlag) {
+	DragonSoundManager(Audio::Mixer *mixer, bool &soundFlag, bool isDemo) :
+		SoundManager(mixer, soundFlag), _isDemo(isDemo) {
 	}
 	~DragonSoundManager() override {
 	}
@@ -465,6 +469,57 @@ public:
 	int command(int commandId, int param) override;
 };
 
+/**
+ * ASoundDemo1  (asound.dr1 [demo], _dataOffset = 0x23e0, _dataSize = 0x4900)
+ *
+ * Dispatch table layout (four tables collapsed to flat [93]):
+ *   commands0:  commands  0– 8  (base=0,    max=8)
+ *   commands16: command   16    (base=0x10, max=0x10, 1 entry)
+ *   commands24: commands 24–43  (base=0x18, max=0x2B; slots 28,29,44 = no-op)
+ *   commands64: commands 64–92  (base=0x40, max=0x5C; slots 64–89 = no-op)
+ */
+class ASoundDemo1 : public ASound {
+private:
+	typedef int (ASoundDemo1::*CommandPtr)();
+	static const CommandPtr _commandList[93];
+
+	void loadCommand16();
+	void loadCommand30();
+	void loadCommand31();
+	void loadCommand32();
+	void loadCommand33();
+	void loadCommand34();
+	void loadCommand35();
+	void loadCommand36();
+	void loadCommand37();
+	void loadCommand38();
+	void loadCommand39();
+	void loadCommand40();
+	void loadCommand41();
+	void loadCommand42();
+	void loadCommand43();
+	void loadCommand92();
+
+	int command0(); int command1(); int command2(); int command3();
+	int command4(); int command5(); int command6(); int command7();
+	int command8();
+
+	int command16();
+
+	int command24(); int command25(); int command26(); int command27();
+	int command30(); int command31(); int command32(); int command33();
+	int command34(); int command35(); int command36(); int command37();
+	int command38(); int command39(); int command40(); int command41();
+	int command42(); int command43();
+
+	int command90(); int command91(); int command92();
+
+public:
+	ASoundDemo1(Audio::Mixer *mixer, OPL::OPL *opl);
+	~ASoundDemo1() override {}
+	int command(int commandId, int param) override;
+};
+
 class ASound9 : public ASound {
 private:
 	typedef int (ASound9:: *CommandPtr)();
@@ -514,6 +569,60 @@ public:
 	int command(int commandId, int param) override;
 };
 
+/**
+ * ASoundDemo9  (asound.dr9 [demo], _dataOffset = 0x23a0, _dataSize = 0x62b0)
+ *
+ * Dispatch table layout (flat [51]):
+ *   commands0:     commands  0– 8  (base=0,    max=8)
+ *   commands16_24: command   16    (base=0x10, max=0x10, 1 entry; also
+ *                  reused directly for command 24 - shared handler)
+ *   commands24:    commands 25–29, 34–50 (base=0x18/0x22; slots 30,31 = no-op)
+ *     - command28_32 is shared between commands 28 and 32
+ *     - command29_33 is shared between commands 29 and 33
+ *     (commands 32/33 are redirected to 28/29 by index-correction code
+ *     outside the array, not via separate array slots)
+ *   commands 64+ are unreachable (dispatcher upper bound is 0 for that range)
+ */
+class ASoundDemo9 : public ASound {
+private:
+	typedef int (ASoundDemo9::*CommandPtr)();
+	static const CommandPtr _commandList[51];
+
+	// Deferred loader callbacks (void, Pattern B)
+	void loadCommand28();
+	void loadCommand29();
+	void loadCommand34();
+	void loadCommand35();
+	void loadCommand36();
+	void loadCommand37();
+	void loadCommand38();
+	void loadCommand39();
+	void loadCommand40();
+	void loadCommand41();
+	void loadCommand42();
+
+	int command0(); int command1(); int command2(); int command3();
+	int command4(); int command5(); int command6(); int command7();
+	int command8();
+
+	int command16();
+
+	int command25(); int command26(); int command27();
+	int command28_32();
+	int command29_33();
+
+	int command34(); int command35(); int command36(); int command37();
+	int command38(); int command39(); int command40(); int command41();
+	int command42(); int command43(); int command44(); int command45();
+	int command46(); int command47(); int command48(); int command49();
+	int command50();
+
+public:
+	ASoundDemo9(Audio::Mixer *mixer, OPL::OPL *opl);
+	~ASoundDemo9() override {}
+	int command(int commandId, int param) override;
+};
+
 } // namespace Dragonsphere
 } // namespace MADSV2
 } // namespace MADS




More information about the Scummvm-git-logs mailing list