paavohtl Claude Opus 4.6 (1M context) commited on
Commit
08bd011
·
1 Parent(s): f25f79c

fix: correct play_sound param order and descriptor state

Browse files

Careful 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
- pitch: i32,
 
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} pitch={pitch} pan={pan} pri={priority}"
489
  ));
490
 
491
  // Get the template buffer from channel_slots.
@@ -504,13 +505,11 @@ unsafe fn core_play_sound(
504
  }
505
  };
506
 
507
- // Clamp pan only — pitch can exceed 0x10000 (higher pitch).
508
- let pan = pan.max(-0x10000).min(0x10000);
509
 
510
- // Compute per-channel volume: pitch * 3/4, clamped to [0, 0x10000].
511
- // The original uses the same param for both volume and frequency.
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: pitch * base_freq >> 16 (fixed-point multiply).
524
- // Pitch > 0x10000 means higher than normal pitch.
525
  let base_freq = template_buf.GetFrequency().unwrap_or(22050) as i32;
526
- let channel_freq = ((pitch.max(0) as i64 * base_freq as i64) >> 16) as i32;
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} (ch_freq={channel_freq}) loop={loop_flag}"
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 calculation (same as set_pan).
559
- let pan_idx = ((pan.unsigned_abs() >> 10) as usize).min(63);
 
560
  let mut pan_db = VOLUME_DB_TABLE[63 - pan_idx] as i32;
561
- if pan > 0 { pan_db = -pan_db; }
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, pitch, pan, unused.
620
  pub unsafe extern "thiscall" fn play_sound(
621
- this: *mut DSSound, flags_and_slot: u32, priority: i32, pitch: i32, pan: i32, _p5: u32,
622
  ) -> bool {
623
  let snd = &mut *this;
624
- // Clear bit 0x10000 (loop flag is stripped by slot 3).
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, pitch: i32, pan: i32, _p5: u32,
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, pitch, pan);
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
  }