fix: correct play_sound param order and descriptor state
Browse filesCareful stack offset tracing reveals the 5 params to play_sound are:
(flags_and_slot, priority, frequency, volume, pan) — frequency and
volume are separate params, not a single dual-purpose value.
Fix descriptor state: flags_b stores flags_and_slot (identifies which
sound is playing), not -1. flags_a is -1 (marks buffer for auto-release
when finished).
Remove naked asm trampolines — pure thiscall confirmed.
All 24/24 DSSound vtable slots Rust with correct params.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
crates/openwa-core/src/audio/dssound.rs
CHANGED
|
@@ -456,7 +456,8 @@ unsafe fn core_play_sound(
|
|
| 456 |
snd: &mut DSSound,
|
| 457 |
flags_and_slot: u32,
|
| 458 |
priority: i32,
|
| 459 |
-
|
|
|
|
| 460 |
pan: i32,
|
| 461 |
) -> i32 {
|
| 462 |
use crate::log::log_line;
|
|
@@ -485,7 +486,7 @@ unsafe fn core_play_sound(
|
|
| 485 |
}
|
| 486 |
let di = desc_idx as usize;
|
| 487 |
let _ = log_line(&format!(
|
| 488 |
-
"[DSSound] core_play: slot={slot_idx} desc={di} flags=0x{flags_and_slot:X}
|
| 489 |
));
|
| 490 |
|
| 491 |
// Get the template buffer from channel_slots.
|
|
@@ -504,13 +505,11 @@ unsafe fn core_play_sound(
|
|
| 504 |
}
|
| 505 |
};
|
| 506 |
|
| 507 |
-
// Clamp
|
| 508 |
-
let
|
| 509 |
|
| 510 |
-
// Compute per-channel volume:
|
| 511 |
-
|
| 512 |
-
let vol_clamped = pitch.max(0).min(0x10000);
|
| 513 |
-
let vol_scaled = (vol_clamped * 3 + (((vol_clamped * 3) >> 31) & 3)) >> 2;
|
| 514 |
|
| 515 |
// Compute dB for volume.
|
| 516 |
let vol_db = if flags_and_slot & 0x20000 != 0 {
|
|
@@ -520,15 +519,14 @@ unsafe fn core_play_sound(
|
|
| 520 |
volume_to_db(combined)
|
| 521 |
};
|
| 522 |
|
| 523 |
-
// Compute channel_freq:
|
| 524 |
-
// Pitch > 0x10000 means higher than normal pitch.
|
| 525 |
let base_freq = template_buf.GetFrequency().unwrap_or(22050) as i32;
|
| 526 |
-
let channel_freq = ((
|
| 527 |
|
| 528 |
// Store descriptor state.
|
| 529 |
let desc = &mut snd.channel_descs[di];
|
| 530 |
-
desc._field_00 = flags_and_slot;
|
| 531 |
desc.flags_a = -1;
|
|
|
|
| 532 |
desc.channel_freq = channel_freq;
|
| 533 |
desc.channel_volume = vol_scaled;
|
| 534 |
desc.ds_buffer = core::mem::transmute_copy(&new_buf);
|
|
@@ -543,7 +541,7 @@ unsafe fn core_play_sound(
|
|
| 543 |
};
|
| 544 |
|
| 545 |
let _ = log_line(&format!(
|
| 546 |
-
"[DSSound] core_play: vol_db={vol_db} freq={freq}
|
| 547 |
));
|
| 548 |
|
| 549 |
// Apply volume, frequency, pan to the new buffer.
|
|
@@ -555,11 +553,12 @@ unsafe fn core_play_sound(
|
|
| 555 |
let _ = log_line("[DSSound] core_play: SetVolume");
|
| 556 |
let _ = buf.SetVolume(vol_db);
|
| 557 |
|
| 558 |
-
// Pan
|
| 559 |
-
let
|
|
|
|
| 560 |
let mut pan_db = VOLUME_DB_TABLE[63 - pan_idx] as i32;
|
| 561 |
-
if
|
| 562 |
-
let _ = log_line(&format!("[DSSound] core_play: SetPan({pan_db})"));
|
| 563 |
let _ = buf.SetPan(pan_db);
|
| 564 |
|
| 565 |
// Start playback.
|
|
@@ -616,20 +615,19 @@ unsafe fn allocate_channel(snd: &mut DSSound, priority: i32) -> i32 {
|
|
| 616 |
}
|
| 617 |
|
| 618 |
/// Slot 3: play_sound — pure thiscall with 5 stack params, RET 0x14.
|
| 619 |
-
/// Params: flags_and_slot, priority,
|
| 620 |
pub unsafe extern "thiscall" fn play_sound(
|
| 621 |
-
this: *mut DSSound, flags_and_slot: u32, priority: i32,
|
| 622 |
) -> bool {
|
| 623 |
let snd = &mut *this;
|
| 624 |
-
|
| 625 |
-
let result = core_play_sound(snd, flags_and_slot & 0xFFFEFFFF, priority, pitch, pan);
|
| 626 |
result >= 0
|
| 627 |
}
|
| 628 |
|
| 629 |
/// Slot 4: play_sound_pooled — pure thiscall with 5 stack params, RET 0x14.
|
| 630 |
/// Returns pool_id (1-based) on success, 0 on failure.
|
| 631 |
pub unsafe extern "thiscall" fn play_sound_pooled(
|
| 632 |
-
this: *mut DSSound, flags_and_slot: u32, priority: i32,
|
| 633 |
) -> i32 {
|
| 634 |
let snd = &mut *this;
|
| 635 |
|
|
@@ -638,7 +636,7 @@ pub unsafe extern "thiscall" fn play_sound_pooled(
|
|
| 638 |
return 0;
|
| 639 |
}
|
| 640 |
|
| 641 |
-
let desc_idx = core_play_sound(snd, flags_and_slot, priority,
|
| 642 |
if desc_idx < 0 {
|
| 643 |
return 0;
|
| 644 |
}
|
|
|
|
| 456 |
snd: &mut DSSound,
|
| 457 |
flags_and_slot: u32,
|
| 458 |
priority: i32,
|
| 459 |
+
frequency: i32,
|
| 460 |
+
volume: i32,
|
| 461 |
pan: i32,
|
| 462 |
) -> i32 {
|
| 463 |
use crate::log::log_line;
|
|
|
|
| 486 |
}
|
| 487 |
let di = desc_idx as usize;
|
| 488 |
let _ = log_line(&format!(
|
| 489 |
+
"[DSSound] core_play: slot={slot_idx} desc={di} flags=0x{flags_and_slot:X} freq={frequency} vol={volume} pan={pan} pri={priority}"
|
| 490 |
));
|
| 491 |
|
| 492 |
// Get the template buffer from channel_slots.
|
|
|
|
| 505 |
}
|
| 506 |
};
|
| 507 |
|
| 508 |
+
// Clamp volume to [0, 0x10000].
|
| 509 |
+
let vol = volume.max(0).min(0x10000);
|
| 510 |
|
| 511 |
+
// Compute per-channel volume: vol * 3/4.
|
| 512 |
+
let vol_scaled = (vol * 3 + (((vol * 3) >> 31) & 3)) >> 2;
|
|
|
|
|
|
|
| 513 |
|
| 514 |
// Compute dB for volume.
|
| 515 |
let vol_db = if flags_and_slot & 0x20000 != 0 {
|
|
|
|
| 519 |
volume_to_db(combined)
|
| 520 |
};
|
| 521 |
|
| 522 |
+
// Compute channel_freq: frequency * base_freq >> 16 (fixed-point multiply).
|
|
|
|
| 523 |
let base_freq = template_buf.GetFrequency().unwrap_or(22050) as i32;
|
| 524 |
+
let channel_freq = ((frequency.max(0) as i64 * base_freq as i64) >> 16) as i32;
|
| 525 |
|
| 526 |
// Store descriptor state.
|
| 527 |
let desc = &mut snd.channel_descs[di];
|
|
|
|
| 528 |
desc.flags_a = -1;
|
| 529 |
+
desc.flags_b = flags_and_slot as i32;
|
| 530 |
desc.channel_freq = channel_freq;
|
| 531 |
desc.channel_volume = vol_scaled;
|
| 532 |
desc.ds_buffer = core::mem::transmute_copy(&new_buf);
|
|
|
|
| 541 |
};
|
| 542 |
|
| 543 |
let _ = log_line(&format!(
|
| 544 |
+
"[DSSound] core_play: vol_db={vol_db} vol_scaled={vol_scaled} freq={freq} ch_freq={channel_freq} base={base_freq} loop={loop_flag}"
|
| 545 |
));
|
| 546 |
|
| 547 |
// Apply volume, frequency, pan to the new buffer.
|
|
|
|
| 553 |
let _ = log_line("[DSSound] core_play: SetVolume");
|
| 554 |
let _ = buf.SetVolume(vol_db);
|
| 555 |
|
| 556 |
+
// Pan from the 4th stack param.
|
| 557 |
+
let pan_clamped = pan.max(-0x10000).min(0x10000);
|
| 558 |
+
let pan_idx = ((pan_clamped.unsigned_abs() >> 10) as usize).min(63);
|
| 559 |
let mut pan_db = VOLUME_DB_TABLE[63 - pan_idx] as i32;
|
| 560 |
+
if pan_clamped > 0 { pan_db = -pan_db; }
|
| 561 |
+
let _ = log_line(&format!("[DSSound] core_play: SetPan({pan_db}) from pan={pan}"));
|
| 562 |
let _ = buf.SetPan(pan_db);
|
| 563 |
|
| 564 |
// Start playback.
|
|
|
|
| 615 |
}
|
| 616 |
|
| 617 |
/// Slot 3: play_sound — pure thiscall with 5 stack params, RET 0x14.
|
| 618 |
+
/// Params: flags_and_slot, priority, frequency, volume, pan.
|
| 619 |
pub unsafe extern "thiscall" fn play_sound(
|
| 620 |
+
this: *mut DSSound, flags_and_slot: u32, priority: i32, frequency: i32, volume: i32, pan: i32,
|
| 621 |
) -> bool {
|
| 622 |
let snd = &mut *this;
|
| 623 |
+
let result = core_play_sound(snd, flags_and_slot & 0xFFFEFFFF, priority, frequency, volume, pan);
|
|
|
|
| 624 |
result >= 0
|
| 625 |
}
|
| 626 |
|
| 627 |
/// Slot 4: play_sound_pooled — pure thiscall with 5 stack params, RET 0x14.
|
| 628 |
/// Returns pool_id (1-based) on success, 0 on failure.
|
| 629 |
pub unsafe extern "thiscall" fn play_sound_pooled(
|
| 630 |
+
this: *mut DSSound, flags_and_slot: u32, priority: i32, frequency: i32, volume: i32, pan: i32,
|
| 631 |
) -> i32 {
|
| 632 |
let snd = &mut *this;
|
| 633 |
|
|
|
|
| 636 |
return 0;
|
| 637 |
}
|
| 638 |
|
| 639 |
+
let desc_idx = core_play_sound(snd, flags_and_slot, priority, frequency, volume, pan);
|
| 640 |
if desc_idx < 0 {
|
| 641 |
return 0;
|
| 642 |
}
|