feat: replace DSSound slot 5 (set_pan) with Rust
Browse filesPan uses the same VOLUME_DB_TABLE read backwards β index 0 from the end
gives near-0 dB (no attenuation), larger indices give more attenuation.
Positive pan negates the dB value for right-channel bias.
20/24 DSSound vtable slots now Rust.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-core/src/audio/dssound.rs
CHANGED
|
@@ -287,6 +287,42 @@ pub unsafe extern "thiscall" fn set_master_volume(
|
|
| 287 |
1
|
| 288 |
}
|
| 289 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 290 |
/// Slot 8: set_channel_volume β sets volume on a specific channel.
|
| 291 |
/// `pool_id` is 1-based (1..64). `volume` is Fixed 16.16 (0..0x10000).
|
| 292 |
pub unsafe extern "thiscall" fn set_channel_volume(
|
|
|
|
| 287 |
1
|
| 288 |
}
|
| 289 |
|
| 290 |
+
/// Slot 5: set_pan β sets stereo panning on a specific channel.
|
| 291 |
+
/// `pool_id` is 1-based (1..64). `pan` is Fixed 16.16 (-0x10000..0x10000).
|
| 292 |
+
/// Negative = left, positive = right.
|
| 293 |
+
pub unsafe extern "thiscall" fn set_pan(
|
| 294 |
+
this: *mut DSSound, pool_id: i32, pan: i32,
|
| 295 |
+
) -> u32 {
|
| 296 |
+
let idx = (pool_id - 1) as usize;
|
| 297 |
+
if idx >= 64 {
|
| 298 |
+
return 0;
|
| 299 |
+
}
|
| 300 |
+
let snd = &*this;
|
| 301 |
+
let desc_idx = snd.buffer_pool_shadow[idx];
|
| 302 |
+
if desc_idx < 0 || desc_idx as usize >= 8 {
|
| 303 |
+
return 0;
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
+
// Clamp pan to [-0x10000, 0x10000].
|
| 307 |
+
let pan = pan.max(-0x10000).min(0x10000);
|
| 308 |
+
|
| 309 |
+
// Index into table backwards: abs(pan) >> 10 gives 0..63.
|
| 310 |
+
// Table is read from the END (index 63 = near silence, index 0 = full).
|
| 311 |
+
let table_idx = ((pan.unsigned_abs() >> 10) as usize).min(63);
|
| 312 |
+
let mut db = VOLUME_DB_TABLE[63 - table_idx] as i32;
|
| 313 |
+
|
| 314 |
+
// Positive pan β negate (right channel louder = negative pan dB for left).
|
| 315 |
+
if pan > 0 {
|
| 316 |
+
db = -db;
|
| 317 |
+
}
|
| 318 |
+
|
| 319 |
+
if let Some(buf) = snd.channel_descs[desc_idx as usize].buffer() {
|
| 320 |
+
let _ = buf.SetPan(db);
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
1
|
| 324 |
+
}
|
| 325 |
+
|
| 326 |
/// Slot 8: set_channel_volume β sets volume on a specific channel.
|
| 327 |
/// `pool_id` is 1-based (1..64). `volume` is Fixed 16.16 (0..0x10000).
|
| 328 |
pub unsafe extern "thiscall" fn set_channel_volume(
|
crates/openwa-core/src/audio/mod.rs
CHANGED
|
@@ -10,7 +10,7 @@ pub use dssound::{DSSound, DSSoundVtable, ChannelDescriptor};
|
|
| 10 |
pub use dssound::{
|
| 11 |
update_channels, release_finished,
|
| 12 |
is_slot_loaded, is_channel_finished, stop_channel,
|
| 13 |
-
set_master_volume, set_channel_volume,
|
| 14 |
sub_destructor as dssound_sub_destructor, load_wav,
|
| 15 |
noop as dssound_noop, returns_0 as dssound_returns_0, returns_1 as dssound_returns_1,
|
| 16 |
};
|
|
|
|
| 10 |
pub use dssound::{
|
| 11 |
update_channels, release_finished,
|
| 12 |
is_slot_loaded, is_channel_finished, stop_channel,
|
| 13 |
+
set_master_volume, set_channel_volume, set_pan,
|
| 14 |
sub_destructor as dssound_sub_destructor, load_wav,
|
| 15 |
noop as dssound_noop, returns_0 as dssound_returns_0, returns_1 as dssound_returns_1,
|
| 16 |
};
|
crates/openwa-wormkit/src/replacements/sound.rs
CHANGED
|
@@ -170,7 +170,7 @@ unsafe fn patch_dssound_vtable() -> Result<(), String> {
|
|
| 170 |
use openwa_core::audio::{
|
| 171 |
update_channels, release_finished,
|
| 172 |
is_slot_loaded, is_channel_finished, stop_channel,
|
| 173 |
-
set_master_volume, set_channel_volume, dssound_sub_destructor,
|
| 174 |
load_wav, dssound_noop, dssound_returns_0, dssound_returns_1,
|
| 175 |
};
|
| 176 |
|
|
@@ -192,6 +192,9 @@ unsafe fn patch_dssound_vtable() -> Result<(), String> {
|
|
| 192 |
// Slot 11: release_finished β like update_channels, returns count
|
| 193 |
*vt.add(11) = release_finished as *const () as u32;
|
| 194 |
|
|
|
|
|
|
|
|
|
|
| 195 |
// Slot 9: is_channel_finished β returns 0 if playing, 1 if stopped/free
|
| 196 |
*vt.add(9) = is_channel_finished as *const () as u32;
|
| 197 |
|
|
@@ -216,6 +219,6 @@ unsafe fn patch_dssound_vtable() -> Result<(), String> {
|
|
| 216 |
// Trivial returns-1 (slot 23)
|
| 217 |
*vt.add(23) = dssound_returns_1 as *const () as u32;
|
| 218 |
|
| 219 |
-
let _ = log_line("[Sound] DSSound vtable: patched
|
| 220 |
}).map_err(|e| e.to_string())
|
| 221 |
}
|
|
|
|
| 170 |
use openwa_core::audio::{
|
| 171 |
update_channels, release_finished,
|
| 172 |
is_slot_loaded, is_channel_finished, stop_channel,
|
| 173 |
+
set_master_volume, set_channel_volume, set_pan, dssound_sub_destructor,
|
| 174 |
load_wav, dssound_noop, dssound_returns_0, dssound_returns_1,
|
| 175 |
};
|
| 176 |
|
|
|
|
| 192 |
// Slot 11: release_finished β like update_channels, returns count
|
| 193 |
*vt.add(11) = release_finished as *const () as u32;
|
| 194 |
|
| 195 |
+
// Slot 5: set_pan β stereo panning with dB lookup
|
| 196 |
+
*vt.add(5) = set_pan as *const () as u32;
|
| 197 |
+
|
| 198 |
// Slot 9: is_channel_finished β returns 0 if playing, 1 if stopped/free
|
| 199 |
*vt.add(9) = is_channel_finished as *const () as u32;
|
| 200 |
|
|
|
|
| 219 |
// Trivial returns-1 (slot 23)
|
| 220 |
*vt.add(23) = dssound_returns_1 as *const () as u32;
|
| 221 |
|
| 222 |
+
let _ = log_line("[Sound] DSSound vtable: patched 20/24 slots with Rust");
|
| 223 |
}).map_err(|e| e.to_string())
|
| 224 |
}
|