[Scummvm-git-logs] scummvm master -> 1ce640b1a11d5187cb4c780a4ee1e3e49a5f6bd3
dreammaster
noreply at scummvm.org
Sun Jun 21 02:42:02 UTC 2026
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
4bd44c641c MADS: FOREST: global_digi_play is actual global_midi_play
76905fd6af MADS: FOREST: Move digi/midi files into Forest namespace
1ce640b1a1 MADS: FOREST: Skeleton MidiPlayer class
Commit: 4bd44c641c8a672f55947e3dd8d4d9bd10b96032
https://github.com/scummvm/scummvm/commit/4bd44c641c8a672f55947e3dd8d4d9bd10b96032
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-06-21T12:41:49+10:00
Commit Message:
MADS: FOREST: global_digi_play is actual global_midi_play
Changed paths:
engines/mads/madsv2/forest/global.cpp
engines/mads/madsv2/forest/global.h
engines/mads/madsv2/forest/rooms/room101.cpp
engines/mads/madsv2/forest/rooms/room103.cpp
engines/mads/madsv2/forest/rooms/room104.cpp
engines/mads/madsv2/forest/rooms/room106.cpp
engines/mads/madsv2/forest/rooms/room107.cpp
engines/mads/madsv2/forest/rooms/room199.cpp
engines/mads/madsv2/forest/rooms/room201.cpp
engines/mads/madsv2/forest/rooms/room203.cpp
engines/mads/madsv2/forest/rooms/room205.cpp
engines/mads/madsv2/forest/rooms/room220.cpp
engines/mads/madsv2/forest/rooms/room304.cpp
engines/mads/madsv2/forest/rooms/room305.cpp
engines/mads/madsv2/forest/rooms/room308.cpp
engines/mads/madsv2/forest/rooms/room321.cpp
engines/mads/madsv2/forest/rooms/room322.cpp
engines/mads/madsv2/forest/rooms/room402.cpp
engines/mads/madsv2/forest/rooms/room403.cpp
engines/mads/madsv2/forest/rooms/room420.cpp
engines/mads/madsv2/forest/rooms/room501.cpp
engines/mads/madsv2/forest/rooms/room503.cpp
engines/mads/madsv2/forest/rooms/room509.cpp
engines/mads/madsv2/forest/rooms/room510.cpp
engines/mads/madsv2/forest/rooms/room520.cpp
engines/mads/madsv2/forest/rooms/room903.cpp
engines/mads/madsv2/forest/rooms/room904.cpp
diff --git a/engines/mads/madsv2/forest/global.cpp b/engines/mads/madsv2/forest/global.cpp
index 5b6de4b6fe6..3615775203e 100644
--- a/engines/mads/madsv2/forest/global.cpp
+++ b/engines/mads/madsv2/forest/global.cpp
@@ -985,9 +985,16 @@ void global_error_code() {
text_show(text_id);
}
-void global_digi_play(int num) {
- // TODO
- warning("TODO: global_digi_play");
+void global_midi_play(int num) {
+ static const char *NAMES[14] = {
+ "adven2", "foolarnd", "homeag", "humorus1", "humorus2", "pianogtr", "raindrop",
+ "xad", "xcarey", "xuspens1", "travels1", "birdsong", "adventur", "action1"
+ };
+
+ assert(num >= 1 && num <= 14);
+ Common::String name = Common::String::format("*%s.hmi", NAMES[num - 1]);
+
+ midi_play(name.c_str());
}
void global_daemon_code() {
diff --git a/engines/mads/madsv2/forest/global.h b/engines/mads/madsv2/forest/global.h
index 0c47ac2b5b2..5c847f1e4df 100644
--- a/engines/mads/madsv2/forest/global.h
+++ b/engines/mads/madsv2/forest/global.h
@@ -268,7 +268,7 @@ extern void global_error_code();
extern void global_anim1(int arg_0, int arg_2, int arg_4, int16 *arg_6);
extern void global_anim2(int arg_0, int arg_2, int arg_4, int16 *arg_6);
extern void global_anim3(int handle, int16 *frame);
-extern void global_digi_play(int num);
+extern void global_midi_play(int num);
extern void global_daemon_code();
} // namespace Forest
diff --git a/engines/mads/madsv2/forest/rooms/room101.cpp b/engines/mads/madsv2/forest/rooms/room101.cpp
index 45a43b03e8a..8e60e2a8050 100644
--- a/engines/mads/madsv2/forest/rooms/room101.cpp
+++ b/engines/mads/madsv2/forest/rooms/room101.cpp
@@ -116,7 +116,7 @@ static void room_101_init2() {
kernel_position_anim(scratch._a4, 194, 145, 75, 4);
global[g009] = -1;
- global_digi_play(8);
+ global_midi_play(8);
if (previous_room != KERNEL_RESTORING_GAME) {
player.x = 96;
@@ -557,7 +557,7 @@ static void room_101_anim10() {
scratch._b4 = 35;
} else if (frame < 35) {
if (frame == 5)
- global_digi_play(11);
+ global_midi_play(11);
else if (frame == 30) {
digi_play_build(101, '_', 3, 1);
scratch._b4 = 30;
diff --git a/engines/mads/madsv2/forest/rooms/room103.cpp b/engines/mads/madsv2/forest/rooms/room103.cpp
index 89426005151..f4f4b3a16ff 100644
--- a/engines/mads/madsv2/forest/rooms/room103.cpp
+++ b/engines/mads/madsv2/forest/rooms/room103.cpp
@@ -333,7 +333,7 @@ static void room_103_anim4() {
} else if (frame < 50) {
switch (frame) {
case 16:
- global_digi_play(8);
+ global_midi_play(8);
aainfo[3]._val3 = 15;
digi_play_build(103, 'c', 1, 1);
scratch._90 = 16;
diff --git a/engines/mads/madsv2/forest/rooms/room104.cpp b/engines/mads/madsv2/forest/rooms/room104.cpp
index 7191b997870..71c10cb5336 100644
--- a/engines/mads/madsv2/forest/rooms/room104.cpp
+++ b/engines/mads/madsv2/forest/rooms/room104.cpp
@@ -151,7 +151,7 @@ static void room_104_init() {
static void room_104_init1() {
global[player_score] = 0;
global[g009] = -1;
- global_digi_play(8);
+ global_midi_play(8);
viewing_at_y = 22;
player.walker_visible = 0;
player.commands_allowed = 0;
@@ -186,7 +186,7 @@ static void room_104_init2() {
static void room_104_init3() {
global[g009] = -1;
- global_digi_play(8);
+ global_midi_play(8);
global[g131] = 0;
global[g141] = 0;
@@ -593,7 +593,7 @@ static void room_104_anim3() {
aainfo[8]._val3 = 8;
digi_play_build(104, 'e', 3, 1);
scratch._a2 = 84;
- global_digi_play(14);
+ global_midi_play(14);
break;
case 89:
if (aainfo[8]._val3 == 8) {
diff --git a/engines/mads/madsv2/forest/rooms/room106.cpp b/engines/mads/madsv2/forest/rooms/room106.cpp
index e54b918ce02..398d276c017 100644
--- a/engines/mads/madsv2/forest/rooms/room106.cpp
+++ b/engines/mads/madsv2/forest/rooms/room106.cpp
@@ -363,7 +363,7 @@ static void room_106_anim4() {
return;
case 105:
global[g009] = 0;
- global_digi_play(4);
+ global_midi_play(4);
global[g154] = 0;
aainfo[7]._val3 = 13;
aainfo[7]._frame = 20;
diff --git a/engines/mads/madsv2/forest/rooms/room107.cpp b/engines/mads/madsv2/forest/rooms/room107.cpp
index ebf9365e9e6..f762365faeb 100644
--- a/engines/mads/madsv2/forest/rooms/room107.cpp
+++ b/engines/mads/madsv2/forest/rooms/room107.cpp
@@ -120,7 +120,7 @@ static void room_107_anim1() {
if (scratch._8e == 21) {
aainfo[0]._val3 = 2;
scratch._8e = -1;
- global_digi_play(4);
+ global_midi_play(4);
aainfo[0]._frame = 26;
kernel_reset_animation(aa[0], 26);
}
diff --git a/engines/mads/madsv2/forest/rooms/room199.cpp b/engines/mads/madsv2/forest/rooms/room199.cpp
index e84be3e44d7..87cbfd4a322 100644
--- a/engines/mads/madsv2/forest/rooms/room199.cpp
+++ b/engines/mads/madsv2/forest/rooms/room199.cpp
@@ -102,7 +102,7 @@ static void room_199_init1() {
static void room_199_init() {
global[player_score] = 0;
global[g009] = -1;
- global_digi_play(7);
+ global_midi_play(7);
aainfo[2]._val3 = -1;
aainfo[2]._val4 = 0;
diff --git a/engines/mads/madsv2/forest/rooms/room201.cpp b/engines/mads/madsv2/forest/rooms/room201.cpp
index 31ab0cd044c..9684f3d598b 100644
--- a/engines/mads/madsv2/forest/rooms/room201.cpp
+++ b/engines/mads/madsv2/forest/rooms/room201.cpp
@@ -73,7 +73,7 @@ static Scratch scratch;
static void room_201_init1() {
global[player_score] = -1;
global[g009] = -1;
- global_digi_play(11);
+ global_midi_play(11);
global[g131] = 0;
global[g141] = 0;
diff --git a/engines/mads/madsv2/forest/rooms/room203.cpp b/engines/mads/madsv2/forest/rooms/room203.cpp
index 72638c88bd0..5088c5f7fd9 100644
--- a/engines/mads/madsv2/forest/rooms/room203.cpp
+++ b/engines/mads/madsv2/forest/rooms/room203.cpp
@@ -125,7 +125,7 @@ static void room_203_init1() {
aainfo[0]._active = -1;
scratch._9a = 11;
scratch._92 = 74;
- global_digi_play(11);
+ global_midi_play(11);
scratch._a6 = 5;
return;
}
@@ -143,7 +143,7 @@ static void room_203_init1() {
global[g143] = 0;
if (global[g046] == 0) {
- global_digi_play(15);
+ global_midi_play(15);
scratch._a6 = 2;
aa[4] = kernel_run_animation(kernel_name('w', 4), 105);
aainfo[4]._active = -1;
@@ -171,7 +171,7 @@ static void room_203_init1() {
kernel_flip_hotspot(119, global[g047] == 0 ? 1 : 0);
kernel_flip_hotspot(27, global[g047]);
} else {
- global_digi_play(11);
+ global_midi_play(11);
scratch._a6 = 5;
}
}
@@ -256,7 +256,7 @@ static void room_203_anim1() {
} else if (frame < 50) {
if (frame == 22) {
if (local->_a6 != 1) {
- global_digi_play(10);
+ global_midi_play(10);
local->_a6 = 1;
}
aainfo[4]._frame = 3;
@@ -270,7 +270,7 @@ static void room_203_anim1() {
if (aainfo[0]._frame == 1) {
if (global[g046] == 0 && flags[8] > 1 && local->_a6 != 1) {
- global_digi_play(10);
+ global_midi_play(10);
local->_a6 = 1;
}
}
@@ -917,12 +917,12 @@ static void room_203_anim5() {
result = 27;
} else if (frame < 29) {
if (frame == 1) {
- global_digi_play(12);
+ global_midi_play(12);
local->_a6 = 4;
} else if (frame == 19) {
digi_play_build(103, '_', 3, 2);
if (local->_a6 != 2) {
- global_digi_play(15);
+ global_midi_play(15);
local->_a6 = 2;
}
} else if (frame == 22) {
@@ -957,7 +957,7 @@ static void room_203_anim5() {
local->_a6 = 0;
} else if (frame < 25) {
if (frame == 1) {
- global_digi_play(5);
+ global_midi_play(5);
local->_a6 = 3;
} else if (frame == 18) {
if (!local->_ac && local->_98 == 33) {
@@ -1297,7 +1297,7 @@ static void room_203_daemon() {
player.commands_allowed = true;
} else {
if (local->_a6 != 1) {
- global_digi_play(10);
+ global_midi_play(10);
local->_a6 = 1;
}
diff --git a/engines/mads/madsv2/forest/rooms/room205.cpp b/engines/mads/madsv2/forest/rooms/room205.cpp
index a6f427c53f2..384865a30d3 100644
--- a/engines/mads/madsv2/forest/rooms/room205.cpp
+++ b/engines/mads/madsv2/forest/rooms/room205.cpp
@@ -253,7 +253,7 @@ static void room_205_anim5() {
if (aainfo[6]._frame == 135) {
global[g009] = 0;
- global_digi_play(9);
+ global_midi_play(9);
kernel_timing_trigger(180, 105);
} else if (aainfo[6]._frame == 138) {
aainfo[6]._frame = 137;
diff --git a/engines/mads/madsv2/forest/rooms/room220.cpp b/engines/mads/madsv2/forest/rooms/room220.cpp
index 4973007164b..465632497d6 100644
--- a/engines/mads/madsv2/forest/rooms/room220.cpp
+++ b/engines/mads/madsv2/forest/rooms/room220.cpp
@@ -63,7 +63,7 @@ static Scratch scratch;
static void room_220_init() {
global[player_score] = -1;
global[g009] = -1;
- global_digi_play(10);
+ global_midi_play(10);
viewing_at_y = 22;
player.walker_visible = 0;
player.commands_allowed = 0;
@@ -90,7 +90,7 @@ static void room_220_anim1() {
kernel_abort_animation(aa[0]);
aainfo[0]._active = 0;
global[g009] = -1;
- global_digi_play(15);
+ global_midi_play(15);
aa[1] = kernel_run_animation("*RM220Y12", 0);
aainfo[1]._active = -1;
scratch._92 = 55;
diff --git a/engines/mads/madsv2/forest/rooms/room304.cpp b/engines/mads/madsv2/forest/rooms/room304.cpp
index 70235ac4f5e..ec8ee34447f 100644
--- a/engines/mads/madsv2/forest/rooms/room304.cpp
+++ b/engines/mads/madsv2/forest/rooms/room304.cpp
@@ -273,7 +273,7 @@ static void room_304_anim4() {
digi_play_build(304, '_', 3, 2);
scratch._a0 = 3;
global[g009] = 0;
- global_digi_play(14);
+ global_midi_play(14);
} else if (frame == 11) {
digi_stop(2);
}
diff --git a/engines/mads/madsv2/forest/rooms/room305.cpp b/engines/mads/madsv2/forest/rooms/room305.cpp
index 468ae49e6e6..ff0d670596e 100644
--- a/engines/mads/madsv2/forest/rooms/room305.cpp
+++ b/engines/mads/madsv2/forest/rooms/room305.cpp
@@ -89,7 +89,7 @@ static void room_305_init1() {
if (previous_room == 301) {
aa[1] = kernel_run_animation(kernel_name('t', 1), 104);
aainfo[1]._active = -1;
- global_digi_play(14);
+ global_midi_play(14);
return;
}
@@ -243,7 +243,7 @@ static void room_305_init() {
global[g009] = -1;
if (global[g066] == 1)
- global_digi_play(8);
+ global_midi_play(8);
}
static void room_305_anim1() {
@@ -484,7 +484,7 @@ static void room_305_anim6() {
kernel_timing_trigger(45, 105);
scratch._a4++;
global[g009] = -1;
- global_digi_play(6);
+ global_midi_play(6);
break;
case 15:
if (global[g065] != 0) {
diff --git a/engines/mads/madsv2/forest/rooms/room308.cpp b/engines/mads/madsv2/forest/rooms/room308.cpp
index ec247be676f..7ef97d10d99 100644
--- a/engines/mads/madsv2/forest/rooms/room308.cpp
+++ b/engines/mads/madsv2/forest/rooms/room308.cpp
@@ -108,7 +108,7 @@ static void room_308_anim1() {
break;
case 70:
global[g009] = 0;
- global_digi_play(9);
+ global_midi_play(9);
break;
case 88:
digi_initial_volume(60);
@@ -794,7 +794,7 @@ static void room_308_anim20() {
int16 result = -1;
if (cur == 6) {
global[g009] = 0;
- global_digi_play(5);
+ global_midi_play(5);
digi_play_build(308, 't', 5, 1);
scratch._94 = 3;
scratch._b4 = 3;
@@ -923,7 +923,7 @@ static void room_308_anim24() {
result = imath_random(20, 25);
} else if (cur == 29) {
global[g009] = 0;
- global_digi_play(5);
+ global_midi_play(5);
}
if (result >= 0) {
@@ -1055,7 +1055,7 @@ static void room_308_init() {
aainfo[1]._frame = -1;
kernel_synch(KERNEL_ANIM, ss[7], KERNEL_NOW, 0);
global[g009] = -1;
- global_digi_play(15);
+ global_midi_play(15);
player.commands_allowed = 0;
return;
}
@@ -1070,7 +1070,7 @@ static void room_308_init() {
aainfo[1]._val4 = -1;
kernel_synch(KERNEL_ANIM, ss[8], KERNEL_NOW, 0);
global[g009] = -1;
- global_digi_play(15);
+ global_midi_play(15);
return;
}
if (player_has(15)) {
@@ -1083,7 +1083,7 @@ static void room_308_init() {
aainfo[1]._val4 = -1;
kernel_synch(KERNEL_ANIM, ss[8], KERNEL_NOW, 0);
global[g009] = -1;
- global_digi_play(15);
+ global_midi_play(15);
return;
}
@@ -1114,7 +1114,7 @@ static void room_308_init() {
if (global[g073] == 0) {
global[g009] = -1;
- global_digi_play(15);
+ global_midi_play(15);
return;
}
@@ -1125,7 +1125,7 @@ static void room_308_init() {
aainfo[8]._frame = 0;
scratch._c2 = 100;
global[g009] = -1;
- global_digi_play(15);
+ global_midi_play(15);
}
static void room_308_daemon() {
@@ -1176,7 +1176,7 @@ static void room_308_daemon() {
aainfo[0]._val4 = -1;
kernel_synch(KERNEL_ANIM, ss[6], KERNEL_NOW, 0);
global[g009] = -1;
- global_digi_play(15);
+ global_midi_play(15);
break;
case 102:
diff --git a/engines/mads/madsv2/forest/rooms/room321.cpp b/engines/mads/madsv2/forest/rooms/room321.cpp
index bbf9024206f..fc47eafab3e 100644
--- a/engines/mads/madsv2/forest/rooms/room321.cpp
+++ b/engines/mads/madsv2/forest/rooms/room321.cpp
@@ -155,9 +155,9 @@ static void room_321_init() {
kernel_seq_loc(seq[4], 230, 105);
kernel_seq_scale(seq[4], 83);
kernel_flip_hotspot(177, 0);
- global_digi_play(13);
+ global_midi_play(13);
} else {
- global_digi_play(3);
+ global_midi_play(3);
}
global[g009] = -1;
diff --git a/engines/mads/madsv2/forest/rooms/room322.cpp b/engines/mads/madsv2/forest/rooms/room322.cpp
index 6fbecfcff86..c510d1402e7 100644
--- a/engines/mads/madsv2/forest/rooms/room322.cpp
+++ b/engines/mads/madsv2/forest/rooms/room322.cpp
@@ -339,7 +339,7 @@ static void room_322_anim8() {
digi_play_build(322, '_', 1, 2);
} else if (cur == 27) {
global[g009] = 0;
- global_digi_play(4);
+ global_midi_play(4);
}
if (result >= 0) {
diff --git a/engines/mads/madsv2/forest/rooms/room402.cpp b/engines/mads/madsv2/forest/rooms/room402.cpp
index cbee1bfb2c0..f1387102cf6 100644
--- a/engines/mads/madsv2/forest/rooms/room402.cpp
+++ b/engines/mads/madsv2/forest/rooms/room402.cpp
@@ -168,7 +168,7 @@ static void room_402_init1() {
}
global[player_score] = 0;
- global_digi_play(15);
+ global_midi_play(15);
}
static void room_402_init() {
@@ -356,7 +356,7 @@ static void room_402_anim_state() {
kernel_flip_hotspot(187, 0);
break;
case 17:
- global_digi_play(5);
+ global_midi_play(5);
global[g009] = 0;
aa[1] = kernel_run_animation(kernel_name('L', 13), 103);
aainfo[1]._active = -1;
@@ -584,7 +584,7 @@ static void room_402_anim2() {
case 20: {
int16 frame = aainfo[1]._frame;
if (frame == 2) {
- global_digi_play(15);
+ global_midi_play(15);
player.commands_allowed = -1;
global[g083] = 0;
room_402_anim6();
@@ -612,7 +612,7 @@ static void room_402_anim2() {
case 2: {
int16 frame = aainfo[1]._frame;
if (frame == 57) {
- global_digi_play(10);
+ global_midi_play(10);
global[player_score] = 0;
} else if (frame < 57) {
if (frame == 37) {
diff --git a/engines/mads/madsv2/forest/rooms/room403.cpp b/engines/mads/madsv2/forest/rooms/room403.cpp
index d777d24502b..d35ee2533fa 100644
--- a/engines/mads/madsv2/forest/rooms/room403.cpp
+++ b/engines/mads/madsv2/forest/rooms/room403.cpp
@@ -438,7 +438,7 @@ static void room_403_anim6() {
aainfo[5]._frame = 12;
kernel_reset_animation(aa[5], 12);
scratch._a4 = -1;
- global_digi_play(14);
+ global_midi_play(14);
kernel_seq_delete(seq[1]);
global[g080] = -1;
} else if (a4 == 89) {
diff --git a/engines/mads/madsv2/forest/rooms/room420.cpp b/engines/mads/madsv2/forest/rooms/room420.cpp
index ed5f1ee07ca..b0a53052ea0 100644
--- a/engines/mads/madsv2/forest/rooms/room420.cpp
+++ b/engines/mads/madsv2/forest/rooms/room420.cpp
@@ -113,7 +113,7 @@ static void room_420_anim2() {
scratch._8e = 34;
scratch.animation_info[1]._val3 = 10;
digi_play_build(420, 'b', 1, 1);
- global_digi_play(3);
+ global_midi_play(3);
} else if (cur == 39) {
if (scratch.animation_info[1]._val3 == 10) {
scratch.animation_info[1]._frame = 34;
diff --git a/engines/mads/madsv2/forest/rooms/room501.cpp b/engines/mads/madsv2/forest/rooms/room501.cpp
index e8ed6ca0d89..ed46140e7b8 100644
--- a/engines/mads/madsv2/forest/rooms/room501.cpp
+++ b/engines/mads/madsv2/forest/rooms/room501.cpp
@@ -356,7 +356,7 @@ static void room_501_anim5() {
digi_play_build(501, 'e', 1, 1);
scratch._a4 = 3;
} else if (scratch._a4 == 3) {
- global_digi_play(14);
+ global_midi_play(14);
global[g156] = 0;
aainfo[1]._val3 = 23;
aainfo[1]._frame = 105;
diff --git a/engines/mads/madsv2/forest/rooms/room503.cpp b/engines/mads/madsv2/forest/rooms/room503.cpp
index 26ed0aa44e7..35bd8fb3393 100644
--- a/engines/mads/madsv2/forest/rooms/room503.cpp
+++ b/engines/mads/madsv2/forest/rooms/room503.cpp
@@ -144,7 +144,7 @@ static void room_503_init1() {
if (previous_room == 199) {
if (global[g100] != 0) {
- global_digi_play(14);
+ global_midi_play(14);
viewing_at_y = 22;
scratch._ba = 2;
aainfo[0]._active = kernel_run_animation(kernel_name('N', 2), 106);
@@ -182,7 +182,7 @@ static void room_503_init1() {
scratch._b8 = 1;
}
- global_digi_play(6);
+ global_midi_play(6);
aa[0] = kernel_run_animation(kernel_name('y', 2), 100);
aainfo[0]._val3 = -1;
scratch._a6 = 52;
@@ -207,7 +207,7 @@ static void room_503_init3() {
if (previous_room == 199) {
if (global[g100] != 0) {
- global_digi_play(14);
+ global_midi_play(14);
viewing_at_y = 22;
scratch._ba = 2;
aainfo[0]._active = kernel_run_animation(kernel_name('N', 2), 106);
diff --git a/engines/mads/madsv2/forest/rooms/room509.cpp b/engines/mads/madsv2/forest/rooms/room509.cpp
index 480dbdc7665..10ff60818a0 100644
--- a/engines/mads/madsv2/forest/rooms/room509.cpp
+++ b/engines/mads/madsv2/forest/rooms/room509.cpp
@@ -63,7 +63,7 @@ static void room_509_init() {
mouse_hide();
global[player_score] = 0;
global[g009] = -1;
- global_digi_play(15);
+ global_midi_play(15);
global[g009] = -1;
viewing_at_y = 22;
global[player_score] = 0;
diff --git a/engines/mads/madsv2/forest/rooms/room510.cpp b/engines/mads/madsv2/forest/rooms/room510.cpp
index 5627f2ef5cc..213430b7c43 100644
--- a/engines/mads/madsv2/forest/rooms/room510.cpp
+++ b/engines/mads/madsv2/forest/rooms/room510.cpp
@@ -226,7 +226,7 @@ static void room_510_anim3() {
digi_play_build(510, '_', 1, 2);
scratch._90 = 1;
midi_stop();
- global_digi_play(4);
+ global_midi_play(4);
} else if (aa_frame == 40) {
midi_stop();
new_room = 107;
@@ -288,7 +288,7 @@ static void room_510_daemon() {
if (scratch._8e == 668) {
scratch._8e = -1;
global[g009] = 0;
- global_digi_play(14);
+ global_midi_play(14);
kernel_timing_trigger(2100, 104);
}
break;
@@ -314,7 +314,7 @@ static void room_510_daemon() {
break;
case 104:
global[g009] = -1;
- global_digi_play(11);
+ global_midi_play(11);
break;
case 106:
scratch._96 = -1;
diff --git a/engines/mads/madsv2/forest/rooms/room520.cpp b/engines/mads/madsv2/forest/rooms/room520.cpp
index 4c44a7458df..13d6596dcc9 100644
--- a/engines/mads/madsv2/forest/rooms/room520.cpp
+++ b/engines/mads/madsv2/forest/rooms/room520.cpp
@@ -130,7 +130,7 @@ static void room_520_daemon() {
scratch._8c = 66;
break;
case 101:
- global_digi_play(14);
+ global_midi_play(14);
break;
}
diff --git a/engines/mads/madsv2/forest/rooms/room903.cpp b/engines/mads/madsv2/forest/rooms/room903.cpp
index 6d17b2af68b..af19e94920a 100644
--- a/engines/mads/madsv2/forest/rooms/room903.cpp
+++ b/engines/mads/madsv2/forest/rooms/room903.cpp
@@ -53,7 +53,7 @@ static void room_903_init() {
static void room_903_daemon() {
if (kernel.trigger == TRIGGER1)
- global_digi_play(14);
+ global_midi_play(14);
if (mouse_any_stroke || g_engine->hasPendingKey() || kernel.trigger == TRIGGER0) {
g_engine->flushKeys();
diff --git a/engines/mads/madsv2/forest/rooms/room904.cpp b/engines/mads/madsv2/forest/rooms/room904.cpp
index 5a08adbba09..bfc535ce269 100644
--- a/engines/mads/madsv2/forest/rooms/room904.cpp
+++ b/engines/mads/madsv2/forest/rooms/room904.cpp
@@ -88,7 +88,7 @@ static void room_904_seen_intro() {
static void room_904_init() {
last_keypressed = -1;
- global_digi_play(3);
+ global_midi_play(3);
aainfo[1]._active = 0;
aainfo[1]._frame = 0;
global[g009] = -1;
Commit: 76905fd6afab17eaec7c88c6f7aba61cb9df1bce
https://github.com/scummvm/scummvm/commit/76905fd6afab17eaec7c88c6f7aba61cb9df1bce
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-06-21T12:41:50+10:00
Commit Message:
MADS: FOREST: Move digi/midi files into Forest namespace
It's the only game that uses them, so it's best to be clear.
Changed paths:
A engines/mads/madsv2/forest/digi.cpp
A engines/mads/madsv2/forest/digi.h
A engines/mads/madsv2/forest/midi.cpp
A engines/mads/madsv2/forest/midi.h
R engines/mads/madsv2/core/digi.cpp
R engines/mads/madsv2/core/digi.h
R engines/mads/madsv2/core/midi.cpp
R engines/mads/madsv2/core/midi.h
R engines/mads/madsv2/forest/asound.cpp
R engines/mads/madsv2/forest/asound.h
engines/mads/madsv2/forest/global.cpp
engines/mads/madsv2/forest/rooms/room101.cpp
engines/mads/madsv2/forest/rooms/room103.cpp
engines/mads/madsv2/forest/rooms/room104.cpp
engines/mads/madsv2/forest/rooms/room106.cpp
engines/mads/madsv2/forest/rooms/room107.cpp
engines/mads/madsv2/forest/rooms/room199.cpp
engines/mads/madsv2/forest/rooms/room201.cpp
engines/mads/madsv2/forest/rooms/room203.cpp
engines/mads/madsv2/forest/rooms/room204.cpp
engines/mads/madsv2/forest/rooms/room205.cpp
engines/mads/madsv2/forest/rooms/room210.cpp
engines/mads/madsv2/forest/rooms/room211.cpp
engines/mads/madsv2/forest/rooms/room220.cpp
engines/mads/madsv2/forest/rooms/room301.cpp
engines/mads/madsv2/forest/rooms/room302.cpp
engines/mads/madsv2/forest/rooms/room303.cpp
engines/mads/madsv2/forest/rooms/room304.cpp
engines/mads/madsv2/forest/rooms/room305.cpp
engines/mads/madsv2/forest/rooms/room306.cpp
engines/mads/madsv2/forest/rooms/room307.cpp
engines/mads/madsv2/forest/rooms/room308.cpp
engines/mads/madsv2/forest/rooms/room321.cpp
engines/mads/madsv2/forest/rooms/room322.cpp
engines/mads/madsv2/forest/rooms/room401.cpp
engines/mads/madsv2/forest/rooms/room402.cpp
engines/mads/madsv2/forest/rooms/room403.cpp
engines/mads/madsv2/forest/rooms/room404.cpp
engines/mads/madsv2/forest/rooms/room405.cpp
engines/mads/madsv2/forest/rooms/room420.cpp
engines/mads/madsv2/forest/rooms/room501.cpp
engines/mads/madsv2/forest/rooms/room503.cpp
engines/mads/madsv2/forest/rooms/room509.cpp
engines/mads/madsv2/forest/rooms/room510.cpp
engines/mads/madsv2/forest/rooms/room520.cpp
engines/mads/madsv2/forest/rooms/room904.cpp
engines/mads/module.mk
diff --git a/engines/mads/madsv2/forest/asound.cpp b/engines/mads/madsv2/forest/asound.cpp
deleted file mode 100644
index 70022f4fdb8..00000000000
--- a/engines/mads/madsv2/forest/asound.cpp
+++ /dev/null
@@ -1,1805 +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 3 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, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "audio/fmopl.h"
-#include "mads/madsv2/forest/asound.h"
-
-namespace MADS {
-namespace MADSV2 {
-namespace Forest {
-
-
-bool AdlibChannel::_isDisabled;
-
-/*
- * PATCH_ATTEN_TO_TL (seg001:0x0092 / offset from _asound_samples base)
- * patchAttenuation (0-127) -> 6-bit OPL total-level.
- * The Dragonsphere asm uses PATCH_ATTEN_TO_TL[bx] for the modulator lookup
- * and unk_12431 - bx (i.e. PATCH_ATTEN_TO_TL[127 - patchAtt]) for the
- * carrier lookup.
- */
-static const uint8 PATCH_ATTEN_TO_TL[128] = {
- 63, 54, 49, 45, 42, 40, 38, 36, 34, 33, 32, 31, 30, 29, 28, 27,
- 26, 25, 25, 24, 23, 23, 22, 22, 21, 21, 20, 20, 19, 19, 18, 18,
- 18, 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 14, 14, 13, 13, 13,
- 12, 12, 12, 12, 11, 11, 11, 11, 11, 10, 10, 10, 10, 9, 9, 9,
- 9, 9, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6,
- 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4,
- 4, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
-};
-
-/*
- * VOL_VEL_TO_ATTEN_STEP (_volVelToAttenStep)
- * volume or velocity byte (0-127) -> attenuation step (1-32).
- * Groups of 4 inputs map to the same step.
- */
-static const uint8 VOL_VEL_TO_ATTEN_STEP[128] = {
- 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
- 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
- 9, 9, 9, 9, 10,10,10,10, 11,11,11,11, 12,12,12,12,
- 13,13,13,13, 14,14,14,14, 15,15,15,15, 16,16,16,16,
- 17,17,17,17, 18,18,18,18, 19,19,19,19, 20,20,20,20,
- 21,21,21,21, 22,22,22,22, 23,23,23,23, 24,24,24,24,
- 25,25,25,25, 26,26,26,26, 27,27,27,27, 28,28,28,28,
- 29,29,29,29, 30,30,30,30, 31,31,31,31, 32,32,32,32
-};
-
-/*
- * SEMITONE_FREQ_TABLE (_semitoneFreqTable)
- * OPL F-number base for each semitone within an octave.
- */
-static const uint16 SEMITONE_FREQ_TABLE[12] = {
- 0x0200, 0x021E, 0x023F, 0x0261, 0x0285, 0x02AB,
- 0x02D4, 0x02FF, 0x032D, 0x035D, 0x0390, 0x03C7
-};
-
-/*
- * VOICE_SLOTS (byte_1239B in the binary, also used as the operator-reg
- * index table for command6/7)
- *
- * Layout for each voice: { slot0 (modulator), slot1 (carrier) }
- * The writeVolume loop uses:
- * pass 0 -> VOICE_SLOTS[ch][0] (modulator)
- * pass 1 -> VOICE_SLOTS[ch][1] (carrier)
- * The alg!=0 single-op path (loc_11692) goes directly to VOICE_SLOTS[ch][1].
- */
-static const uint8 VOICE_SLOTS[ADLIB_CHANNEL_COUNT][2] = {
- { 0, 3 }, { 1, 4 }, { 2, 5 },
- { 6, 9 }, { 7, 10 }, { 8, 11 },
- { 12, 15 }, { 13, 16 }, { 14, 17 }
-};
-
-/*
- * SLOT_TO_REG_OFFSET (_slotToRegOffset)
- * operator-slot index (0-17) -> OPL register group offset.
- */
-static const uint8 SLOT_TO_REG_OFFSET[18] = {
- 0, 1, 2, 3, 4, 5,
- 8, 9, 10, 11, 12, 13,
- 16, 17, 18, 19, 20, 21
-};
-
-/*
- * byte_1239B - all 22 operator TL register indices muted/restored by
- * command6 and command7. They cover every OPL operator slot (0x40-0x55).
- */
-static const uint8 ALL_OP_TL_REGS[22] = {
- 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
- 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
- 0x50, 0x51, 0x52, 0x53, 0x54, 0x55
-};
-
-/* Null / silence sound-data placeholder stream. */
-static uint8 ADLIB_NULLDATA[] = {
- 0x00, 0x01, 0xF3, 0x00, 0x00, 0xEF, 0x00, 0x00,
- 0xF5, 0x00, 0x00, 0x00, 0xF7, 0x00, 0xF8, 0x1D,
- 0xFF, 0x00, 0xF4, 0x6E, 0x2A, 0x1C, 0xF4, 0x5F,
- 0x2A, 0x1C, 0x2A, 0x1C, 0x2A, 0x1C, 0xFF, 0xFF,
- 0x00, 0x00, 0x00, 0x00
-};
-
-/* OPL version flag (_adlib_v5660 / opl_version_flag).
- * 0x18 = OPL3 (patch-attenuation-aware writeVolume path). */
-constexpr uint16 OPL_VERSION_FLAG = 0x18;
-
-/* Rhythm-mode flags (from data segment). */
-constexpr bool RHYTHM_HI_HAT = true;
-constexpr bool RHYTHM_CYMBAL = true;
-constexpr bool RHYTHM_ENABLE = true;
-
-AdlibSample::AdlibSample(Common::SeekableReadStream &s) {
- _attackRate = s.readByte();
- _decayRate = s.readByte();
- _sustainLevel = s.readByte();
- _releaseRate = s.readByte();
- _egTyp = s.readByte();
- _ksr = s.readByte();
- _totalLevel = s.readByte();
- _scalingLevel = s.readByte();
- _waveformSelect = s.readByte();
- _freqMultiple = s.readByte();
- _feedback = s.readByte();
- _ampMod = s.readByte();
- _vib = s.readByte();
- _alg = s.readByte();
- _freqSweepInit = s.readByte();
- _reserved = s.readByte();
- _freqMask = s.readUint16LE();
- _freqBase = s.readUint16LE();
- _outerLoopPtr = s.readUint16LE();
-}
-
-void AdlibChannel::reset() {
- /* Zero the scalar "live" fields only.
- *
- * From AdlibChannel_reset in the binary: clears _activeCount, _pitchBend,
- * _volumeFadeStep, _vibratoDepth, _arpCounterReload (field_13),
- * _writeVolumePending (field_11), _transpose, _patchAttenuation,
- * _pendingStop, _velocity, _volume, _freqSweepCounter, _noiseFreqMask,
- * _freqAccum, _freqStep, _loopStartPtr, _pSrc.
- * All other fields are left as-is (they are overwritten by load() or
- * by the bytecode stream before being read).
- */
- _activeCount = 0;
- _pitchBend = 0;
- _volumeFadeStep = 0;
- _vibratoDepth = 0;
- _arpCounterReload = 0; /* field_13 */
- _writeVolumePending = 0; /* field_11 */
- _transpose = 0;
- _patchAttenuation = 0;
- _pendingStop = 0;
- _velocity = 0;
- _volume = 0;
- _freqSweepCounter = 0;
- _noiseFreqMask = 0;
- _freqAccum = 0;
- _freqStep = 0;
- _loopStartPtr = nullptr;
- _pSrc = nullptr;
-}
-
-void AdlibChannel::load(byte *soundData) {
- _isDisabled = true;
-
- /* Zero all bytes in the struct. */
- memset(this, 0, sizeof(AdlibChannel));
-
- /* Initialise all loop/source pointers to the supplied data block. */
- _loopStartPtr = soundData;
- _pSrc = soundData;
- _innerLoopPtr = soundData;
- _outerLoopPtr = soundData;
- _soundData = soundData;
-
- /* Start at maximum attenuation (silent) and mark the channel active. */
- _patchAttenuation = 0x40;
- _activeCount = 1;
-
- _isDisabled = false;
-}
-
-void AdlibChannel::setPtr2(byte *ptr) {
- /* Hard-redirect both read pointers, then arm a one-step fade. */
- _loopStartPtr = ptr;
- _pSrc = ptr;
- _volumeFadeStep = 0xFF; /* -1 signed: fade down */
- _fadePeriodReload = 1;
- _fadePeriodCounter = 1;
-}
-
-void AdlibChannel::enable() {
- /* AdlibChannel_enable: mark pending-stop on active channels only. */
- if (_activeCount == 0)
- return;
- _pendingStop = 0xFF;
- _soundData = ADLIB_NULLDATA;
-}
-
-void AdlibChannel::processChannelFade() {
- if (_activeCount == 0)
- return;
- if (_pendingStop == 0)
- return;
-
- /* Channel has fully faded when both velocity and volume are zero. */
- if (_velocity == 0 && _volume == 0) {
- _loopStartPtr = ADLIB_NULLDATA;
- _pSrc = ADLIB_NULLDATA;
- _pendingStop = 0;
- return;
- }
-
- /* Arm a quick fade-down (period 2, step -1). */
- _volumeFadeStep = 0xFF;
- _fadePeriodReload = 2;
- if (_fadePeriodCounter == 0)
- _fadePeriodCounter = 1;
-}
-
-ASound::ASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::Path &filename,
- int dataOffset, int dataSize)
- : SoundDriver(mixer, opl, filename, dataOffset, dataSize) {
- AdlibChannel::_isDisabled = false;
-
- /* Standard OPL timer-reset sequence. */
- write(4, 0x60);
- write(4, 0x80);
- write(2, 0xFF);
- write(4, 0x21);
- write(4, 0x60);
- write(4, 0x80);
-
- Common::fill(_adlibPorts, _adlibPorts + 256, 0);
- command0();
-
- _opl->start(new Common::Functor0Mem<void, ASound>(this, &ASound::onTimer),
- CALLBACKS_PER_SECOND);
-}
-
-int ASound::stop() {
- command0();
- int result = _pollResult;
- _pollResult = 0;
- return result;
-}
-
-int ASound::poll() {
- update();
- int result = _pollResult;
- _pollResult = 0;
- return result;
-}
-
-void ASound::noise() {
- Common::StackLock slock(_driverMutex);
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
- noise_inner(i);
-}
-
-int ASound::command0() {
- /* Push _isDisabled, temporarily force to 0xFFFF while resetting. */
- uint16 savedDisabled = _isDisabled;
- _isDisabled = 0xFFFF;
-
- /* 1. Reset all 9 channels. */
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
- _channels[i]->reset();
-
- /* 2. Mute all operator TL registers (0x40 down to 0x4F, via adlib_write2
- * with value 0x3F, stepping from 0x4F down while reg >= 0x40). */
- for (int reg = 0x4F; reg >= 0x40; --reg)
- write((uint8)reg, 0x3F);
-
- /* 3. Zero registers 0xFF down to 0x60. */
- for (int reg = 0xFF; reg >= 0x60; --reg)
- write((uint8)reg, 0x00);
-
- /* 4. Zero registers 0x3F down to 0x01. */
- for (int reg = 0x3F; reg >= 0x01; --reg)
- write((uint8)reg, 0x00);
-
- /* 5. Waveform Select Enable. */
- write(0x01, 0x20);
-
- /* 6. Reset tick callback. */
- resetCallback();
-
- _isDisabled = savedDisabled;
- return 0;
-}
-
-int ASound::command1() {
- /* Fade all channels: music 0-6 (command3) then SFX 7-8 (command5). */
- command3();
- command5();
- return 0;
-}
-
-int ASound::command2() {
- /* Hard-redirect music channels 0-6 to null stream with setPtr2. */
- _channel0.setPtr2(ADLIB_NULLDATA);
- _channel1.setPtr2(ADLIB_NULLDATA);
- _channel2.setPtr2(ADLIB_NULLDATA);
- _channel3.setPtr2(ADLIB_NULLDATA);
- _channel4.setPtr2(ADLIB_NULLDATA);
- _channel5.setPtr2(ADLIB_NULLDATA);
- _channel6.setPtr2(ADLIB_NULLDATA);
- return 0;
-}
-
-int ASound::command3() {
- /* Pending-stop music channels 0-6 (natural envelope fade via enable). */
- _channel0.enable();
- _channel1.enable();
- _channel2.enable();
- _channel3.enable();
- _channel4.enable();
- _channel5.enable();
- _channel6.enable();
- return 0;
-}
-
-int ASound::command4() {
- /* Hard-redirect SFX channels 7-8. */
- _channel7.setPtr2(ADLIB_NULLDATA);
- _channel8.setPtr2(ADLIB_NULLDATA);
- return 0;
-}
-
-int ASound::command5() {
- /* Pending-stop SFX channels 7-8. */
- _channel7.enable();
- _channel8.enable();
- return 0;
-}
-
-int ASound::command6() {
- /* Guard: already disabled. */
- if (_isDisabled == 0xFFFF)
- return 0;
- _isDisabled = 0xFFFF;
-
- /* Save each channel's _freqSweepCounter -> _savedSweepCounter, then zero it. */
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i) {
- AdlibChannel *ch = _channels[i];
- ch->_savedSweepCounter = ch->_freqSweepCounter;
- ch->_freqSweepCounter = 0;
- }
-
- /* Mute all 22 operator TL registers. */
- for (int i = 0; i < 22; ++i)
- adlib_channelOff(ALL_OP_TL_REGS[i]);
-
- return 0;
-}
-
-int ASound::command7() {
- /* Guard: only resume from a paused state. */
- if (_isDisabled != 0xFFFF)
- return 0;
-
- /* Restore all operator volumes from the _adlibPorts shadow
- * (asound_playMusicC: just re-writes whatever was last written). */
- for (int i = 0; i < 22; ++i)
- adlib_channelOn(ALL_OP_TL_REGS[i]);
-
- /* Restore each channel's sweep counter and check whether any was non-zero. */
- uint8 anySweep = 0;
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i) {
- AdlibChannel *ch = _channels[i];
- ch->_freqSweepCounter = ch->_savedSweepCounter;
- anySweep |= ch->_savedSweepCounter;
- }
-
- if (anySweep != 0)
- signalSoundPlaying();
-
- _isDisabled = 0;
- return 0;
-}
-
-int ASound::command8() {
- /* Returns non-zero if any channel is currently active.
- * Clears byte_12393 (music-only flag) first so all 9 channels are checked. */
- _musicOnlyFlag = 0;
- uint8 result = 0;
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
- result |= _channels[i]->_activeCount;
- return result;
-}
-
-int ASound::command18() {
- /* Re-entrant background-music launcher (asound_command18 in the binary).
- * Fades everything, then dispatches back through the command table using
- * _musicIndex (word_12370) as the command ID. */
- command1();
- return command(_musicIndex, 0);
-}
-
-void ASound::callFunction(uint16 offset) {
- error("Unsupported call to sound driver function at offset %.4x", offset);
-}
-
-void ASound::write(uint8 reg, uint8 value) {
- _adlibPorts[reg] = value;
- _opl->writeReg(reg, value);
-}
-
-void ASound::onTimer() {
- Common::StackLock slock(_driverMutex);
- poll();
-}
-
-uint16 ASound::getRandomNumber() {
- /* asound_getRandomNumber: ax = ror3(0x9248 + seed). */
- uint16 ax = (uint16)(0x9248u + _randomSeed);
- ax = (uint16)((ax >> 3) | (ax << 13));
- _randomSeed = ax;
- return ax;
-}
-
-void ASound::adlib_channelOff(uint8 portIndex) {
- /* sub_1018F: OR the register with 0x3F (force max attenuation),
- * then write back both to _adlibPorts and to the OPL chip.
- * Note: unlike the Phantom driver, the original value is NOT preserved
- * in _adlibPorts - the ORed value is stored back. */
- uint8 val = _adlibPorts[portIndex] | 0x3F;
- _adlibPorts[portIndex] = val;
- _opl->writeReg(portIndex, val);
-}
-
-void ASound::adlib_channelOn(uint8 portIndex) {
- /* asound_playMusicC: re-writes whatever _adlibPorts already holds.
- * command7 simply replays the shadow without recalculating anything. */
- _opl->writeReg(portIndex, _adlibPorts[portIndex]);
-}
-
-void ASound::signalSoundPlaying() {
- /* asound_signalSoundPlaying: set resultFlag/pollResult to non-zero. */
- if (_resultFlag == (int16)0xFFFF)
- return;
- _resultFlag = (int16)0xFFFF;
- _pollResult = (int16)0xFFFF;
-}
-
-void ASound::clearCallback() {
- _callbackFnPtr = nullptr;
- _callbackCounter = 0;
- _callbackPeriod = 0;
-}
-
-void ASound::tickCallback() {
- if (_callbackPeriod == 0)
- return;
- if (--_callbackCounter != 0)
- return;
-
- _callbackCounter = _callbackPeriod;
- if (_callbackFnPtr == nullptr)
- return;
-
- auto fn = _callbackFnPtr;
- _callbackFnPtr = nullptr;
- (this->*fn)();
-}
-
-void ASound::writeVolume() {
- AdlibChannel *ch = _activeChannelPtr;
- uint8 chanNum = _activeChannelNumber;
-
- /* Compute combined attenuation step from volume and velocity. */
- uint8 volIdx = ch->_volume;
- uint8 velIdx = ch->_velocity;
- int16 volStep = (int16)(uint16)VOL_VEL_TO_ATTEN_STEP[volIdx];
- int16 velStep = (int16)(uint16)VOL_VEL_TO_ATTEN_STEP[velIdx];
- int16 var4 = volStep + velStep - 1; /* var_4: combined step (shared) */
-
- /* Check _alg of the first sample to determine loop count. */
- AdlibSample *smpFirst = &_samples[ch->_sampleIndex * 2];
- int passes = (smpFirst->_alg == 0) ? 2 : 1;
-
- /* si and di track the two TL values written per pass for caching. */
- int16 finalSi = 0, finalDi = 0;
-
- /* var_6 = loop counter (0, then 1 for the two-pass case).
- * For alg != 0 we jump straight into the carrier path (var_6 stays at
- * effectively 1: VOICE_SLOTS[ch][1]). */
- for (int var6 = (passes == 1 ? 1 : 0); var6 < 2; ++var6) {
-
- /* Reload var_2 = var_4 at the start of each pass (loc_11642). */
- int16 var2 = var4;
-
- /* Select the operator slot. */
- uint8 slot = VOICE_SLOTS[chanNum][var6];
- uint8 regOff = SLOT_TO_REG_OFFSET[slot];
- uint16 tlReg = (uint16)regOff + 0x40; /* var_8 */
-
- /* KSL bits from the port shadow. */
- int16 kslBits = (int16)((uint16)_adlibPorts[tlReg] & 0xC0); /* var_A */
-
- int16 si, di;
-
- if (OPL_VERSION_FLAG < 0x18) {
- /* ---- OPL2 simple path (loc_1167C / loc_1167C equivalent) ---- */
- int16 tl = (int16)0x3F - var2;
- tl |= kslBits;
- si = tl;
- di = tl;
- /* adlib_write2(8, tlReg, tl) */
- write((uint8)tlReg, (uint8)tl);
- } else {
- /* ---- OPL3 patch-attenuation path (loc_115BE / loc_116D4) ---- */
- uint8 pa = ch->_patchAttenuation;
-
- /* Modulator TL (first register, offset 0): */
- int16 tlMod = (int16)(uint16)PATCH_ATTEN_TO_TL[pa];
- /* -(tlMod - var2) = var2 - tlMod */
- int16 atten1 = var2 - tlMod; /* ax = si initially */
- si = atten1;
- if (si < 0) si = 0;
- else if (si > 63) si = 63;
- int16 reg0val = ((int16)0x3F - si) | kslBits;
- si = reg0val;
- write((uint8)tlReg, (uint8)reg0val);
-
- /* Carrier TL (second register, offset 2):
- * unk_12431 - bx (where bx = pa) == PATCH_ATTEN_TO_TL[127 - pa]. */
- int16 tlCar = (int16)(uint16)PATCH_ATTEN_TO_TL[127 - pa];
- /* di = var_2 - tlCar (var_4 for alg!=0, var_2=var_4 reload for alg==0) */
- di = var2 - tlCar;
- int16 diClamped = di;
- if (diClamped < 0) diClamped = 0;
- else if (diClamped > 0x3F) diClamped = 0x3F;
- int16 reg2val = ((int16)0x3F - diClamped) | kslBits;
- di = reg2val;
- write((uint8)(tlReg + 2), (uint8)reg2val);
- }
-
- /* For the alg!=0 single-pass case we only run this once (var6==1).
- * For the alg==0 two-pass case, record both sets. */
- if (var6 == 1) {
- finalSi = si;
- finalDi = di;
- } else {
- /* var6==0: record si/di for the mod pass; di is overwritten on
- * the carrier pass so we use si for the high byte of field_2A. */
- finalSi = si;
- finalDi = di;
- }
- }
-
- /* Cache the written TL bytes in field_2A:
- * dl = di & 0x3F (carrier / second register)
- * dh = si & 0x3F (modulator / first register)
- * Packed as a word at offset 0x2A. */
- ch->_cachedCarrierTL = (uint8)(finalDi & 0x3F); /* dl -> field_2A low byte */
- /* The high byte (si & 0x3F) is stored in _savedFreqSweep (offset 0x2B)
- * by the assembly. We write it separately to avoid clobbering the real
- * savedFreqSweep which lives there - the original asm stores both bytes
- * as a word at [bx+2Ah], meaning field_2A=dl and field_2B=dh=si&0x3F.
- * In our C++ layout _savedFreqSweep is at 0x2B; we shadow the dh byte
- * into it only when writing volume, consistent with the original. */
- ch->_savedFreqSweep = (uint8)(finalSi & 0x3F);
-}
-
-void ASound::writeFrequency() {
- AdlibChannel *ch = _activeChannelPtr;
- uint8 chanNum = _activeChannelNumber;
- uint16 aReg = (uint16)chanNum + 0xA0;
- uint16 bReg = (uint16)chanNum + 0xB0;
-
- /* Note is 1-based; _octaveTranspose shifts by whole octaves. */
- int note = (int)ch->_note + (int)ch->_octaveTranspose - 1;
- int octave = note / 12;
- int semi = note % 12;
- if (semi < 0) {
- semi += 12; --octave;
- }
-
- /* F-number from table, with optional signed transpose offset. */
- int16 fnum = (int16)SEMITONE_FREQ_TABLE[semi] + (int16)(int8)ch->_transpose;
-
- write((uint8)aReg, (uint8)fnum);
-
- uint8 bVal = _adlibPorts[bReg] & 0x20; /* preserve key-on bit */
- bVal |= (uint8)((fnum >> 8) & 0x03); /* F-num bits 9:8 */
- bVal |= (uint8)(((uint8)octave & 0x07) << 2); /* block/octave bits 4:2 */
- write((uint8)bReg, bVal);
-}
-
-void ASound::writePitchBend() {
- AdlibChannel *ch = _activeChannelPtr;
- uint8 chanNum = _activeChannelNumber;
- uint16 aReg = (uint16)chanNum + 0xA0;
- uint16 bReg = (uint16)chanNum + 0xB0;
-
- /* Reconstruct the 10-bit F-number from the port shadow. */
- uint16 fnum = (uint16)_adlibPorts[aReg]
- | ((uint16)(_adlibPorts[bReg] & 0x1F) << 8);
-
- int16 bent = (int16)fnum + (int16)(int8)ch->_pitchBend;
-
- write((uint8)aReg, (uint8)bent);
-
- /* Preserve block + key-on, update F-num[9:8]. */
- uint8 bVal = _adlibPorts[bReg] & 0x20;
- bVal |= (uint8)((bent >> 8) & 0x03);
- write((uint8)bReg, bVal);
-}
-
-void ASound::writeArpeggio() {
- AdlibChannel *ch = _activeChannelPtr;
- uint8 chanNum = _activeChannelNumber;
- uint16 aReg = (uint16)chanNum + 0xA0;
- uint16 bReg = (uint16)chanNum + 0xB0;
-
- /* dl = _note + _octaveTranspose + _writeVolumePending - 1 */
- int note = (int)ch->_note + (int)ch->_octaveTranspose
- + (int)ch->_writeVolumePending - 1;
- int octave = note / 12;
- int semi = note % 12;
- if (semi < 0) {
- semi += 12; --octave;
- }
-
- uint16 freqEntry = SEMITONE_FREQ_TABLE[semi];
- uint8 fnHigh = (uint8)((freqEntry >> 8) & 0x03);
- uint8 block = (uint8)(octave & 0x07);
- uint8 bVal = (uint8)((block << 2) | fnHigh) | (_adlibPorts[bReg] & 0x20);
-
- write((uint8)aReg, (uint8)freqEntry);
- write((uint8)bReg, bVal);
-}
-
-void ASound::updateOctave() {
- uint8 chanNum = _activeChannelNumber;
- uint16 bReg = (uint16)chanNum + 0xB0;
- write((uint8)bReg, _adlibPorts[bReg] & 0xDF);
-}
-
-void ASound::noteOn() {
- AdlibChannel *ch = _activeChannelPtr;
- AdlibSample *smp = &_samples[ch->_sampleIndex];
-
- writeVolume();
-
- ch->_freqSweepCounter = smp->_freqSweepInit;
-
- if (ch->_freqSweepCounter != 0) {
- /* Sweep is pending; signal that sound is active but don't key on yet. */
- signalSoundPlaying();
- return;
- }
-
- /* No sweep - write frequency and set key-on immediately. */
- writeFrequency();
-
- uint8 chanNum = _activeChannelNumber;
- uint16 bReg = (uint16)chanNum + 0xB0;
- write((uint8)bReg, _adlibPorts[bReg] | 0x20);
-}
-
-void ASound::writeSampleRegs() {
- AdlibSample *smp = _samplePtr;
- uint16 base = _currentOpBase;
-
- /* 0xBD: rhythm mode flags. */
- uint8 bdVal = _adlibPorts[0xBD] & 0x3F;
- if (RHYTHM_HI_HAT) bdVal |= 0x80;
- if (RHYTHM_CYMBAL) bdVal |= 0x40;
- write(0xBD, bdVal);
-
- /* 0x08: note-select / rhythm enable. */
- write(0x08, RHYTHM_ENABLE ? 0x40 : 0x00);
-
- /* 0xC0+voice: feedback and algorithm.
- * asm: feedback << 1, then alg==1 -> bit0=0, else -> bit0=1. */
- write((uint8)(_activeChannelReg + 0xC0),
- (uint8)((smp->_feedback << 1) | (smp->_alg == 1 ? 0 : 1)));
-
- /* 0x60+base: attack / decay. */
- write((uint8)(base + 0x60),
- (uint8)(((smp->_attackRate & 0x0F) << 4) | (smp->_decayRate & 0x0F)));
-
- /* 0x80+base: sustain level / release rate. */
- write((uint8)(base + 0x80),
- (uint8)(((smp->_sustainLevel & 0x0F) << 4) | (smp->_releaseRate & 0x0F)));
-
- /* 0x20+base: AM/VIB/EGT/KSR/mult flags. */
- uint8 amVal = smp->_freqMultiple & 0x0F;
- if (smp->_egTyp == 1) amVal |= 0x20;
- if (smp->_vib == 1) amVal |= 0x40;
- if (smp->_ksr == 1) amVal |= 0x10;
- if (smp->_ampMod == 1) amVal |= 0x80;
- write((uint8)(base + 0x20), amVal);
-
- /* 0xE0+base: waveform select. */
- write((uint8)(base + 0xE0), (uint8)(smp->_waveformSelect & 0x03));
-}
-
-void ASound::loadSample() {
- AdlibChannel *ch = _activeChannelPtr;
- uint8 chanNum = _activeChannelNumber;
-
- /* Phase 1: Silence modulator operator (slot 0). */
- uint8 mSlot = VOICE_SLOTS[chanNum][0];
- uint8 mRegOff = SLOT_TO_REG_OFFSET[mSlot];
- write((uint8)(mRegOff + 0x80), 0xFF);
- write((uint8)(mRegOff + 0x40), 63);
-
- /* Phase 2: Silence carrier operator (slot 1). */
- uint8 cSlot = VOICE_SLOTS[chanNum][1];
- uint8 cRegOff = SLOT_TO_REG_OFFSET[cSlot];
- write((uint8)(cRegOff + 0x80), 0xFF);
- write((uint8)(cRegOff + 0x40), 63);
-
- /* Phase 3: Write first sample (modulator) registers. */
- _activeChannelReg = (uint16)chanNum;
- _currentOpBase = mRegOff;
- _samplePtr = &_samples[ch->_sampleIndex * 2];
- writeSampleRegs();
-
- /* Phase 4: Write second sample (carrier) registers. */
- _currentOpBase = cRegOff;
- _samplePtr = &_samples[ch->_sampleIndex * 2 + 1];
- writeSampleRegs();
-
- /* Phase 5: Write carrier TL (KSL | 0x3F for full attenuation initially). */
- write((uint8)(cRegOff + 0x40),
- (uint8)((_samplePtr->_scalingLevel << 6) | 0x3F));
-
- /* Phase 6: Use the first sample again for the modulator TL and for
- * sweep/frequency initialisation. */
- AdlibSample *smp3 = &_samples[ch->_sampleIndex * 2];
- uint16 mTLReg = (uint16)mRegOff + 0x40;
-
- if (smp3->_alg == 0) {
- write((uint8)mTLReg, (uint8)((smp3->_scalingLevel << 6) | 0x3F));
- } else {
- /* alg != 0: negate (totalLevel - 63) to get the TL value. */
- uint8 tl = (uint8)(-(int8)(smp3->_totalLevel - 63));
- write((uint8)mTLReg, (uint8)((smp3->_scalingLevel << 6) | (tl & 0x3F)));
- }
-
- /* Copy sweep/frequency parameters from the sample into the channel. */
- ch->_freqSweepCounter = smp3->_freqSweepInit;
- ch->_noiseFreqMask = smp3->_freqMask;
- ch->_freqAccum = smp3->_freqBase;
- ch->_freqStep = smp3->_outerLoopPtr;
-}
-
-void ASound::update() {
- if (_isDisabled)
- return;
-
- (void)getRandomNumber();
- ++_frameNumber2;
-
- pollAllChannels();
- tickCallback(); /* asound_updateCallback */
- updateAllChannels();
-
- _anySweepActive = 0;
-
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
- update1(i);
-
- /* If no sweep is active, flag the result as "done". */
- if (!_anySweepActive) {
- if (_resultFlag != (int16)0xFFFF) {
- _resultFlag = (int16)0xFFFF;
- _pollResult = (int16)0xFFFF;
- }
- }
-}
-
-void ASound::update1(int channelIndex) {
- /* asound_update1: called with cx = channelIndex+1 in the original loop.
- * Accesses channel via the adlib_channels pointer table. */
- AdlibChannel *ch = _channels[channelIndex];
-
- if (ch->_freqSweepCounter == 0)
- return;
-
- _anySweepActive = 1;
- ch->_freqAccum += ch->_freqStep;
- ch->_freqSweepCounter--;
-
- if (ch->_freqSweepCounter != 0)
- return;
-
- /* Sweep finished: write zero frequency to silence this OPL voice. */
- uint8 voice = (uint8)channelIndex;
- write((uint8)(voice + 0xA0), 0x00);
- write((uint8)(voice + 0xB0), 0x00);
-}
-
-void ASound::setFrequency(uint8 voice, uint16 freq) {
- /* asound_setFrequency: writes A0+v and B0+v (with key-on). */
- write((uint8)(voice + 0xA0), (uint8)(freq & 0xFF));
- uint8 bVal = (_adlibPorts[voice + 0xB0] & 0x20)
- | (uint8)((freq >> 8) & 0x03)
- | 0x20;
- write((uint8)(voice + 0xB0), bVal);
-}
-
-void ASound::noise_inner(int channelIndex) {
- /* adlib_noise_inner */
- AdlibChannel *ch = _channels[channelIndex];
-
- if (ch->_freqSweepCounter == 0)
- return;
-
- uint16 rnd = getRandomNumber();
- uint16 freq = (rnd & ch->_noiseFreqMask) + ch->_freqAccum;
- setFrequency((uint8)channelIndex, freq);
-}
-
-void ASound::updateAllChannels() {
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
- _channels[i]->processChannelFade();
-}
-
-void ASound::findFreeChannel(byte *soundData) {
- _findChannelMode = 0;
-
- /* Scan channels 0-6 for an empty slot. */
- for (int ch = 0; ch < 7; ++ch) {
- if (_channels[ch]->_activeCount == 0) {
- _channels[ch]->load(soundData);
- return;
- }
- }
-
- /* _findChannelMode==0: fall through to full search. */
- findFreeChannelFull(soundData);
-}
-
-void ASound::findFreeChannelFull(byte *soundData) {
- _findChannelMode = 2;
-
- /* Scan channels 7-8 for an empty slot. */
- if (_channel7._activeCount == 0) {
- _channel7.load(soundData); return;
- }
- if (_channel8._activeCount == 0) {
- _channel8.load(soundData); return;
- }
-
- /* Scan ch8 then ch7 for pending-stop (pre-emptible). */
- if (_channel8._pendingStop == 0xFF) {
- _channel8.load(soundData); return;
- }
- if (_channel7._pendingStop == 0xFF) {
- _channel7.load(soundData); return;
- }
-
- /* If _findChannelMode allows it, scan ch6..ch0 for pending-stop. */
- if (_findChannelMode == 0) {
- if (_channel6._pendingStop == 0xFF) {
- _channel6.load(soundData); return;
- }
- if (_channel5._pendingStop == 0xFF) {
- _channel5.load(soundData); return;
- }
- if (_channel4._pendingStop == 0xFF) {
- _channel4.load(soundData); return;
- }
- if (_channel3._pendingStop == 0xFF) {
- _channel3.load(soundData); return;
- }
- if (_channel2._pendingStop == 0xFF) {
- _channel2.load(soundData); return;
- }
- if (_channel1._pendingStop == 0xFF) {
- _channel1.load(soundData); return;
- }
- if (_channel0._pendingStop == 0xFF) {
- _channel0.load(soundData); return;
- }
- }
-}
-
-int ASound::isMusicChannelsActive() {
- _musicOnlyFlag = 1;
- uint8 result = 0;
- for (int i = 0; i <= 6; ++i)
- result |= _channels[i]->_activeCount;
- return result;
-}
-
-int ASound::isAnyChannelActive() {
- _musicOnlyFlag = 0;
- uint8 result = 0;
- for (int i = 0; i < ADLIB_CHANNEL_COUNT; ++i)
- result |= _channels[i]->_activeCount;
- return result;
-}
-
-void ASound::pollAllChannels() {
- _activeChannelNumber = 0;
- for (int ch = 0; ch < ADLIB_CHANNEL_COUNT; ++ch) {
- _activeChannelPtr = _channels[ch];
- pollActiveChannel();
- /* Note: _activeChannelNumber is incremented at the end of
- * pollActiveChannel, not here. */
- }
-}
-
-bool ASound::isSoundActive(byte *ptr) const {
- for (int ch = 0; ch < ADLIB_CHANNEL_COUNT; ++ch) {
- if (_channels[ch]->_activeCount && _channels[ch]->_soundData == ptr)
- return true;
- }
- return false;
-}
-
-uint16 ASound::readWord_impl() {
- /* asound_readWord: advance pSrc past the low byte, read lo then hi. */
- uint16 lo = *++pSrc;
- uint16 hi = *++pSrc;
- return lo | (hi << 8);
-}
-
-void ASound::pollActiveChannel() {
- AdlibChannel *ch = _activeChannelPtr;
-
- if (ch->_activeCount == 0) {
- ++_activeChannelNumber;
- return;
- }
-
- /* byte_16A0A: volume-dirty flag. Cleared here, set by various opcodes
- * and by the fade/vibrato sections; causes writeVolume at the end. */
- bool volDirty = false;
-
- /* ---- Key-on delay countdown ---- */
- if (ch->_keyOnDelay != 0) {
- ch->_keyOnDelay--;
- ch = _activeChannelPtr;
- if (ch->_keyOnDelay == 0)
- updateOctave();
- }
-
- /* ---- Duration countdown ---- */
- ch = _activeChannelPtr;
- ch->_activeCount--;
- ch = _activeChannelPtr;
- if (ch->_activeCount != 0)
- goto post_keyon;
-
- /* ================================================================
- * Command-dispatch loop.
- * Re-entered (via goto dispatch) after each command that does not
- * consume a duration tick. Falls through to the note-event path
- * when a note byte is encountered.
- * ================================================================ */
-dispatch:
- {
- ch = _activeChannelPtr;
- pSrc = ch->_pSrc;
-
- uint8 b = *pSrc;
-
- if (!(b & 0x80))
- goto note_event;
-
- /* Decode group (si) and sub-opcode (di). */
- uint8 si = b & 0x70;
- uint8 di = b & 0x0F;
-
- if (si == 0x00) {
- /* ============================================================
- * opcodes1 (group 0, 0x8_)
- * Called with: pSrc pointing at the command byte.
- * On entry, opcodes1 does: inc pSrc (skip past command byte).
- * On exit, sets _pSrc = pSrc + 1 (def_10CDC).
- * ============================================================ */
- pSrc++; /* skip command byte */
-
- switch (di) {
-
- case 0x0: /* set sampleIndex, call loadSample */
- ch->_sampleIndex = *pSrc;
- loadSample();
- volDirty = true;
- /* def_10CDC: _pSrc = pSrc + 1 */
- ch->_pSrc = pSrc + 1;
- goto dispatch;
-
- case 0x1: /* set velocity */
- {
- uint8 vel = *pSrc;
- if (ch->_pendingStop != 0) {
- /* If current velocity (signed) > new vel (signed), clamp down. */
- if ((int16)(int8)ch->_velocity > (int16)(int8)vel)
- ch->_velocity = vel;
- } else {
- ch->_velocity = vel;
- }
- volDirty = true;
- ch->_pSrc = pSrc + 1;
- goto dispatch;
- }
-
- case 0x2: /* set volume */
- {
- uint8 vol = *pSrc;
- if (ch->_pendingStop != 0) {
- /* Don't raise volume above current when fading out. */
- uint16 curVol = (uint16)ch->_volume;
- if (curVol <= (uint16)vol)
- goto op2_set_vol;
- /* else fall through and skip the set */
- volDirty = true;
- ch->_pSrc = pSrc + 1;
- goto dispatch;
- }
-op2_set_vol:
- ch->_volume = vol;
- volDirty = true;
- ch->_pSrc = pSrc + 1;
- goto dispatch;
- }
-
- case 0x3: /* set patchAttenuation */
- ch->_patchAttenuation = *pSrc;
- volDirty = true; /* opcodes1 case 3 jumps to loc_10B56 -> byte_16A0A=1 */
- ch->_pSrc = pSrc + 1;
- goto dispatch;
-
- case 0x4: /* set fade: fadePeriodReload, volumeFadeStep */
- if (ch->_pendingStop != 0) {
- /* Skip this opcode entirely when pending-stop is set. */
- ch->_pSrc = pSrc + 2;
- goto dispatch;
- }
- ch->_fadePeriodReload = *pSrc++;
- ch->_volumeFadeStep = *pSrc;
- ch->_fadePeriodCounter = 1;
- ch->_pSrc = pSrc + 1;
- goto dispatch;
-
- case 0x5: /* set vibrato: vibPeriodReload, vibPeriodCounter=reload, vibratoDepth, vibratoMode */
- ch->_vibPeriodReload = *pSrc++;
- ch->_vibPeriodCounter = ch->_vibPeriodReload;
- ch->_vibratoDepth = *pSrc++;
- ch->_vibratoMode = *pSrc;
- ch->_pSrc = pSrc + 1;
- goto dispatch;
-
- case 0x6: /* set transpose */
- ch->_transpose = *pSrc;
- ch->_pSrc = pSrc + 1;
- goto dispatch;
-
- case 0x7: /* set octaveTranspose */
- ch->_octaveTranspose = *pSrc;
- ch->_pSrc = pSrc + 1;
- goto dispatch;
-
- case 0x8: /* set field_11 (_writeVolumePending) */
- ch->_writeVolumePending = *pSrc;
- ch->_pSrc = pSrc + 1;
- goto dispatch;
-
- case 0x9: /* set arpeggio: field_12->field_C, pitchBend, field_13 */
- ch->_arpPeriodReload = *pSrc++;
- ch->_arpPeriodCounter = ch->_arpPeriodReload; /* field_C = field_12 */
- ch->_pitchBend = *pSrc++;
- ch->_arpCounterReload = *pSrc;
- ch->_pSrc = pSrc + 1;
- goto dispatch;
-
- case 0xA: /* skip forward by N+3 bytes (from the command byte) */
- {
- uint8 skip = *pSrc;
- /* pSrc currently points at the byte after the command byte.
- * Advance _pSrc by (skip + 3) from the *command* byte position,
- * which is pSrc-1. So _pSrc += skip + 3 from original _pSrc,
- * which was command byte. But def_10CDC does _pSrc = pSrc+1
- * giving +2 past command. Then skip+3 total from command: */
- /* asm: si = skip; ax = si + 3; add pSrc, ax; then def_10CDC
- * does pSrc+1. So net advance from the command byte =
- * skip + 3 + 1 = skip + 4. But pSrc already points one past
- * command byte, so _pSrc = pSrc + skip + 3. */
- ch->_pSrc = pSrc + (uint16)skip + 3;
- goto dispatch;
- }
-
- case 0xB: /* set durationOverride, clear noteOffset */
- ch->_durationOverride = *pSrc;
- ch->_noteOffset = 0;
- ch->_pSrc = pSrc + 1;
- goto dispatch;
-
- case 0xC: /* set noteOffset, clear durationOverride */
- ch->_noteOffset = *pSrc;
- ch->_durationOverride = 0;
- ch->_pSrc = pSrc + 1;
- goto dispatch;
-
- default:
- /* Unknown sub-opcode: advance past the single operand byte. */
- ch->_pSrc = pSrc + 1;
- goto dispatch;
- }
- }
-
- if (si == 0x10) {
- /* ============================================================
- * opcodes2 (group 1, 0x9_)
- * Loop control, restart, branch / call.
- * On exit: either sets _pSrc directly or falls to def_10EAC
- * (which just returns without touching _pSrc - the handlers
- * themselves are responsible for updating _pSrc).
- * ============================================================ */
- switch (di) {
-
- case 0x0: /* inner loop */
- {
- ch = _activeChannelPtr;
- if (ch->_innerLoopCount == 0) {
- pSrc++; /* advance to count byte */
- uint8 cnt = *pSrc;
- if (cnt == 0) {
- ch->_pSrc += 2;
- ch = _activeChannelPtr;
- ch->_innerLoopPtr = ch->_pSrc;
- ch->_innerLoopCount = 0;
- goto dispatch;
- }
- ch->_innerLoopCount = (uint16)cnt;
- /* Jump to innerLoopPtr (loc_10D5A). */
- ch->_pSrc = ch->_innerLoopPtr;
- goto dispatch;
- }
- /* Count is non-zero: decrement. */
- ch->_innerLoopCount--;
- ch = _activeChannelPtr;
- if (ch->_innerLoopCount == 0) {
- /* Loop done: advance past the two-byte opcode. */
- ch->_pSrc += 2;
- ch = _activeChannelPtr;
- ch->_innerLoopPtr = ch->_pSrc;
- goto dispatch;
- }
- /* Still looping: jump back. */
- ch->_pSrc = ch->_innerLoopPtr;
- goto dispatch;
- }
-
- case 0x1: /* outer loop */
- {
- ch = _activeChannelPtr;
- if (ch->_outerLoopCount == 0) {
- pSrc++;
- uint8 cnt = *pSrc;
- if (cnt == 0) {
- ch->_pSrc += 2;
- ch = _activeChannelPtr;
- ch->_outerLoopPtr = ch->_pSrc;
- ch->_innerLoopPtr = ch->_pSrc;
- ch->_innerLoopCount = 0;
- ch->_outerLoopCount = 0;
- goto dispatch;
- }
- ch->_outerLoopCount = (uint16)cnt;
- /* Jump to outerLoopPtr. */
- ch->_pSrc = ch->_outerLoopPtr;
- ch = _activeChannelPtr;
- ch->_innerLoopPtr = ch->_outerLoopPtr;
- goto dispatch;
- }
- /* Count non-zero: decrement. */
- ch->_outerLoopCount--;
- ch = _activeChannelPtr;
- if (ch->_outerLoopCount == 0) {
- ch->_pSrc += 2;
- ch = _activeChannelPtr;
- ch->_outerLoopPtr = ch->_pSrc;
- ch->_innerLoopPtr = ch->_pSrc;
- goto dispatch;
- }
- ch->_pSrc = ch->_outerLoopPtr;
- ch = _activeChannelPtr;
- ch->_innerLoopPtr = ch->_outerLoopPtr;
- goto dispatch;
- }
-
- case 0x2: /* restart: reset all loop pointers to _soundData */
- {
- ch = _activeChannelPtr;
- uint16 sd = (uint16)(uintptr_t)ch->_soundData;
- ch->_loopStartPtr = ch->_soundData;
- ch->_pSrc = ch->_soundData;
- ch->_innerLoopPtr = ch->_soundData;
- ch->_outerLoopPtr = ch->_soundData;
- (void)sd;
- goto dispatch;
- }
-
- case 0x3: /* set sound-data pointer (abs word offset), reset all loops */
- {
- byte *ptr = &_soundData[readWord_impl()];
- ch = _activeChannelPtr;
- ch->_loopStartPtr = ptr;
- ch->_pSrc = ptr;
- ch->_innerLoopPtr = ptr;
- ch->_outerLoopPtr = ptr;
- ch->_soundData = ptr;
- goto dispatch;
- }
-
- case 0x4: /* branch unconditional */
- {
- byte *dest = &_soundData[readWord_impl()];
- ch = _activeChannelPtr;
- ch->_pSrc = dest;
- goto dispatch;
- }
-
- case 0x5: /* branch with return-address save */
- {
- byte *dest = &_soundData[readWord_impl()];
- ch = _activeChannelPtr;
- ch->_branchTargetPtr = ch->_pSrc + 3;
- ch->_pSrc = dest;
- goto dispatch;
- }
-
- case 0x6: /* return from branch */
- {
- ch = _activeChannelPtr;
- if (ch->_branchTargetPtr != nullptr) {
- ch->_pSrc = ch->_branchTargetPtr;
- ch->_branchTargetPtr = nullptr;
- } else {
- ch->_pSrc++;
- }
- goto dispatch;
- }
-
- default:
- /* Unknown sub-opcode: no _pSrc advance (def_10EAC). */
- goto dispatch;
- }
- }
-
- if (si == 0x20) {
- /* ============================================================
- * opcodes3 (group 2, 0xA_)
- * Tempo/callback globals, random table operations,
- * indirect-table operations, call-by-address, nullsub.
- *
- * opcodes3 receives di (sub-opcode) but NOT the already-
- * incremented pSrc; each case increments pSrc itself as needed.
- * ============================================================ */
- switch (di) {
-
- case 0x0: /* random pick from packed table -> write to stream */
- {
- /* Format: [cmd] [tblSize] [entry0..N-1] [targetSlot]
- * pSrc points at the command byte on entry. */
- pSrc++;
- uint8 tblSize = *pSrc;
- pSrc++; /* now at entry[0] */
- (void)getRandomNumber();
- uint16 rnd = _randomSeed & 0x7FFF;
- int16 idx = (int16)((int16)rnd % (int16)(uint16)tblSize);
- uint8 chosen = *(pSrc + idx);
- uint8 target = *(pSrc + tblSize);
- *(pSrc + (uint16)target + 1) = chosen;
- ch = _activeChannelPtr;
- ch->_pSrc += (uint16)tblSize + 3;
- goto dispatch;
- }
-
- case 0x1: /* random range [lo..hi] -> write to stream */
- {
- /* Format: [cmd] [lo] [hi] [targetSlot] ... */
- pSrc++;
- uint8 lo = *pSrc++;
- uint8 hi = *pSrc++;
- uint16 range = (uint16)(hi - lo) + 1;
- /* pSrc now at targetSlot byte. */
- (void)getRandomNumber();
- uint16 rnd = _randomSeed & 0x7FFF;
- uint8 res = (uint8)((int16)rnd % (int16)range) + lo;
- uint8 slot = *pSrc;
- *(pSrc + (uint16)slot + 1) = res;
- ch = _activeChannelPtr;
- ch->_pSrc += 4; /* command+lo+hi+slot = 4 bytes consumed */
- goto dispatch;
- }
-
- case 0x2: /* indirect table read from scriptVar -> write to stream */
- {
- /* Format: [cmd] [varIdx] [tableSlot] [table...] */
- pSrc++;
- uint8 varIdx = *pSrc++;
- uint8 tableSlot = *pSrc++;
- /* pSrc now points at the inline table. */
- uint8 idxVal = _scriptVars[varIdx];
- uint8 chosen = *(pSrc + idxVal);
- uint8 target = *(pSrc + tableSlot);
- *(pSrc + (uint16)target + 1) = chosen;
- ch = _activeChannelPtr;
- ch->_pSrc += (uint16)tableSlot + 4;
- goto dispatch;
- }
-
- case 0x3: /* call function by address (near call in original) */
- {
- uint16 fnOffset = readWord_impl();
- callFunction(fnOffset);
- ch = _activeChannelPtr;
- ch->_pSrc += 3;
- goto dispatch;
- }
-
- case 0x4: /* nullsub_1 with byte arg */
- {
- /* "call near ptr aAsoundDriverAn+33h" - the target is a no-op. */
- pSrc++;
- /* (void)*pSrc; */
- ch = _activeChannelPtr;
- ch->_pSrc += 2;
- goto dispatch;
- }
-
- case 0x5: /* advance _pSrc by 4 (from command byte) */
- {
- /* loc_10F55 is shared with case 1's epilogue: _pSrc += 4. */
- ch = _activeChannelPtr;
- ch->_pSrc += 4;
- goto dispatch;
- }
-
- case 0x6: /* set word_124F2 (_tempoFineStep) */
- {
- pSrc++;
- uint8 val = *pSrc;
- _tempoFineStep = (uint16)val;
- ch = _activeChannelPtr;
- ch->_pSrc += 2;
- goto dispatch;
- }
-
- case 0x7: /* set word_124F0 (_tempoCoarseStep) */
- {
- pSrc++;
- uint8 val = *pSrc;
- _tempoCoarseStep = (uint16)val;
- ch = _activeChannelPtr;
- ch->_pSrc += 2;
- goto dispatch;
- }
-
- case 0x8: /* set word_124EE (_tempoPeriod), enable tick callback */
- {
- uint16 period = readWord_impl();
- _tempoPeriod = period;
- ch = _activeChannelPtr;
- ch->_pSrc += 3;
- _tempoEnabled = 1;
- _tempoTickCounter = 1;
- goto dispatch;
- }
-
- case 0x9: /* set word_124F4 (_tempoShift) */
- {
- pSrc++;
- uint8 val = *pSrc;
- _tempoShift = (uint16)val;
- ch = _activeChannelPtr;
- ch->_pSrc += 2;
- goto dispatch;
- }
-
- default:
- goto dispatch;
- }
- }
-
- if (si == 0x30) {
- /* ============================================================
- * opcodes4 (group 3, 0xB_)
- * Script-variable load (imm or var), store to stream, inc, dec.
- * Each case increments pSrc itself, then sets _pSrc.
- *
- * Switch on di (0-4); di >= 5 falls through to return.
- * ============================================================ */
- switch (di) {
-
- case 0x0: /* var[dst] = imm */
- {
- pSrc++;
- uint8 dst = *pSrc++;
- uint8 imm = *pSrc;
- _scriptVars[dst] = imm;
- ch = _activeChannelPtr;
- ch->_pSrc += 3;
- goto dispatch;
- }
-
- case 0x1: /* var[dst] = var[src] */
- {
- pSrc++;
- uint8 dst = *pSrc++;
- uint8 src = *pSrc;
- _scriptVars[dst] = _scriptVars[src];
- ch = _activeChannelPtr;
- ch->_pSrc += 3;
- goto dispatch;
- }
-
- case 0x2: /* stream[tableSlot+1] = var[src] */
- {
- /* asm: [bx+di+1] = cl, where bx=pSrc, di=tableSlot. */
- pSrc++;
- uint8 src = *pSrc++;
- uint8 tableSlot = *pSrc;
- *(pSrc + (uint16)tableSlot + 1) = _scriptVars[src];
- ch = _activeChannelPtr;
- ch->_pSrc += 3;
- goto dispatch;
- }
-
- case 0x3: /* var[dst]++ */
- {
- pSrc++;
- uint8 dst = *pSrc;
- _scriptVars[dst]++;
- ch = _activeChannelPtr;
- ch->_pSrc += 2;
- goto dispatch;
- }
-
- case 0x4: /* var[dst]-- */
- {
- pSrc++;
- uint8 dst = *pSrc;
- _scriptVars[dst]--;
- ch = _activeChannelPtr;
- ch->_pSrc += 2;
- goto dispatch;
- }
-
- default:
- goto dispatch;
- }
- }
-
- if (si == 0x40) {
- /* ============================================================
- * opcodes5 (group 4, 0xC_)
- * Script-variable ALU: add/sub/mul/div/rem/and/or/xor.
- *
- * Entry: inc pSrc, read dst (si), inc pSrc, read src (di).
- * Then _pSrc += 3 (command + dst + src).
- * 16 sub-opcodes (0-15).
- *
- * For sub-opcodes 0,2,4: src is an immediate (di from the byte).
- * For sub-opcodes 1,3,5: src is _scriptVars[di].
- * For 6-9: signed or unsigned division/remainder.
- * For 10-15: bitwise AND/OR/XOR, imm or var.
- * ============================================================ */
- pSrc++;
- uint8 dst = *pSrc++;
- uint8 src = *pSrc; /* immediate value or var index */
- ch = _activeChannelPtr;
- ch->_pSrc += 3;
-
- switch (di) {
- case 0x0: _scriptVars[dst] += src; break;
- case 0x1: _scriptVars[dst] += _scriptVars[src]; break;
- case 0x2: _scriptVars[dst] -= src; break;
- case 0x3: _scriptVars[dst] -= _scriptVars[src]; break;
- case 0x4: /* mul ax=di, mul [si] -> al stored */
- _scriptVars[dst] = (uint8)((uint16)src * (uint16)_scriptVars[dst]); break;
- case 0x5:
- _scriptVars[dst] = (uint8)((uint16)_scriptVars[src] * (uint16)_scriptVars[dst]); break;
- case 0x6: /* signed idiv by imm -> quotient in al */
- _scriptVars[dst] = (uint8)((int8)_scriptVars[dst] / (int8)src); break;
- case 0x7: /* unsigned div by var -> quotient in al */
- _scriptVars[dst] = _scriptVars[dst] / _scriptVars[src]; break;
- case 0x8: /* signed idiv by imm -> remainder in dl (stored to dst) */
- _scriptVars[dst] = (uint8)((int8)_scriptVars[dst] % (int8)src); break;
- case 0x9: /* unsigned div by var -> remainder in ah (stored to dst) */
- _scriptVars[dst] = _scriptVars[dst] % _scriptVars[src]; break;
- case 0xA: _scriptVars[dst] &= src; break;
- case 0xB: _scriptVars[dst] &= _scriptVars[src]; break;
- case 0xC: _scriptVars[dst] |= src; break;
- case 0xD: _scriptVars[dst] |= _scriptVars[src]; break;
- case 0xE: _scriptVars[dst] ^= src; break;
- case 0xF: _scriptVars[dst] ^= _scriptVars[src]; break;
- default: break;
- }
- goto dispatch;
- }
-
- if (si == 0x50) {
- /* ============================================================
- * opcodes6 (group 5, 0xD_)
- * Conditional branch: compare var[si] vs immediate (di as imm byte).
- *
- * Format: [cmd] [varIdx] [imm] [addrLo] [addrHi]
- * Entry: inc pSrc, read varIdx (si reg), inc pSrc, read imm (di reg).
- * Comparison: var[varIdx] vs imm.
- *
- * If condition met: call asound_readWord (reads addrLo/addrHi
- * from current pSrc position), set _pSrc = &_soundData[addr].
- * If not met: _pSrc += 5 (command+varIdx+imm+addr word = 5 bytes).
- *
- * var_2 is used as a flag: 0 = branch taken, 1 = not taken.
- * (Confusingly, var_2 = 1 means "taken" in opcodes7 but
- * 0 means "taken" in opcodes6 - see def_11292 / def_11360 difference.)
- *
- * opcodes6: var_2=1 -> taken (call readWord, set pSrc),
- * var_2=0 -> not taken (_pSrc += 5).
- * ============================================================ */
- pSrc++;
- uint8 varIdx = *pSrc++;
- uint8 imm = *pSrc;
- uint8 vval = _scriptVars[varIdx];
- bool taken = false;
-
- switch (di) {
- case 0x0: taken = ((uint16)vval == (uint16)imm); break; /* == */
- case 0x1: taken = ((uint16)vval != (uint16)imm); break; /* != */
- case 0x2: taken = ((int16)(uint16)vval >= (int16)(uint16)imm); break; /* jge -> taken if >= */
- case 0x3: taken = ((int16)(uint16)vval <= (int16)(uint16)imm); break; /* jle -> taken if <= */
- case 0x4: taken = (_scriptVars[varIdx] != _scriptVars[imm]); break; /* jnz after cmp [di],[si] */
- case 0x5: taken = (_scriptVars[varIdx] == _scriptVars[imm]); break; /* jz after cmp [di],[si] */
- case 0x6: taken = (_scriptVars[imm] <= _scriptVars[varIdx]); break; /* jbe -> [di]<=[si] taken */
- case 0x7: taken = (_scriptVars[imm] >= _scriptVars[varIdx]); break; /* jnb -> [di]>=[si] taken */
- default: break;
- }
-
- ch = _activeChannelPtr;
- if (taken) {
- ch->_pSrc = &_soundData[readWord_impl()];
- } else {
- ch->_pSrc += 5;
- }
- goto dispatch;
- }
-
- if (si == 0x60) {
- /* ============================================================
- * opcodes7 (group 6, 0xE_)
- * Conditional branch: compare var[si] vs var[di] (both scriptVars).
- *
- * Format: [cmd] [varIdxA] [varIdxB] [addrLo] [addrHi]
- * Entry: inc pSrc, read varIdxA (si), inc pSrc, read varIdxB (di).
- * var_2 = 0 initially.
- *
- * If condition met: var_2 = 1 -> branch taken:
- * _pSrc = pSrc + 5; _branchTargetPtr = pSrc + 5;
- * call readWord -> _pSrc = &_soundData[addr].
- * If not met (var_2 = 0): _pSrc += 5 (skip condition + word).
- *
- * Note: unlike opcodes6, opcodes7 DOES save a branch-target
- * (_branchTargetPtr = _pSrc + 5) on the taken path.
- * ============================================================ */
- pSrc++;
- uint8 idxA = *pSrc++;
- uint8 idxB = *pSrc;
- uint8 va = _scriptVars[idxA];
- uint8 vb = (uint8)idxB; /* di byte used as an immediate in some cases... */
-
- /* Actually in opcodes7 the layout is var vs var:
- * si = varIdxA, di = varIdxB (both are variable indices). */
- vb = _scriptVars[idxB];
-
- bool taken = false;
- switch (di & 0x07) {
- case 0x0: taken = ((uint16)va != (uint16)vb); break; /* jnz after cmp ax,di (case 0: jz -> NOT taken if ==; var_2 stays 0; but then def path: var_2==0 -> skip. Wait - let me re-read.) */
- /* Re-reading loc_112F0: cmp ax,di; jz loc_11352 (-> var_2=1=taken).
- * So case 0: taken = (va == vb). */
- default: break;
- }
-
- /* Actually re-reading carefully:
- * case 0 (loc_112F0): cmp ax,di; jz -> loc_11352 (var_2=1, taken)
- * else -> loc_112FA (ax=0, var_2=0, not taken)
- * case 1 (loc_11302): cmp ax,di; jz -> loc_1130A -> (jz loc_112FA, not taken)
- * else -> loc_11284 (var_2=1, taken)
- * -> case 1: taken = (va != vb)
- * case 2 (loc_1130E): jge -> loc_112FA (not taken); else loc_11284 (taken)
- * -> taken = (va < vb) (signed)
- * case 3 (loc_1131A): jle -> not taken; else taken
- * -> taken = (va > vb) (signed)
- * case 4 (loc_11326): cmp [di],al; jnz -> loc_112FA (not taken); else loc_11284 (taken)
- * -> taken = (_scriptVars[idxB] == va) (already same as case 0 with vars swapped)
- * case 5 (loc_11332): cmp [di],al; jz->loc_1130A (not taken if ==, taken if !=)
- * -> taken = (_scriptVars[idxB] != va)
- * case 6 (loc_1133C): jbe -> not taken; else taken -> taken = (_scriptVars[idxB] > va)
- * case 7 (loc_11348): jnb -> not taken; else taken -> taken = (_scriptVars[idxB] < va)
- */
- switch (di) {
- case 0x0: taken = (va == vb); break;
- case 0x1: taken = (va != vb); break;
- case 0x2: taken = ((int8)va < (int8)vb); break;
- case 0x3: taken = ((int8)va > (int8)vb); break;
- case 0x4: taken = (vb == va); break;
- case 0x5: taken = (vb != va); break;
- case 0x6: taken = (vb > va); break;
- case 0x7: taken = (vb < va); break;
- default: break;
- }
-
- ch = _activeChannelPtr;
- if (taken) {
- /* Save return target (pSrc+5 from the command byte). */
- ch->_branchTargetPtr = ch->_pSrc + 5;
- ch->_pSrc = &_soundData[readWord_impl()];
- } else {
- ch->_pSrc += 5;
- }
- goto dispatch;
- }
-
- /* Unknown group: skip. */
- goto dispatch;
- }
-
-note_event:
- {
- /* ---- Note event: [note][duration] ---- */
- ch = _activeChannelPtr;
- pSrc = ch->_pSrc;
- ch->_note = *pSrc;
- pSrc++;
- ch->_activeCount = *pSrc;
- pSrc++;
- ch->_pSrc += 2;
-
- ch = _activeChannelPtr;
- if (ch->_note == 0 || ch->_activeCount == 0) {
- updateOctave();
- goto post_keyon;
- }
-
- /* ---- Key-on ---- */
- ch = _activeChannelPtr;
- if (ch->_durationOverride != 0)
- ch->_keyOnDelay = ch->_durationOverride;
- else
- ch->_keyOnDelay = ch->_activeCount - ch->_noteOffset;
- noteOn();
- }
-
-post_keyon:
- {
- ch = _activeChannelPtr;
-
- /* ---- Arpeggio counter (field_13 / _arpCounterReload) ---- */
- if (ch->_arpCounterReload != 0) {
- /* Decrement the arpeggio period counter (field_C / _arpPeriodCounter). */
- ch->_arpPeriodCounter--;
- ch = _activeChannelPtr;
- if (ch->_arpPeriodCounter == 0) {
- /* Reload from field_12 (_arpPeriodReload). */
- ch->_arpPeriodCounter = ch->_arpPeriodReload;
- /* Call sub_117E8 (writeArpeggio - writes the arpeggio frequency). */
- writeArpeggio();
- }
- ch = _activeChannelPtr;
- /* Decrement the repeat counter unless it is the infinite sentinel 0xFF. */
- if (ch->_arpCounterReload != 0xFF)
- ch->_arpCounterReload--;
- }
-
- /* ---- Write-volume pending (field_11 / _writeVolumePending) ---- */
- ch = _activeChannelPtr;
- if (ch->_writeVolumePending != 0) {
- /* sub_11856 was already called by writeArpeggio above (or this is
- * a standalone field_11 set via opcode 8). Clear the flag. */
- writeArpeggio();
- ch = _activeChannelPtr;
- ch->_writeVolumePending = 0;
- }
-
- /* ---- Fade / volume step ---- */
- ch = _activeChannelPtr;
- if (ch->_fadePeriodCounter != 0) {
- ch->_fadePeriodCounter--;
- ch = _activeChannelPtr;
- if (ch->_fadePeriodCounter == 0) {
- ch->_fadePeriodCounter = ch->_fadePeriodReload;
- ch = _activeChannelPtr;
- if (ch->_volumeFadeStep != 0) {
- if (ch->_pendingStop != 0) {
- /* Pending-stop fade: step velocity and volume down. */
- if (ch->_velocity > 0)
- ch->_velocity += ch->_volumeFadeStep;
- ch = _activeChannelPtr;
- if (ch->_volume != 0)
- ch->_volume += ch->_volumeFadeStep;
- } else {
- /* Normal fade: step velocity, clamp to [0, 0x7F]. */
- if ((int8)ch->_volumeFadeStep > 0) {
- ch->_velocity += ch->_volumeFadeStep;
- ch = _activeChannelPtr;
- if ((uint16)ch->_velocity > 0x7F)
- ch->_velocity = 0x7F;
- } else {
- ch->_velocity += ch->_volumeFadeStep;
- ch = _activeChannelPtr;
- if ((int8)ch->_velocity < 0)
- ch->_velocity = 0;
- }
- }
- volDirty = true; /* byte_16A0A = 1 */
- }
- }
- }
-
- /* ---- Vibrato ---- */
- ch = _activeChannelPtr;
- if (ch->_vibPeriodCounter != 0) {
- ch->_vibPeriodCounter--;
- ch = _activeChannelPtr;
- if (ch->_vibPeriodCounter == 0) {
- ch->_vibPeriodCounter = ch->_vibPeriodReload;
- ch = _activeChannelPtr;
-
- if ((int8)ch->_vibratoDepth > 0) {
- /* Positive vibrato: ceiling at 0x7F. */
- uint8 sum = ch->_vibratoDepth + ch->_patchAttenuation;
- if (sum > 0x7F) {
- if (ch->_vibratoMode == 0xFF) {
- /* One-shot: clamp and stop. */
- ch->_vibratoDepth = 0;
- ch->_patchAttenuation = 0x7F;
- } else if (sum == 0x80 && ch->_vibratoDepth != 1) {
- /* Soft bounce at 0x80: patchAtten = 0x7F - vibratoDepth. */
- ch->_patchAttenuation = 0x7F - ch->_vibratoDepth;
- } else {
- ch->_vibratoDepth = (uint8)(-(int8)ch->_vibratoDepth);
- }
- }
- ch = _activeChannelPtr;
- ch->_patchAttenuation += ch->_vibratoDepth;
- volDirty = true;
-
- } else if ((int8)ch->_vibratoDepth < 0) {
- /* Negative vibrato: floor at 0. */
- uint8 sum = ch->_vibratoDepth + ch->_patchAttenuation;
- /* Note: sum is uint8 wrapping, but the asm uses "or al,al; jge"
- * treating the result as signed. */
- if ((int8)sum < 0) {
- if (ch->_vibratoMode == 0xFF) {
- ch->_vibratoDepth = 0;
- ch->_patchAttenuation = 0;
- } else if (sum == 0xFF && ch->_vibratoDepth != 0xFF) {
- /* Soft bounce: patchAtten = neg(vibratoDepth). */
- ch->_patchAttenuation = (uint8)(-(int8)ch->_vibratoDepth);
- } else {
- ch->_vibratoDepth = (uint8)(-(int8)ch->_vibratoDepth);
- }
- }
- ch = _activeChannelPtr;
- ch->_patchAttenuation += ch->_vibratoDepth;
- volDirty = true;
- }
- /* vibratoDepth == 0: nothing to do. */
- }
- }
-
- if (volDirty)
- writeVolume();
- }
-
- ++_activeChannelNumber;
-}
-
-void ASound::playSound(int offset) {
- findFreeChannelFull(loadData(offset));
-}
-
-} // namespace Forest
-} // namespace MADSV2
-} // namespace MADS
diff --git a/engines/mads/madsv2/forest/asound.h b/engines/mads/madsv2/forest/asound.h
deleted file mode 100644
index 32fefa08461..00000000000
--- a/engines/mads/madsv2/forest/asound.h
+++ /dev/null
@@ -1,649 +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 3 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, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#ifndef MADS_FOREST_ASOUND_H
-#define MADS_FOREST_ASOUND_H
-
-#include "common/mutex.h"
-#include "common/queue.h"
-#include "common/util.h"
-#include "mads/core/sound_manager.h"
-
-namespace MADS {
-namespace MADSV2 {
-namespace Forest {
-
-#define ADLIB_CHANNEL_COUNT 9
-
-struct AdlibChannel {
- static bool _isDisabled;
-
- // ---- byte fields (offsets 0x00 - 0x13) --------------------------------
-
- uint8 _activeCount = 0; // 0x00 duration tick countdown; 0 = channel idle
- uint8 _pitchBend = 0; // 0x01 signed pitch-bend offset applied by writePitchBend
- uint8 _volumeFadeStep = 0; // 0x02 signed per-period volume/velocity delta (0xFF = fade out)
- uint8 _vibratoDepth = 0; // 0x03 signed LFO depth; negated each period to oscillate
- uint8 _note = 0; // 0x04 MIDI note number for current event
- uint8 _sampleIndex = 0; // 0x05 index into _samples[] selecting the OPL patch
- uint8 _volume = 0; // 0x06 channel volume (0-127)
- uint8 _noteOffset = 0; // 0x07 subtracted from _activeCount to shorten note duration
- uint8 _durationOverride = 0; // 0x08 when non-zero, overrides the stream's duration byte
- uint8 _keyOnDelay = 0; // 0x09 countdown before the OPL key-on bit is cleared (gate time)
- uint8 _fadePeriodCounter = 0; // 0x0A counts down to 0 before applying _volumeFadeStep
- uint8 _fadePeriodReload = 0; // 0x0B reload value for _fadePeriodCounter
- uint8 _arpPeriodCounter = 0; // 0x0C arpeggio tick counter (reloaded from _arpPeriodReload)
- uint8 _vibPeriodCounter = 0; // 0x0D LFO tick counter; when it reaches 0 a vibrato step fires
- uint8 _vibPeriodReload = 0; // 0x0E reload value for _vibPeriodCounter
- uint8 _patchAttenuation = 0; // 0x0F per-note attenuation offset added on top of the patch TL
- uint8 _velocity = 0; // 0x10 note velocity (0-127); used together with _volume for TL
- uint8 _writeVolumePending = 0; // 0x11 non-zero -> call sub_11856 (secondary freq write) this tick
- uint8 _arpPeriodReload = 0; // 0x12 arpeggio period reload value (set by opcode 9)
- uint8 _arpCounterReload = 0; // 0x13 arpeggio counter reload (decremented; 0xFF = infinite)
-
- // ---- pointer fields (offsets 0x14 - 0x1F, word-sized in original) ----
-
- byte *_loopStartPtr = nullptr; // 0x14 start of the current loop body
- byte *_pSrc = nullptr; // 0x16 current read pointer into the sound-data stream
- byte *_innerLoopPtr = nullptr; // 0x18 inner-loop restart address
- byte *_outerLoopPtr = nullptr; // 0x1A outer-loop restart address
- byte *_soundData = nullptr; // 0x1C base address of this channel's sound-data block
- byte *_branchTargetPtr = nullptr; // 0x1E target of the most recent branch/jump opcode
-
- // ---- word counter fields (offsets 0x20 - 0x29) ----------------------
-
- uint16 _innerLoopCount = 0; // 0x20 remaining inner-loop iterations (0 = infinite until opcode)
- uint16 _outerLoopCount = 0; // 0x22 remaining outer-loop iterations (0 = infinite until opcode)
- uint16 _noiseFreqMask = 0; // 0x24 AND mask applied to the random number in noise mode
- uint16 _freqAccum = 0; // 0x26 frequency sweep accumulator (base frequency + swept offset)
- uint16 _freqStep = 0; // 0x28 per-tick increment added to _freqAccum during a sweep
-
- // ---- sweep / pause state (offsets 0x2A - 0x2D) ----------------------
-
- // 0x2A-0x2B Last computed OPL total-level bytes written by writeVolume.
- // lo byte (0x2A) = carrier TL nibble; hi byte (0x2B) = modulator TL nibble.
- // Written at the end of asound_writeVolume so that command7 (resume) can
- // restore operator levels without a full recalculation.
- uint8 _cachedCarrierTL = 0; // 0x2A cached carrier total-level (6-bit, 0 = loudest)
- uint8 _savedFreqSweep = 0; // 0x2B copy of _freqSweepCounter saved by command6 (pause)
- uint8 _freqSweepCounter = 0; // 0x2C countdown for frequency-sweep ticks; 0 = sweep done
- uint8 _savedSweepCounter = 0; // 0x2D second save slot: _freqSweepCounter is mirrored here
- // by command6/7 so command7 can restore the live value
-
-// ---- tuning / control (offsets 0x2E - 0x31) ------------------------
-
- uint8 _transpose = 0; // 0x2E semitone offset added when looking up _semitoneFreqTable
- uint8 _octaveTranspose = 0; // 0x2F octave shift: added to _note before octave calculation
- uint8 _pendingStop = 0; // 0x30 0xFF = channel is fading out and will go idle when silent
- uint8 _vibratoMode = 0; // 0x31 0xFF = one-shot vibrato (clamp & stop); else = continuous
-
- /**
- * Zeroes the "live" fields of one channel without touching the
- * loop/sound-data pointers (those are handled separately by load).
- */
- void reset();
-
- /**
- * Clears the entire channel struct, then initialises all loop/source
- * pointers to the supplied sound-data address, sets _patchAttenuation to
- * 0x40 (maximum, silent), and marks the channel active (_activeCount = 1).
- */
- void load(byte *soundData);
-
- /**
- * Redirects _loopStartPtr and _pSrc to the null/silence stream and arms a
- * one-step volume fade (_volumeFadeStep = 0xFF, _fadePeriodReload/Counter = 1)
- * so the channel fades out gracefully over the next tick.
- */
- void setPtr2(byte *ptr);
-
- /**
- * Marks the channel pending-stop (_pendingStop = 0xFF) and redirects
- * _soundData to the null/silence stream. Unlike setPtr2 this does not
- * touch _volumeFadeStep; the channel fades naturally via processChannelFade.
- */
- void enable();
-
- /**
- * Called every frame for each channel. When _pendingStop is set, waits
- * until both _velocity and _volume are zero before marking the channel idle
- * (_activeCount = 0); otherwise applies _volumeFadeStep to velocity/volume
- * each _fadePeriodReload ticks and clamps the result to [0, 0x7F].
- */
- void processChannelFade();
-};
-
-// ---------------------------------------------------------------------------
-// AdlibSample (unchanged from Return of the Phantom, 0x16 bytes)
-// ---------------------------------------------------------------------------
-struct AdlibSample {
- uint8 _attackRate = 0;
- uint8 _decayRate = 0;
- uint8 _sustainLevel = 0;
- uint8 _releaseRate = 0;
- uint8 _egTyp = 0;
- uint8 _ksr = 0;
- uint8 _totalLevel = 0;
- uint8 _scalingLevel = 0;
- uint8 _waveformSelect = 0;
- uint8 _freqMultiple = 0;
- uint8 _feedback = 0;
- uint8 _ampMod = 0;
- uint8 _vib = 0;
- uint8 _alg = 0;
- uint8 _freqSweepInit = 0; // initial _freqSweepCounter value; 0 = immediate key-on
- uint8 _reserved = 0;
- uint16 _freqMask = 0; // loaded into channel _noiseFreqMask
- uint16 _freqBase = 0; // loaded into channel _freqAccum
- uint16 _outerLoopPtr = 0; // loaded into channel _freqStep
-
- AdlibSample() {
- }
- AdlibSample(Common::SeekableReadStream &s);
-};
-
-// ---------------------------------------------------------------------------
-// ASound - Dragonsphere Adlib sound driver base class
-//
-// Command dispatch table layout (from off_11A14 / off_11A26 / off_11A2E /
-// funcs_12251 / off_11A64 in the disassembly):
-//
-// Table 1 off_11A14 commands 0- 8 (max=8, base=0, 9 entries)
-// Table 2 off_11A26 commands 16-19 (max=0x13, base=0x10, 4 entries)
-// command16 = background-music dispatcher (calls command18)
-// command17 = play specific piece (loads 7 channels direct)
-// command18 = re-entrant music launcher (reads word_12370 to pick a sub-command)
-// command19 = no-op (asound_command98)
-// Table 3 off_11A2E commands 24-32 (max=0x20, base=0x18, 9 entries)
-// Table 4 funcs_12251 commands 32-49 (max=0x31, base=0x20, 18 entries)
-// Includes asound_command32-48 (music pieces / SFX loaders)
-// and asound_command98 (no-op) in the last slot.
-// Table 5 off_11A64 commands 64-101 (max=0x65, base=0x40, 38 entries)
-// Includes asound_command64-101 (single-shot SFX loaders via
-// findFreeChannel / findFreeChannelFull) and two no-ops.
-//
-// The driver also exposes:
-// asound_command90 / 91 - two-voice SFX (findFreeChannelFull x2)
-// asound_command95 - four-voice music piece (findFreeChannel x4)
-// sub_11F98 - two-voice SFX (findFreeChannelFull x2)
-//
-// word_12370 tracks the "current music index" used by command18 to select
-// which music-piece loader to call.
-// ---------------------------------------------------------------------------
-class ASound : public SoundDriver {
-protected:
- /** Member-function pointer type for deferred sound-loader callbacks. */
- typedef void (ASound::*CallbackFunction)();
-
-private:
- // ---- callback / tick state ------------------------------------------
- uint16 _callbackCounter = 0; // per-tick countdown
- uint16 _callbackPeriod = 0; // reload value; 0 = callback disabled
- // Pointer to the deferred sound-loader called when the
- // counter fires (stored as uint16 in the original; typed as a member
- // function pointer in the C++ port).
- CallbackFunction _callbackFnPtr = nullptr;
-
- // ---- active-channel context (set by pollAllChannels) ----------------
- AdlibChannel *_activeChannelPtr = nullptr;
- uint8 _activeChannelNumber = 0;
- uint16 _activeChannelReg = 0; // 0xA0+ch register for the active channel
- uint16 _currentOpBase = 0; // operator register base for the active channel
-
- // ---- per-frame working state ----------------------------------------
- AdlibSample *_samplePtr = nullptr; // patch being loaded/written
- byte *pSrc = nullptr; // current read pointer (mirrors channel _pSrc)
- int16 _pollResult = 0;
- int16 _resultFlag = 0;
- uint16 _randomSeed = 0x4D2;
-
- // ---- driver-wide flags ----------------------------------------------
- uint16 _isDisabled = 0; // non-zero while the engine is paused (command6)
- uint8 _findChannelMode = 0; // 0=full search, 1=ch0-5 only, 2=ch6-8 then pending
-
- // ---- per-channel sweep shadows (for channel 5 special-casing) -------
- // Not present as separate globals in Dragonsphere; the channel
- // struct fields _savedFreqSweep / _savedSweepCounter handle this.
-
- // ---- misc globals ---------------------------------------------------
- uint8 _anySweepActive = 0; // set to 1 if any channel has _freqSweepCounter > 0
- int _frameNumber2 = 0; // secondary frame counter incremented every update
-
- // ---- script / sequencer registers -----------------------------------
- uint8 _scriptVars[32] = {}; // byte_16A10: 32 general-purpose script registers
-
- // ---- music-index tracker (word_12370) --------------------------------
- // Tracks which music piece was last launched by command18.
- uint16 _musicIndex = 0;
-
- // ---- tempo / sequencer state (from opcodes3 group 2 handlers) --------
- uint8 _musicOnlyFlag = 0; // byte_12393: 1=music-only check, 0=all channels
- uint16 _tempoFineStep = 0; // word_124F2: fine tempo step (opcode A6)
- uint16 _tempoCoarseStep = 0; // word_124F0: coarse tempo step (opcode A7)
- uint16 _tempoPeriod = 0; // word_124EE: tempo period in ticks (opcode A8)
- uint8 _tempoEnabled = 0; // non-zero when tempo tick is active (opcode A8)
- uint16 _tempoTickCounter = 0; // countdown for tempo callback
- uint16 _tempoShift = 0; // word_124F4: tempo shift (opcode A9)
-
- // =========================================================================
- // Private helpers
- // =========================================================================
-
- /** Timer callback entry point; calls update(). */
- void onTimer();
-
- /** Zeros _callbackFnPtr, _callbackCounter, and _callbackPeriod. */
- void clearCallback();
- void resetCallback() {
- clearCallback();
- }
-
- /**
- * Forces one OPL operator to maximum attenuation (total-level = 0x3F)
- * while preserving its upper KSL bits. 'portIndex' is the register index
- * into _adlibPorts (i.e. the 0x40-range operator register).
- * Used by command6 to mute all operator pairs during a pause.
- */
- void adlib_channelOff(uint8 portIndex);
-
- /**
- * Computes and writes the total-level registers for the active channel
- * (asound_writeVolume).
- *
- * Two top-level paths depending on the _alg field of the first sample:
- * _alg == 0 (FM): both operators contribute; loop twice writing
- * VOICE_SLOTS[ch][0] then VOICE_SLOTS[ch][1].
- * _alg != 0 (additive): only the carrier (slot 1) carries volume.
- *
- * Within each pass, two inner paths based on OPL version:
- * < 0x18 (OPL2): TL = clamp(0x3F - var_2, 0, 0x3F).
- * >= 0x18 (OPL3): patch-attenuation-aware mapping using
- * PATCH_ATTEN_TO_TL and VOL_VEL_TO_ATTEN_STEP tables;
- * writes two registers (offset 0 and offset 2).
- *
- * Caches the two written TL bytes in _cachedCarrierTL / _savedFreqSweep
- * so command7 can restore levels without a full recalculation.
- */
- void writeVolume();
-
- /**
- * Derives the OPL F-number and block (octave) from _note, _octaveTranspose,
- * and _transpose using _semitoneFreqTable, then writes registers 0xA0+ch
- * and 0xB0+ch (with key-on bit set).
- */
- void writeFrequency();
-
- /**
- * Applies _pitchBend as a signed offset to the already-computed frequency
- * registers without a full note recalculation.
- */
- void writePitchBend();
-
- /**
- * Arpeggio frequency write (sub_11856).
- * Called from pollActiveChannel when _writeVolumePending (field_11) is set.
- * Computes a modified frequency from _note + _octaveTranspose + field_11 - 1
- * and writes it to the OPL registers, preserving the key-on bit.
- */
- void writeArpeggio();
-
- /**
- * Clears the key-on bit (bit 5) of the 0xB0+ch register, silencing the
- * note while preserving pitch. Called during _keyOnDelay countdown.
- */
- void updateOctave();
-
- /**
- * Arms the frequency sweep counter from the sample definition, then - if
- * _freqSweepCounter is zero - immediately triggers the note by writing
- * volume and frequency registers and setting the key-on bit.
- */
- void noteOn();
-
- /**
- * Writes all OPL operator registers for the patch pointed to by _samplePtr,
- * using _currentOpBase as the operator base. Covers ADSR, KSL/TL,
- * feedback/algorithm, AM/VIB flags, and waveform-select registers.
- */
- void writeSampleRegs();
-
- /**
- * Loads all OPL registers for the patch assigned to the active channel,
- * covering both modulator and carrier operators, and sets up the channel's
- * sweep/frequency state from the AdlibSample definition.
- */
- void loadSample();
-
- /**
- * Main per-frame update: increments frame counters, polls all channels,
- * fires the tick callback, calls updateAllChannels, then runs the per-channel
- * frequency-sweep tick for all 9 voices.
- */
- void update();
-
- /**
- * Per-channel frequency-sweep tick for channel 'channelIndex' (0-based).
- * When _freqSweepCounter > 0: adds _freqStep to _freqAccum, decrements the
- * counter, and - when it reaches zero - zeroes the voice's frequency registers.
- * Sets _anySweepActive when the counter is still non-zero.
- */
- void update1(int channelIndex);
-
- /**
- * Writes a frequency value directly to the OPL registers for 'voice'.
- * The high byte selects the block/octave; the low byte is the F-number LSB.
- */
- void setFrequency(uint8 voice, uint16 freq);
-
- /**
- * Noise-channel inner tick: picks a random frequency offset masked by
- * _noiseFreqMask, adds _freqAccum, and writes the result to the voice
- * frequency registers.
- */
- void noise_inner(int channelIndex);
-
- /**
- * Calls processChannelFade for all 9 channels each frame.
- */
- void updateAllChannels();
-
- /**
- * Advances pSrc by one, reads two bytes little-endian, and returns the word.
- * Used by the bytecode opcodes that take 16-bit operands.
- */
- uint16 readWord_impl();
-
- /**
- * Deferred-callback tick: decrements _callbackCounter; when it reaches zero,
- * reloads it from _callbackPeriod and calls _callbackFnPtr (if non-null),
- * then clears _callbackFnPtr so it fires exactly once.
- */
- void tickCallback();
-
-protected:
- // ---- nine AdlibChannel instances ------------------------------------
- AdlibChannel _channel0, _channel1, _channel2;
- AdlibChannel _channel3, _channel4, _channel5;
- AdlibChannel _channel6, _channel7, _channel8;
- AdlibChannel *_channels[ADLIB_CHANNEL_COUNT] = {
- &_channel0, &_channel1, &_channel2,
- &_channel3, &_channel4, &_channel5,
- &_channel6, &_channel7, &_channel8
- };
-
- uint8 _adlibPorts[0x100] = { 0 };
- Common::Array<AdlibSample> _samples;
-
-protected:
- // =========================================================================
- // Protected helpers (used by ASound1âASound9)
- // =========================================================================
-
- /**
- * Checks whether any of channels 0-6 (or 0-8 when _musicOnlyFlag is clear)
- * have a non-zero _activeCount. Returns non-zero if sound is playing.
- * This is 'sub_1061A' in the disassembly.
- */
- int isMusicChannelsActive();
-
- /**
- * Like isMusicChannelsActive but scans all 9 channels unconditionally
- * (clears the ch0-6-only flag first). This is 'sub_1064E'.
- */
- int isAnyChannelActive();
-
- /**
- * Schedule fn as the next deferred-load callback.
- * Does NOT touch _callbackCounter or _callbackPeriod â those are preserved
- * from the previous loader so the callback fires on the right beat.
- * Cast the derived-class member-function pointer with reinterpret_cast.
- */
- void scheduleCallback(CallbackFunction fn) { _callbackFnPtr = fn; }
-
- /**
- * Arm the periodic timer and clear any pending callback pointer.
- * Call at the head of every immediate-load function (symmetric counter/period).
- */
- void resetCallbackTimer(uint16 period) {
- _callbackFnPtr = nullptr;
- _callbackCounter = period;
- _callbackPeriod = period;
- }
-
- /**
- * Arm the periodic timer with separate counter and period values.
- * Used by command44 which sets counter=0x60 but period=0xE0.
- */
- void resetCallbackTimerEx(uint16 counter, uint16 period) {
- _callbackFnPtr = nullptr;
- _callbackCounter = counter;
- _callbackPeriod = period;
- }
-
- /** Set the music-piece index (word_12370) read by command18. */
- void setMusicIndex(uint16 idx) { _musicIndex = idx; }
- /** Read the current music-piece index. */
- uint16 getMusicIndex() const { return _musicIndex; }
-
- /** Write one script-variable register (byte_16A10[idx]). */
- void setScriptVar(int idx, uint8 val) { _scriptVars[idx] = val; }
- /**
- * Writes (reg, value) to the OPL chip and updates the _adlibPorts shadow
- * array so subsequent reads return the last-written value.
- */
- void write(uint8 reg, uint8 value);
-
- /** Updates and returns _randomSeed using a simple linear-feedback shift. */
- uint16 getRandomNumber();
-
- /**
- * Restores one OPL operator by re-writing the value already stored in the
- * _adlibPorts shadow array. command7 uses this to resume playback after
- * a command6 pause without recalculating any TL values.
- * 'portIndex' is the operator register index into _adlibPorts.
- */
- void adlib_channelOn(uint8 portIndex);
-
- /** Sets _pollResult and _resultFlag to indicate that sound is playing. */
- void signalSoundPlaying();
-
- /**
- * Iterates over all 9 channels, sets _activeChannelPtr / _activeChannelNumber,
- * and calls pollActiveChannel for each one.
- */
- void pollAllChannels();
-
- /**
- * Per-channel bytecode interpreter, called once per frame per active channel.
- *
- * Sound data is a sequence of (note, duration) byte pairs plus command bytes
- * with the high bit set (0x80-0xFF). The upper nibble of a command byte
- * (after masking out the high bit) selects one of seven opcode groups:
- *
- * 0x0_ -> opcodes1 (patch/velocity/volume/vibrato/transpose/arpeggio)
- * 0x1_ -> opcodes2 (inner/outer loop control, restart, branch/call)
- * 0x2_ -> opcodes3 (tempo, script-variable arithmetic, call-by-address)
- * 0x3_ -> opcodes4 (script-variable load/store/copy/inc/dec)
- * 0x4_ -> opcodes5 (script-variable ALU: add/sub/mul/div with imm or var)
- * 0x5_ -> opcodes6 (extended: random-range, indexed table read/write)
- * 0x6_ -> opcodes7 (driver-level calls: command dispatch, etc.)
- *
- * The lower nibble is passed as the sub-opcode to each group handler.
- * Note bytes (high bit clear) consume one duration tick per call.
- */
- void pollActiveChannel();
-
- /** Returns true if the sound data block at 'ptr' is already playing. */
- bool isSoundActive(byte *ptr) const;
-
- /**
- * Scans channels 0-6 for an empty slot (_activeCount == 0) and calls
- * load() on the first one found. Falls through to findFreeChannelFull
- * for channels 6-8 when _findChannelMode != 1.
- */
- void findFreeChannel(byte *soundData);
-
- /**
- * Extends the search to channels 7-8, then checks for pending-stop
- * channels (which can be pre-empted), working in reverse priority order
- * (ch8, ch7, ch6 ... ch0).
- */
- void findFreeChannelFull(byte *soundData);
-
- /** Returns a pointer to the sound data at the given offset. */
- byte *loadData(int offset) {
- return &_soundData[offset];
- }
-
-protected:
- // =========================================================================
- // Core commands (0-8) - identical in purpose to Return of the Phantom
- // =========================================================================
-
- /**
- * command0: Full hardware reset.
- * 1. Reset all 9 channels.
- * 2. Mute all operator TL registers (0x40-0x55) to 0x3F.
- * 3. Zero remaining operator registers (0x60-0xFF and 0x01-0x3F).
- * 4. Write Waveform Select Enable (register 0x01 = 0x20).
- * 5. Reset the tick callback.
- */
- int command0();
-
- /**
- * command1: Fade out all channels.
- * Calls command3 (fade music channels 0-6) then command5 (fade SFX 7-8).
- */
- int command1();
-
- /**
- * command2: Fade out music channels 0-6.
- * Calls AdlibChannel::setPtr2 on each, redirecting to the null stream
- * and arming a one-step fade.
- */
- int command2();
-
- /**
- * command3: Fade out music channels 0-6 with pending-stop.
- * Calls AdlibChannel::enable on channels 0-6.
- */
- int command3();
-
- /**
- * command4: Fade out SFX channels 7-8.
- * Calls AdlibChannel::setPtr2 on channels 7 and 8.
- */
- int command4();
-
- /**
- * command5: Stop SFX channels 7-8 with pending-stop flag.
- * Calls AdlibChannel::enable on channels 7 and 8, letting each channel
- * finish its current OPL envelope before going idle.
- */
- int command5();
-
- /**
- * command6: Pause playback.
- * Saves each channel's _freqSweepCounter into _savedSweepCounter, zeroes
- * _freqSweepCounter on all channels, then mutes all 22 operator TL
- * registers (the byte_1239B table covers all operator slots 0x40-0x55).
- * Sets _isDisabled to prevent further updates.
- */
- int command6();
-
- /**
- * command7: Resume playback.
- * Restores operator volumes for all channels from _adlibPorts shadow,
- * copies _savedSweepCounter back to _freqSweepCounter on all channels,
- * signals sound playing if any channel was active, then clears _isDisabled.
- */
- int command7();
-
- /**
- * command8: Returns non-zero if any of the 9 channels has a non-zero
- * _activeCount (i.e. sound is currently playing).
- * Also clears the music-only flag (byte_12393 = 0) so the check covers
- * all 9 channels.
- */
- int command8();
-
- /**
- * Calls a function at a fixed offset within the sound driver.
- * @param offset Offset of the function
- */
- virtual void callFunction(uint16 offset);
-
- // =========================================================================
- // Music-index launcher (called via command18)
- // =========================================================================
-
- /**
- * command18: Re-entrant music launcher.
- * First calls command1 to fade current output, then branches on _musicIndex
- * (word_12370):
- * <= 0x12 -> calls off_11A26 table (commands 16-19)
- * > 0x12 -> calls funcs_12251 table (commands 32-49), index = _musicIndex - 0x20
- */
- int command18();
-
-public:
- /**
- * Constructor.
- * @param mixer Mixer instance
- * @param opl OPL chip instance
- * @param filename Path to the .DR1 (or equivalent) sound-driver file
- * @param dataOffset Offset in the file of the data segment
- * @param dataSize Size of the data segment
- */
- ASound(Audio::Mixer *mixer, OPL::OPL *opl, const Common::Path &filename,
- int dataOffset, int dataSize);
-
- ~ASound() override {
- }
-
- /** Stop all currently playing sounds (wraps command0). */
- virtual int stop() override;
-
- /** Main poll method; drives the per-frame update. */
- int poll() override;
-
- /**
- * Noise channel tick: for each of the 9 channels calls noise_inner,
- * which randomises the voice frequency each frame using _noiseFreqMask.
- */
- void noise() override;
-
- /**
- * Starts playback of the sound data at the given byte offset within the
- * driver's data segment, using findFreeChannelFull to select a channel.
- */
- void playSound(int offset);
-
- void setVolume(int volume) override {
- // TODO: implement if needed
- }
-};
-
-} // namespace Forest
-} // namespace MADSV2
-} // namespace MADS
-
-#endif
diff --git a/engines/mads/madsv2/core/digi.cpp b/engines/mads/madsv2/forest/digi.cpp
similarity index 85%
rename from engines/mads/madsv2/core/digi.cpp
rename to engines/mads/madsv2/forest/digi.cpp
index c598d28ae94..3ab8e397273 100644
--- a/engines/mads/madsv2/core/digi.cpp
+++ b/engines/mads/madsv2/forest/digi.cpp
@@ -19,12 +19,13 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/config.h"
#include "mads/madsv2/engine.h"
namespace MADS {
namespace MADSV2 {
+namespace Forest {
int digi_val2;
int digi_timing_index;
@@ -55,11 +56,17 @@ void digi_play_build(int room, char thing, int num, int slot) {
digi_play(name.c_str(), slot);
}
-void digi_play(const char *name, int slot) {}
-void digi_stop(int which_one) {}
-void digi_read_another_chunk() {}
-void digi_initial_volume(int vol) {}
-void digi_set_volume(int vol, int slot) {}
+void digi_play(const char *name, int slot) {
+}
+void digi_stop(int which_one) {
+}
+void digi_read_another_chunk() {
+}
+void digi_initial_volume(int vol) {
+}
+void digi_set_volume(int vol, int slot) {
+}
+} // namespace Forest
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/digi.h b/engines/mads/madsv2/forest/digi.h
similarity index 94%
rename from engines/mads/madsv2/core/digi.h
rename to engines/mads/madsv2/forest/digi.h
index f212c2f334c..58b64fc11a8 100644
--- a/engines/mads/madsv2/core/digi.h
+++ b/engines/mads/madsv2/forest/digi.h
@@ -19,13 +19,14 @@
*
*/
-#ifndef MADS_DIGI_SOUND_H
-#define MADS_DIGI_SOUND_H
+#ifndef MADS_FOREST_DIGI_H
+#define MADS_FOREST_DIGI_H
#include "common/scummsys.h"
namespace MADS {
namespace MADSV2 {
+namespace Forest {
//extern int config_file.forest1;
extern int digi_val2;
@@ -42,6 +43,7 @@ extern void digi_read_another_chunk();
extern void digi_initial_volume(int vol);
extern void digi_set_volume(int vol, int slot);
+} // namespace Forest
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/forest/global.cpp b/engines/mads/madsv2/forest/global.cpp
index 3615775203e..d5bae9788be 100644
--- a/engines/mads/madsv2/forest/global.cpp
+++ b/engines/mads/madsv2/forest/global.cpp
@@ -20,7 +20,7 @@
*/
#include "common/textconsole.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/text.h"
@@ -28,7 +28,7 @@
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/pal.h"
#include "mads/madsv2/forest/global.h"
#include "mads/madsv2/forest/extra.h"
diff --git a/engines/mads/madsv2/core/midi.cpp b/engines/mads/madsv2/forest/midi.cpp
similarity index 85%
rename from engines/mads/madsv2/core/midi.cpp
rename to engines/mads/madsv2/forest/midi.cpp
index 34ed0051361..6d5533bf289 100644
--- a/engines/mads/madsv2/core/midi.cpp
+++ b/engines/mads/madsv2/forest/midi.cpp
@@ -20,13 +20,20 @@
*/
#include "common/textconsole.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
+#include "mads/madsv2/core/env.h"
#include "mads/madsv2/engine.h"
namespace MADS {
namespace MADSV2 {
+namespace Forest {
void midi_play(const char *name) {
+ assert(env_exist(name));
+
+ // TODO
+ warning("TODO: global_midi_play");
+
// TODO
}
@@ -34,5 +41,6 @@ void midi_stop() {
// TODO
}
+} // namespace Forest
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/core/midi.h b/engines/mads/madsv2/forest/midi.h
similarity index 89%
rename from engines/mads/madsv2/core/midi.h
rename to engines/mads/madsv2/forest/midi.h
index 52515cc9adc..508c7ec82ac 100644
--- a/engines/mads/madsv2/core/midi.h
+++ b/engines/mads/madsv2/forest/midi.h
@@ -19,18 +19,21 @@
*
*/
-#ifndef MADS_CORE_MIDI_H
-#define MADS_CORE_MIDI_H
+#ifndef MADS_FOREST_MIDI_H
+#define MADS_FOREST_MIDI_H
#include "common/scummsys.h"
namespace MADS {
namespace MADSV2 {
+namespace Forest {
extern void midi_play(const char *name);
extern void midi_stop();
-inline void midi_loop() {}
+inline void midi_loop() {
+}
+} // namespace Forest
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/forest/rooms/room101.cpp b/engines/mads/madsv2/forest/rooms/room101.cpp
index 8e60e2a8050..650ac79c08f 100644
--- a/engines/mads/madsv2/forest/rooms/room101.cpp
+++ b/engines/mads/madsv2/forest/rooms/room101.cpp
@@ -19,13 +19,13 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/player.h"
diff --git a/engines/mads/madsv2/forest/rooms/room103.cpp b/engines/mads/madsv2/forest/rooms/room103.cpp
index f4f4b3a16ff..a3f08454721 100644
--- a/engines/mads/madsv2/forest/rooms/room103.cpp
+++ b/engines/mads/madsv2/forest/rooms/room103.cpp
@@ -19,13 +19,13 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/sprite.h"
#include "mads/madsv2/core/text.h"
diff --git a/engines/mads/madsv2/forest/rooms/room104.cpp b/engines/mads/madsv2/forest/rooms/room104.cpp
index 71c10cb5336..02f3b94bce2 100644
--- a/engines/mads/madsv2/forest/rooms/room104.cpp
+++ b/engines/mads/madsv2/forest/rooms/room104.cpp
@@ -19,13 +19,13 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
diff --git a/engines/mads/madsv2/forest/rooms/room106.cpp b/engines/mads/madsv2/forest/rooms/room106.cpp
index 398d276c017..d600c93d2eb 100644
--- a/engines/mads/madsv2/forest/rooms/room106.cpp
+++ b/engines/mads/madsv2/forest/rooms/room106.cpp
@@ -20,13 +20,13 @@
*/
#include "mads/madsv2/core/config.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
diff --git a/engines/mads/madsv2/forest/rooms/room107.cpp b/engines/mads/madsv2/forest/rooms/room107.cpp
index f762365faeb..7176b0e1239 100644
--- a/engines/mads/madsv2/forest/rooms/room107.cpp
+++ b/engines/mads/madsv2/forest/rooms/room107.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
diff --git a/engines/mads/madsv2/forest/rooms/room199.cpp b/engines/mads/madsv2/forest/rooms/room199.cpp
index 87cbfd4a322..bb9bb8458c3 100644
--- a/engines/mads/madsv2/forest/rooms/room199.cpp
+++ b/engines/mads/madsv2/forest/rooms/room199.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/global.h"
#include "mads/madsv2/core/kernel.h"
diff --git a/engines/mads/madsv2/forest/rooms/room201.cpp b/engines/mads/madsv2/forest/rooms/room201.cpp
index 9684f3d598b..a90c96828f9 100644
--- a/engines/mads/madsv2/forest/rooms/room201.cpp
+++ b/engines/mads/madsv2/forest/rooms/room201.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
diff --git a/engines/mads/madsv2/forest/rooms/room203.cpp b/engines/mads/madsv2/forest/rooms/room203.cpp
index 5088c5f7fd9..8324ca890c2 100644
--- a/engines/mads/madsv2/forest/rooms/room203.cpp
+++ b/engines/mads/madsv2/forest/rooms/room203.cpp
@@ -19,12 +19,12 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/forest/extra.h"
diff --git a/engines/mads/madsv2/forest/rooms/room204.cpp b/engines/mads/madsv2/forest/rooms/room204.cpp
index 11c9f3dc451..70fbaec8dab 100644
--- a/engines/mads/madsv2/forest/rooms/room204.cpp
+++ b/engines/mads/madsv2/forest/rooms/room204.cpp
@@ -19,12 +19,12 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/global.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/forest/global.h"
diff --git a/engines/mads/madsv2/forest/rooms/room205.cpp b/engines/mads/madsv2/forest/rooms/room205.cpp
index 384865a30d3..3396f9183d9 100644
--- a/engines/mads/madsv2/forest/rooms/room205.cpp
+++ b/engines/mads/madsv2/forest/rooms/room205.cpp
@@ -19,14 +19,14 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/global.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/forest/global.h"
diff --git a/engines/mads/madsv2/forest/rooms/room210.cpp b/engines/mads/madsv2/forest/rooms/room210.cpp
index abea8109c55..97afb3ccc66 100644
--- a/engines/mads/madsv2/forest/rooms/room210.cpp
+++ b/engines/mads/madsv2/forest/rooms/room210.cpp
@@ -20,11 +20,11 @@
*/
#include "mads/madsv2/core/config.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/speech.h"
#include "mads/madsv2/forest/mads/inventory.h"
diff --git a/engines/mads/madsv2/forest/rooms/room211.cpp b/engines/mads/madsv2/forest/rooms/room211.cpp
index a572b5b546d..1477e3d4af2 100644
--- a/engines/mads/madsv2/forest/rooms/room211.cpp
+++ b/engines/mads/madsv2/forest/rooms/room211.cpp
@@ -19,11 +19,11 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/forest/global.h"
#include "mads/madsv2/forest/rooms/section1.h"
diff --git a/engines/mads/madsv2/forest/rooms/room220.cpp b/engines/mads/madsv2/forest/rooms/room220.cpp
index 465632497d6..bb1d922ab1e 100644
--- a/engines/mads/madsv2/forest/rooms/room220.cpp
+++ b/engines/mads/madsv2/forest/rooms/room220.cpp
@@ -19,11 +19,11 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/forest/global.h"
#include "mads/madsv2/forest/rooms/section1.h"
diff --git a/engines/mads/madsv2/forest/rooms/room301.cpp b/engines/mads/madsv2/forest/rooms/room301.cpp
index 45d959c7884..949784b5af7 100644
--- a/engines/mads/madsv2/forest/rooms/room301.cpp
+++ b/engines/mads/madsv2/forest/rooms/room301.cpp
@@ -20,11 +20,11 @@
*/
#include "mads/madsv2/forest/journal.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/forest/global.h"
diff --git a/engines/mads/madsv2/forest/rooms/room302.cpp b/engines/mads/madsv2/forest/rooms/room302.cpp
index ee3db098fd5..a6a8b061c41 100644
--- a/engines/mads/madsv2/forest/rooms/room302.cpp
+++ b/engines/mads/madsv2/forest/rooms/room302.cpp
@@ -19,12 +19,12 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
diff --git a/engines/mads/madsv2/forest/rooms/room303.cpp b/engines/mads/madsv2/forest/rooms/room303.cpp
index c6f8028e090..5587005d36a 100644
--- a/engines/mads/madsv2/forest/rooms/room303.cpp
+++ b/engines/mads/madsv2/forest/rooms/room303.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
diff --git a/engines/mads/madsv2/forest/rooms/room304.cpp b/engines/mads/madsv2/forest/rooms/room304.cpp
index ec8ee34447f..ef4329aaee3 100644
--- a/engines/mads/madsv2/forest/rooms/room304.cpp
+++ b/engines/mads/madsv2/forest/rooms/room304.cpp
@@ -20,12 +20,12 @@
*/
#include "mads/madsv2/core/config.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/text.h"
diff --git a/engines/mads/madsv2/forest/rooms/room305.cpp b/engines/mads/madsv2/forest/rooms/room305.cpp
index ff0d670596e..744461f52fa 100644
--- a/engines/mads/madsv2/forest/rooms/room305.cpp
+++ b/engines/mads/madsv2/forest/rooms/room305.cpp
@@ -20,7 +20,7 @@
*/
#include "mads/madsv2/core/config.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
diff --git a/engines/mads/madsv2/forest/rooms/room306.cpp b/engines/mads/madsv2/forest/rooms/room306.cpp
index 72858656bac..4af54428a68 100644
--- a/engines/mads/madsv2/forest/rooms/room306.cpp
+++ b/engines/mads/madsv2/forest/rooms/room306.cpp
@@ -23,9 +23,9 @@
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/sprite.h"
diff --git a/engines/mads/madsv2/forest/rooms/room307.cpp b/engines/mads/madsv2/forest/rooms/room307.cpp
index 122ff122079..9e6999583c6 100644
--- a/engines/mads/madsv2/forest/rooms/room307.cpp
+++ b/engines/mads/madsv2/forest/rooms/room307.cpp
@@ -20,12 +20,12 @@
*/
#include "mads/madsv2/core/config.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
diff --git a/engines/mads/madsv2/forest/rooms/room308.cpp b/engines/mads/madsv2/forest/rooms/room308.cpp
index 7ef97d10d99..f6e514b7cb9 100644
--- a/engines/mads/madsv2/forest/rooms/room308.cpp
+++ b/engines/mads/madsv2/forest/rooms/room308.cpp
@@ -20,7 +20,7 @@
*/
#include "mads/madsv2/core/config.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/forest/extra.h"
#include "mads/madsv2/forest/journal.h"
#include "mads/madsv2/core/game.h"
diff --git a/engines/mads/madsv2/forest/rooms/room321.cpp b/engines/mads/madsv2/forest/rooms/room321.cpp
index fc47eafab3e..b5db451096b 100644
--- a/engines/mads/madsv2/forest/rooms/room321.cpp
+++ b/engines/mads/madsv2/forest/rooms/room321.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
diff --git a/engines/mads/madsv2/forest/rooms/room322.cpp b/engines/mads/madsv2/forest/rooms/room322.cpp
index c510d1402e7..f2dacc67a0e 100644
--- a/engines/mads/madsv2/forest/rooms/room322.cpp
+++ b/engines/mads/madsv2/forest/rooms/room322.cpp
@@ -23,8 +23,8 @@
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/digi.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/digi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
diff --git a/engines/mads/madsv2/forest/rooms/room401.cpp b/engines/mads/madsv2/forest/rooms/room401.cpp
index f2c9c3c9766..b2f8706c53e 100644
--- a/engines/mads/madsv2/forest/rooms/room401.cpp
+++ b/engines/mads/madsv2/forest/rooms/room401.cpp
@@ -24,9 +24,9 @@
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/sprite.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/text.h"
diff --git a/engines/mads/madsv2/forest/rooms/room402.cpp b/engines/mads/madsv2/forest/rooms/room402.cpp
index f1387102cf6..c18b0b0453e 100644
--- a/engines/mads/madsv2/forest/rooms/room402.cpp
+++ b/engines/mads/madsv2/forest/rooms/room402.cpp
@@ -19,12 +19,12 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sprite.h"
#include "mads/madsv2/forest/journal.h"
diff --git a/engines/mads/madsv2/forest/rooms/room403.cpp b/engines/mads/madsv2/forest/rooms/room403.cpp
index d35ee2533fa..e1713a0dd2b 100644
--- a/engines/mads/madsv2/forest/rooms/room403.cpp
+++ b/engines/mads/madsv2/forest/rooms/room403.cpp
@@ -20,12 +20,12 @@
*/
#include "mads/madsv2/core/config.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sprite.h"
diff --git a/engines/mads/madsv2/forest/rooms/room404.cpp b/engines/mads/madsv2/forest/rooms/room404.cpp
index b17a9c55636..86bfcca25e2 100644
--- a/engines/mads/madsv2/forest/rooms/room404.cpp
+++ b/engines/mads/madsv2/forest/rooms/room404.cpp
@@ -20,7 +20,7 @@
*/
#include "mads/madsv2/core/config.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
diff --git a/engines/mads/madsv2/forest/rooms/room405.cpp b/engines/mads/madsv2/forest/rooms/room405.cpp
index 31e712d124f..b17501b8f1f 100644
--- a/engines/mads/madsv2/forest/rooms/room405.cpp
+++ b/engines/mads/madsv2/forest/rooms/room405.cpp
@@ -20,7 +20,7 @@
*/
#include "mads/madsv2/core/config.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
diff --git a/engines/mads/madsv2/forest/rooms/room420.cpp b/engines/mads/madsv2/forest/rooms/room420.cpp
index b0a53052ea0..b212e995bc4 100644
--- a/engines/mads/madsv2/forest/rooms/room420.cpp
+++ b/engines/mads/madsv2/forest/rooms/room420.cpp
@@ -19,10 +19,10 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/forest/global.h"
#include "mads/madsv2/forest/rooms/section1.h"
diff --git a/engines/mads/madsv2/forest/rooms/room501.cpp b/engines/mads/madsv2/forest/rooms/room501.cpp
index ed46140e7b8..8c930fbe334 100644
--- a/engines/mads/madsv2/forest/rooms/room501.cpp
+++ b/engines/mads/madsv2/forest/rooms/room501.cpp
@@ -23,8 +23,8 @@
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
-#include "mads/madsv2/core/digi.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/digi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
#include "mads/madsv2/core/text.h"
diff --git a/engines/mads/madsv2/forest/rooms/room503.cpp b/engines/mads/madsv2/forest/rooms/room503.cpp
index 35bd8fb3393..19672e9ccae 100644
--- a/engines/mads/madsv2/forest/rooms/room503.cpp
+++ b/engines/mads/madsv2/forest/rooms/room503.cpp
@@ -19,13 +19,13 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/imath.h"
#include "mads/madsv2/core/inter.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/sound.h"
diff --git a/engines/mads/madsv2/forest/rooms/room509.cpp b/engines/mads/madsv2/forest/rooms/room509.cpp
index 10ff60818a0..c9bf05a440d 100644
--- a/engines/mads/madsv2/forest/rooms/room509.cpp
+++ b/engines/mads/madsv2/forest/rooms/room509.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
diff --git a/engines/mads/madsv2/forest/rooms/room510.cpp b/engines/mads/madsv2/forest/rooms/room510.cpp
index 213430b7c43..4626dbd6968 100644
--- a/engines/mads/madsv2/forest/rooms/room510.cpp
+++ b/engines/mads/madsv2/forest/rooms/room510.cpp
@@ -20,12 +20,12 @@
*/
#include "mads/madsv2/core/config.h"
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/font.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/core/player.h"
#include "mads/madsv2/core/quote.h"
diff --git a/engines/mads/madsv2/forest/rooms/room520.cpp b/engines/mads/madsv2/forest/rooms/room520.cpp
index 13d6596dcc9..3ff8a8239f0 100644
--- a/engines/mads/madsv2/forest/rooms/room520.cpp
+++ b/engines/mads/madsv2/forest/rooms/room520.cpp
@@ -19,7 +19,7 @@
*
*/
-#include "mads/madsv2/core/digi.h"
+#include "mads/madsv2/forest/digi.h"
#include "mads/madsv2/core/game.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
diff --git a/engines/mads/madsv2/forest/rooms/room904.cpp b/engines/mads/madsv2/forest/rooms/room904.cpp
index bfc535ce269..52fcc246db8 100644
--- a/engines/mads/madsv2/forest/rooms/room904.cpp
+++ b/engines/mads/madsv2/forest/rooms/room904.cpp
@@ -24,7 +24,7 @@
#include "mads/madsv2/core/global.h"
#include "mads/madsv2/core/kernel.h"
#include "mads/madsv2/core/matte.h"
-#include "mads/madsv2/core/midi.h"
+#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/mouse.h"
#include "mads/madsv2/core/object.h"
#include "mads/madsv2/core/player.h"
diff --git a/engines/mads/module.mk b/engines/mads/module.mk
index b5e8aee7e80..cee9da707fd 100644
--- a/engines/mads/module.mk
+++ b/engines/mads/module.mk
@@ -72,7 +72,6 @@ MODULE_OBJS += \
madsv2/core/cursor.o \
madsv2/core/cycle.o \
madsv2/core/dialog.o \
- madsv2/core/digi.o \
madsv2/core/ems.o \
madsv2/core/env.o \
madsv2/core/error.o \
@@ -96,7 +95,6 @@ MODULE_OBJS += \
madsv2/core/matte.o \
madsv2/core/mcga.o \
madsv2/core/mem.o \
- madsv2/core/midi.o \
madsv2/core/mouse.o \
madsv2/core/object.o \
madsv2/core/pack.o \
@@ -263,12 +261,13 @@ MODULE_OBJS += \
madsv2/dragonsphere/menus.o \
madsv2/dragonsphere/sound_dragonsphere.o \
madsv2/forest/forest.o \
- madsv2/forest/asound.o \
+ madsv2/forest/digi.o \
madsv2/forest/extra.o \
madsv2/forest/global.o \
madsv2/forest/journal.o \
madsv2/forest/main.o \
madsv2/forest/menus.o \
+ madsv2/forest/midi.o \
madsv2/forest/mads/mads.o \
madsv2/forest/rooms/room101.o \
madsv2/forest/rooms/room103.o \
Commit: 1ce640b1a11d5187cb4c780a4ee1e3e49a5f6bd3
https://github.com/scummvm/scummvm/commit/1ce640b1a11d5187cb4c780a4ee1e3e49a5f6bd3
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2026-06-21T12:41:50+10:00
Commit Message:
MADS: FOREST: Skeleton MidiPlayer class
Changed paths:
engines/mads/madsv2/forest/forest.cpp
engines/mads/madsv2/forest/forest.h
engines/mads/madsv2/forest/midi.cpp
engines/mads/madsv2/forest/midi.h
diff --git a/engines/mads/madsv2/forest/forest.cpp b/engines/mads/madsv2/forest/forest.cpp
index 751831779f0..56f0f3eaf3d 100644
--- a/engines/mads/madsv2/forest/forest.cpp
+++ b/engines/mads/madsv2/forest/forest.cpp
@@ -53,6 +53,17 @@ namespace MADS {
namespace MADSV2 {
namespace Forest {
+ForestEngine *g_engine;
+
+ForestEngine::ForestEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
+ MADSV2Engine(syst, gameDesc) {
+ g_engine = this;
+}
+
+ForestEngine::~ForestEngine() {
+ g_engine = nullptr;
+}
+
Common::Error ForestEngine::run() {
initGraphics(320, 200);
_screen = new Graphics::Screen();
diff --git a/engines/mads/madsv2/forest/forest.h b/engines/mads/madsv2/forest/forest.h
index 6765d195a40..d012bd26022 100644
--- a/engines/mads/madsv2/forest/forest.h
+++ b/engines/mads/madsv2/forest/forest.h
@@ -23,6 +23,8 @@
#define MADS_FOREST_H
#include "mads/madsv2/engine.h"
+#include "mads/madsv2/forest/digi.h"
+#include "mads/madsv2/forest/midi.h"
namespace MADS {
namespace MADSV2 {
@@ -30,9 +32,11 @@ namespace Forest {
class ForestEngine : public MADSV2Engine {
public:
- ForestEngine(OSystem *syst, const MADSGameDescription *gameDesc) :
- MADSV2Engine(syst, gameDesc) {}
- ~ForestEngine() override {}
+ MidiPlayer _midiPlayer;
+
+public:
+ ForestEngine(OSystem *syst, const MADSGameDescription *gameDesc);
+ ~ForestEngine() override;
Common::Error run() override;
void syncRoom(Common::Serializer &s) override;
@@ -48,6 +52,8 @@ public:
void global_sound_driver() override;
};
+extern ForestEngine *g_engine;
+
} // namespace Forest
} // namespace MADSV2
} // namespace MADS
diff --git a/engines/mads/madsv2/forest/midi.cpp b/engines/mads/madsv2/forest/midi.cpp
index 6d5533bf289..2691ca8d5c7 100644
--- a/engines/mads/madsv2/forest/midi.cpp
+++ b/engines/mads/madsv2/forest/midi.cpp
@@ -20,25 +20,55 @@
*/
#include "common/textconsole.h"
+#include "audio/midiparser_smf.h"
#include "mads/madsv2/forest/midi.h"
#include "mads/madsv2/core/env.h"
-#include "mads/madsv2/engine.h"
+#include "mads/madsv2/forest/forest.h"
namespace MADS {
namespace MADSV2 {
namespace Forest {
-void midi_play(const char *name) {
- assert(env_exist(name));
+void MidiPlayer::send(uint32 b) {
+ //_driver->send(b);
+ Audio::MidiPlayer::send(b);
+}
+
+void MidiPlayer::play(const char *name) {
+ // Open up the MIDI file
+ Common::SeekableReadStream *f = env_open(name);
+ if (!f) {
+ warning("MIDI not found - %s", name);
+ return;
+ }
+
+#if 0
+ // Read in the file contents
+ size_t size = f->size();
+ byte *buf = (byte *)malloc(size);
+ f->read(buf, size);
+ delete f;
- // TODO
- warning("TODO: global_midi_play");
+ // Set up the parser
+ _parser = new MidiParser_SMF();
+ if (!_parser->loadMusic(buf, size))
+ error("midiPlay() couldn't load music resource");
- // TODO
+ _parser->setTrack(0);
+ _parser->setMidiDriver(this);
+ _parser->setTimerRate(_driver->getBaseTempo());
+#else
+ warning("TODO: Support hmi midi playback");
+ delete f;
+#endif
+}
+
+void midi_play(const char *name) {
+ g_engine->_midiPlayer.play(name);
}
void midi_stop() {
- // TODO
+ g_engine->_midiPlayer.stop();
}
} // namespace Forest
diff --git a/engines/mads/madsv2/forest/midi.h b/engines/mads/madsv2/forest/midi.h
index 508c7ec82ac..82a5e5d8b40 100644
--- a/engines/mads/madsv2/forest/midi.h
+++ b/engines/mads/madsv2/forest/midi.h
@@ -22,16 +22,27 @@
#ifndef MADS_FOREST_MIDI_H
#define MADS_FOREST_MIDI_H
-#include "common/scummsys.h"
+#include "audio/midiplayer.h"
namespace MADS {
namespace MADSV2 {
namespace Forest {
+class MidiPlayer : public Audio::MidiPlayer {
+private:
+ // MidiDriver_BASE interface implementation
+ void send(uint32 b) override;
+
+public:
+ MidiPlayer() : Audio::MidiPlayer() {}
+ ~MidiPlayer() override {}
+
+ void play(const char *name);
+};
+
extern void midi_play(const char *name);
extern void midi_stop();
-inline void midi_loop() {
-}
+inline void midi_loop() {}
} // namespace Forest
} // namespace MADSV2
More information about the Scummvm-git-logs
mailing list