From a02b6c7a3852521d0a73826c1f2df3c15ecd3646 Mon Sep 17 00:00:00 2001 From: escape209 Date: Sun, 9 Aug 2026 14:06:08 +0100 Subject: [PATCH 01/11] iSnd work: Part 2 --- src/SB/Core/gc/iSnd.cpp | 54 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/SB/Core/gc/iSnd.cpp b/src/SB/Core/gc/iSnd.cpp index a5ecbc1f0..7d5e952e6 100644 --- a/src/SB/Core/gc/iSnd.cpp +++ b/src/SB/Core/gc/iSnd.cpp @@ -675,6 +675,56 @@ bool iSndIsPlayingByHandle(U32 handle) return false; } +void iSndStop(U32 snd) +{ + if (snd == 0) + { + return; + } + + U32 enabled = OSDisableInterrupts(); + S32 i; + + for (i = 0; i < 64; i++) + { + if (gSnd.voice[i].sndID == snd) + { + gSnd.voice[i].sndID = 0; + gSnd.voice[i].flags = 0; + break; + } + } + + if (i < 6) + { + if (streams[i].vinf.voice != NULL) + { + DVDCancel(&streams[i].fileInfo.cb); + ARQRemoveRequest(&streams[i].request); + AXSetVoiceState(streams[i].vinf.voice, 0); + MIXReleaseChannel(streams[i].vinf.voice); + iSndMyAXFree(&streams[i].vinf.voice); + streams[i].vinf.flags = 0x40000; + streams[i].vinf.aid = 0; + streams[i].vinf.flags = 0x40000; + } + } + else if (i < 64) + { + i -= 6; + if (voices[i].voice != NULL) + { + AXSetVoiceState(voices[i].voice, 0); + MIXReleaseChannel(voices[i].voice); + iSndMyAXFree(&voices[i].voice); + voices[i].flags = 0; + voices[i].aid = 0; + } + } + + OSRestoreInterrupts(enabled); +} + U32 iVolFromX(F32 param1) { float f = MAX(param1, 1e-20f); @@ -865,7 +915,7 @@ void sndloadcb(tag_xFile* tag) { SoundFlags = 0; } -/* Matching + void iSndDIEDIEDIE() { if (!soundInited) @@ -903,7 +953,7 @@ void iSndDIEDIEDIE() AXQuit(); } -*/ + void iSndSetExternalCallback(iSndExternalCallback callback) { } From 5ee818fd383a99c9f018fbe45c24566f05b711a8 Mon Sep 17 00:00:00 2001 From: escape209 Date: Mon, 10 Aug 2026 08:32:59 +0100 Subject: [PATCH 02/11] Match fcb --- src/SB/Core/gc/iSnd.cpp | 64 +++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 28 deletions(-) diff --git a/src/SB/Core/gc/iSnd.cpp b/src/SB/Core/gc/iSnd.cpp index 7d5e952e6..3ada097a6 100644 --- a/src/SB/Core/gc/iSnd.cpp +++ b/src/SB/Core/gc/iSnd.cpp @@ -63,8 +63,8 @@ vinfo voices[58]; U32* ua_stream_buffer = NULL; //unaligned stream buffer U32* stream_buffer = 0; u32 silence_buffer = 0; -volatile u32 zero_point = 0; -volatile u32 zero_end = 0; +volatile U32 zero_point = 0; +volatile U32 zero_end = 0; volatile U32 SoundFlags = 0; volatile S32 fc = 0; static char soundInited = 0; @@ -276,34 +276,46 @@ static void iSndMyAXFree(AXVPB**); static void fcb() { + S32 i; + S32 need_update; + U32 orig_flags; + U32 length; + U32 source; + U32 flags_bit_12; + U32 flags_bit_10; + U32 flags_bit_13; + U32 flags_bit_9; + U32 dest; + u32 addr; + xSndVoiceInfo* gsnd_voice; + if (!soundInited && iTRCDisk::IsDiskIDed()) { return; } fc++; - S32 i; - S32 need_update = TRUE; + need_update = FALSE; for (i = 0; i < 6; i++) { - xSndVoiceInfo* gsnd_voice = &gSnd.voice[i]; - U32 orig_flags = streams[i].vinf.flags; + orig_flags = streams[i].vinf.flags; + gsnd_voice = &gSnd.voice[i]; if (streams[i].vinf.voice == NULL) { continue; } - u16 addrHi = streams[i].vinf.voice->pb.addr.currentAddressHi; + U32 addrHi = streams[i].vinf.voice->pb.addr.currentAddressHi; if (orig_flags & 0xe0006) { continue; } - u32 addr = addrHi << 16; + addr = (addrHi << 16); addr += streams[i].vinf.voice->pb.addr.currentAddressLo; - U32 dest = streams[i].dest_b; + dest = streams[i].dest_b; dump_flags(orig_flags); - if (dest * 2 < addr && (orig_flags & 0x4000) == 0 && (orig_flags & 0x8) == 0) + if ((addr < dest * 2) && (orig_flags & 0x4000) == 0 && (orig_flags & 0x8) == 0) { streams[i].vinf.flags |= 0x4000; streams[i].vinf.flags &= ~0x8000; @@ -315,7 +327,7 @@ static void fcb() streams[i].x94 = streams[i].x90; orig_flags = streams[i].vinf.flags; } - else if (dest * 2 >= addr && (orig_flags & 0x8000) == 0) + else if ((addr >= dest * 2) && (orig_flags & 0x8000) == 0) { streams[i].vinf.flags |= 0x8000; streams[i].vinf.flags &= ~0x4000; @@ -330,8 +342,9 @@ static void fcb() if ((orig_flags & 0x20) && (orig_flags & 0x4000)) { streams[i].vinf.flags &= ~0x20; - dest = streams[i].dest_a * 2; - dest += streams[i].x24 & 0xFFFF; + U32 dest = streams[i].dest_a; + dest <<= 1; + dest += (streams[i].x24 & 0xFFFF); AXSetVoiceLoopAddr(streams[i].vinf.voice, zero_point); AXSetVoiceEndAddr(streams[i].vinf.voice, dest - 1); AXSetVoiceLoop(streams[i].vinf.voice, 0); @@ -350,7 +363,7 @@ static void fcb() continue; } - if (dest >= zero_point && dest < zero_end && (orig_flags & 0x40)) + if (addr >= zero_point && addr < zero_end && (orig_flags & 0x40)) { streams[i].vinf.flags &= ~0x40; DVDCancelAsync(&streams[i].fileInfo.cb, NULL); @@ -360,14 +373,14 @@ static void fcb() if (streams[i].vinf.flags & 0x10000) { - u32 priority = gsnd_voice->priority; + U32 priority = gsnd_voice->priority; if (priority > 0xff) { priority = 0xff; } iSndMyAXFree(&streams[i].vinf.voice); - streams[i].vinf.voice = AXAcquireVoice(priority, dv_callback, i); + streams[i].vinf.voice = AXAcquireVoice(priority >> 3, dv_callback, i); if (streams[i].vinf.voice == NULL) { streams[i].vinf.voice = NULL; @@ -423,8 +436,6 @@ static void fcb() } if ((orig_flags & 0x800) || (orig_flags & 0x4000000)) { - U32 length; - U32 source; if (orig_flags & 0x800) { length = 0x4000; @@ -440,10 +451,6 @@ static void fcb() source = streams[i].source_b; } - U32 flags_bit_12; - U32 flags_bit_10; - U32 flags_bit_13; - U32 flags_bit_9; flags_bit_9 = orig_flags & 0x200; flags_bit_12 = orig_flags & 0x1000; flags_bit_10 = orig_flags & 0x400; @@ -453,13 +460,13 @@ static void fcb() if (flags_bit_12 && (orig_flags & 0x4000) && !flags_bit_10 && !flags_bit_13) { streams[i].vinf.flags |= 0x400; - ARQPostRequest(&streams[i].request, (u32)streams[i].vinf.voice, 0, 1, source, + ARQPostRequest(&streams[i].request, (u32)&streams[i], 0, 1, source, streams[i].dest_b, length, arqcb); } else if (flags_bit_13 && (orig_flags & 0x8000) && !flags_bit_9 && !flags_bit_12) { streams[i].vinf.flags |= 0x200; - ARQPostRequest(&streams[i].request, (u32)streams[i].vinf.voice, 0, 1, source, + ARQPostRequest(&streams[i].request, (u32)&streams[i], 0, 1, source, streams[i].dest_a, length, arqcb); } } @@ -478,7 +485,7 @@ static void fcb() need_update = TRUE; } - for (i = 0; i < 58; i++) + for (S32 i = 0; i < 58; i++) { if (voices[i].voice == NULL || (voices[i].flags & 0x1)) { @@ -493,8 +500,9 @@ static void fcb() } else { - U32 addr = (voices[i].voice->pb.addr.currentAddressHi << 16) + - voices[i].voice->pb.addr.currentAddressLo; + addr = voices[i].voice->pb.addr.currentAddressHi; + addr <<= 16; + addr += voices[i].voice->pb.addr.currentAddressLo; if (voices[i].flags & 0x4 && !voices[i].voice->pb.addr.loopFlag && addr >= zero_point && addr < zero_end) { @@ -721,7 +729,7 @@ void iSndStop(U32 snd) voices[i].aid = 0; } } - + OSRestoreInterrupts(enabled); } From 8d927884374c5a6278df47f1623642306ed8a3dc Mon Sep 17 00:00:00 2001 From: escape209 Date: Mon, 10 Aug 2026 15:16:49 +0100 Subject: [PATCH 03/11] Add powf definition to cmath --- .../include/PowerPC_EABI_Support/MSL_C/MSL_Common/cmath | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/PowerPC_EABI_Support/include/PowerPC_EABI_Support/MSL_C/MSL_Common/cmath b/src/PowerPC_EABI_Support/include/PowerPC_EABI_Support/MSL_C/MSL_Common/cmath index 70e0fd02a..acb3e6f50 100644 --- a/src/PowerPC_EABI_Support/include/PowerPC_EABI_Support/MSL_C/MSL_Common/cmath +++ b/src/PowerPC_EABI_Support/include/PowerPC_EABI_Support/MSL_C/MSL_Common/cmath @@ -9,6 +9,7 @@ namespace std #ifndef INLINE float atan2f(float y, float x); + float powf(float x, float y); float atan(float x); float sinf(float x); float cosf(float x); @@ -26,6 +27,11 @@ namespace std return (float)atan2((double)y, (double)x); } + inline float powf(float y, float x) + { + return (float)powf((double)y, (double)x); + } + inline float atan(float x) { return (float)atan((double)x); From 453f97ae689901f5b8db669833ee8bd23ac7f8a5 Mon Sep 17 00:00:00 2001 From: escape209 Date: Mon, 10 Aug 2026 15:17:10 +0100 Subject: [PATCH 04/11] Match iSndSetPitch --- src/SB/Core/gc/iSnd.cpp | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/SB/Core/gc/iSnd.cpp b/src/SB/Core/gc/iSnd.cpp index 3ada097a6..c6efafb91 100644 --- a/src/SB/Core/gc/iSnd.cpp +++ b/src/SB/Core/gc/iSnd.cpp @@ -18,6 +18,8 @@ #include #include +#include + u32 aram_array[40]; // Size: 0x20 @@ -861,6 +863,37 @@ void iSndSetVol(U32 snd, F32 vol) } } +void iSndSetPitch(U32 snd, F32 pitch) +{ + xSndVoiceInfo* vp = &gSnd.voice[0]; + + S32 i = 0; + for (; i < 64; i++, vp++) + { + if (vp->sndID == snd) + break; + } + + if (i != 64) + { + vinfo* info; + if (i < 6) + { + info = &streams[i].vinf; + } + else + { + info = &voices[i - 6]; + } + if (info->voice != 0) + { + // todo: define std::powf + AXSetVoiceSrcRatio(info->voice, ((1.0f / 32000) * vp->sample_rate) * + std::powf(2.0f, (pitch / 12.0f))); + } + } +} + void iSndStartStereo(U32 id1, U32 id2, F32 pitch) { } From 35bfdcfc7db44e4b6c237b78e33fad5d9ca7a865 Mon Sep 17 00:00:00 2001 From: escape209 Date: Fri, 21 Aug 2026 18:54:28 +0100 Subject: [PATCH 05/11] Match iSndUpdate --- src/SB/Core/gc/iSnd.cpp | 59 +++++++++++++++++++++++++++++++++++++++++ src/SB/Core/gc/iSnd.h | 1 + 2 files changed, 60 insertions(+) diff --git a/src/SB/Core/gc/iSnd.cpp b/src/SB/Core/gc/iSnd.cpp index c6efafb91..3de6ee7b4 100644 --- a/src/SB/Core/gc/iSnd.cpp +++ b/src/SB/Core/gc/iSnd.cpp @@ -794,6 +794,65 @@ void iSndUpdateSounds() } } +void iSndUpdate() +{ + bool active; + _AXVPB* v; + U32 flags; + xSndVoiceInfo* vp; + S32 testBuffer; + + if (!soundInited) + { + return; + } + + S32 enabled = OSDisableInterrupts(); + iSndUpdateStreams(); + iSndUpdateSounds(); + MIXUpdateSettings(); + OSRestoreInterrupts(enabled); + + for (S32 i = 0; i < 0x40; i++) + { + vp = &gSnd.voice[i]; + + if (i < 6) + { + active = (streams[i].vinf.flags & 0xc07f); + } + else + { + v = voices[i - 6].voice; + testBuffer = 0; + if (v != NULL) + { + testBuffer = v->pb.addr.currentAddressHi; + testBuffer <<= 16; + testBuffer += v->pb.addr.currentAddressLo; + } + flags = voices[i - 6].flags; + active = 0; + if ((flags & 4) && !(flags & 8)) + { + if ((testBuffer >= zero_point) && (testBuffer < zero_end)) + { + active = 1; + } + } + active |= (bool)v; + } + if (active) + { + vp->flags |= 1; + } + else + { + vp->flags &= 0xfffffffe; + } + } +} + S32 iSndPlay(xSndVoiceInfo* vp) { S32 offset = (S32)vp - (S32)gSnd.voice; diff --git a/src/SB/Core/gc/iSnd.h b/src/SB/Core/gc/iSnd.h index c658a8e88..950a59912 100644 --- a/src/SB/Core/gc/iSnd.h +++ b/src/SB/Core/gc/iSnd.h @@ -75,6 +75,7 @@ iSndFileInfo* iSndLookup(U32 id); void iSndPause(U32 snd, U32 pause); void iSndStop(U32 snd); void iSndUpdate(); +void iSndUpdateStreams(); void iSndFindFreeVoice(U32 priority, U32 flags, U32 owner); From 6c6788282d70c9cf6cc1650c68b7623867e25484 Mon Sep 17 00:00:00 2001 From: escape209 Date: Sat, 22 Aug 2026 17:30:07 +0100 Subject: [PATCH 06/11] Match iSndPause --- src/SB/Core/gc/iSnd.cpp | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/SB/Core/gc/iSnd.cpp b/src/SB/Core/gc/iSnd.cpp index 3de6ee7b4..cbb848387 100644 --- a/src/SB/Core/gc/iSnd.cpp +++ b/src/SB/Core/gc/iSnd.cpp @@ -685,6 +685,61 @@ bool iSndIsPlayingByHandle(U32 handle) return false; } +void iSndPause(U32 snd, U32 pause) +{ + if (!soundInited) + { + return; + } + + S32 i; + for (i = 0; i < 64; i++) + { + if (gSnd.voice[i].sndID == snd) + { + break; + } + } + + if (i < 6) + { + if (streams[i].vinf.voice != NULL) + { + if (pause != 0) + { + AXSetVoiceState(streams[i].vinf.voice, 0); + streams[i].vinf.flags |= 2; + } + else + { + AXSetVoiceState(streams[i].vinf.voice, 1); + streams[i].vinf.flags &= 0xFFFFFFFD; + } + } + } + else if (i >= 64) + { + return; + } + else + { + S32 iv = i - 6; + if (voices[iv].voice != NULL) + { + if (pause != 0) + { + AXSetVoiceState(voices[iv].voice, 0); + voices[iv].flags |= 8; + } + else + { + AXSetVoiceState(voices[iv].voice, 1); + voices[iv].flags &= 0xFFFFFFF7; + } + } + } +} + void iSndStop(U32 snd) { if (snd == 0) From 5f33c5ac71b0934981969f64b450ce955a39bfe1 Mon Sep 17 00:00:00 2001 From: escape209 Date: Sun, 23 Aug 2026 12:51:08 +0100 Subject: [PATCH 07/11] Match iSndCalcVol3d --- src/SB/Core/gc/iSnd.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/SB/Core/gc/iSnd.cpp b/src/SB/Core/gc/iSnd.cpp index cbb848387..30dcfe143 100644 --- a/src/SB/Core/gc/iSnd.cpp +++ b/src/SB/Core/gc/iSnd.cpp @@ -819,6 +819,44 @@ void iSndCalcVol(xSndVoiceInfo* vp, vinfo* info) MIXAdjustPan(info->voice, 0x40 - MIXGetPan(info->voice)); } +void iSndCalcVol3d(xSndVoiceInfo* vp, vinfo* vi) +{ + xVec3 pos; + xVec3Sub(&pos, &vp->playPos, &gSnd.pos); + F32 dist = xVec3Length2(&pos); + xVec3Normalize(&pos, &pos); + F32 right = xVec3Dot(&pos, &gSnd.right); + if (dist > vp->outerRadius2) + { + dist = 0.0f; + } + else if (dist <= vp->innerRadius2) + { + dist = 1.0f; + } + else + { + F32 range = vp->outerRadius2 - vp->innerRadius2; + dist = std::sqrtf((range - (dist - vp->innerRadius2)) / range); + } + S32 pan = (S32)(right * 64.0f) + 0x40; + S32 vol = iVolFromX(dist * (vp->vol * gSnd.categoryVolFader[vp->category])); + if (pan < 0) + { + pan = 0; + } + else if (pan > 0x7F) + { + pan = 0x7F; + } + vi->x10 = vol; + vi->x14 = vol; + vi->x18 = pan; + vi->x1c = pan; + MIXAdjustFader(vi->voice, vol - MIXGetFader(vi->voice)); + MIXAdjustPan(vi->voice, pan - MIXGetPan(vi->voice)); +} + void iSndVolUpdate(xSndVoiceInfo* info, vinfo* vinfo) { MIXUnMute(vinfo->voice); From 8d6fc4fb7f649887a7280ef87d9719fc0ddad7fe Mon Sep 17 00:00:00 2001 From: escape209 Date: Mon, 24 Aug 2026 11:43:07 +0100 Subject: [PATCH 08/11] Match iSndUpdateStreams --- src/SB/Core/gc/iSnd.cpp | 71 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/src/SB/Core/gc/iSnd.cpp b/src/SB/Core/gc/iSnd.cpp index 30dcfe143..2cacb3a71 100644 --- a/src/SB/Core/gc/iSnd.cpp +++ b/src/SB/Core/gc/iSnd.cpp @@ -9,6 +9,7 @@ #include "xSnd.h" #include "xstransvc.h" #include "xMath.h" +#include "iCutscene.h" #include #include @@ -55,7 +56,7 @@ struct UNK_STREAM U32 source_b; U32 xe4; ARQRequest request; - U8 pad2[0x4]; + U32 x10c; }; UNK_STREAM streams[6]; @@ -74,6 +75,8 @@ U32 houston_we_have_a_problem = 0; ARQRequest* last_ar; +S32 staticibuf; + static void dv_callback(void* userdata) { struct UNK_VOIDSTAR @@ -871,6 +874,72 @@ void iSndVolUpdate(xSndVoiceInfo* info, vinfo* vinfo) } } +void iSndUpdateStreams() +{ + UNK_STREAM* stream; + + if (!soundInited) + { + return; + } + + for (S32 i = 0; i < 6; i++) + { + stream = &streams[i]; + if (stream->vinf.voice == NULL) + { + continue; + } + U32 flags = stream->vinf.flags; + if (flags & 0x40000) + { + stream->vinf.flags = 0x80000; + } + else if (flags & 0x80000) + { + stream->vinf.flags = 0x100000; + } + else if (flags & 0x20000) + { + stream->vinf.flags = flags & 0xfffdffff; + if (!(stream->vinf.flags & 2)) + { + AXSetVoiceState(stream->vinf.voice, 1); + } + } + else + { + xSndVoiceInfo* vp = &gSnd.voice[i]; + iSndVolUpdate(vp, &stream->vinf); + if ((stream->vinf.flags & 0x1000000) && (stream->vinf.flags & 0x2000000)) + { + void* data = iCSSoundGetData(vp, &stream->xe4); + stream->source_b = (U32)data; + if (data != NULL) + { + U32 enabled = OSDisableInterrupts(); + if (stream->vinf.flags & 4) + { + stream->vinf.flags |= 0x200; + stream->vinf.flags |= 0x400; + ARQPostRequest(&stream->request, (U32)stream, 0, 1, stream->source_b, + stream->dest_a, 0x8000, arqcb); + stream->x10c = 0; + } + else + { + stream->x10c++; + } + stream->vinf.flags &= 0xfdffffff; + stream->vinf.flags |= 0x4000000; + staticibuf = stream->source_b; + OSRestoreInterrupts(enabled); + } + } + } + } +} + void iSndUpdateSounds() { if (!soundInited) From e6e973ad33f6b2dc114618bea59faf0f3a449b8a Mon Sep 17 00:00:00 2001 From: escape209 Date: Wed, 26 Aug 2026 14:57:15 +0100 Subject: [PATCH 09/11] Equivalent iSndPlaySound, fix vinfo.xc type --- src/SB/Core/gc/iSnd.cpp | 104 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/src/SB/Core/gc/iSnd.cpp b/src/SB/Core/gc/iSnd.cpp index 2cacb3a71..82295e21b 100644 --- a/src/SB/Core/gc/iSnd.cpp +++ b/src/SB/Core/gc/iSnd.cpp @@ -30,7 +30,7 @@ struct vinfo _AXVPB* voice; U32 flags; U32 aid; - U32 xc; + F32 xc; S32 x10; S32 x14; S32 x18; @@ -1015,6 +1015,108 @@ void iSndUpdate() } } +struct +{ + U32 a; // 0x00 + U32 b; // 0x04 + U32 c; // 0x08 + AXPBADDR addr; // 0x0C + AXPBADPCM adpcm; // 0x1C + AXPBADPCMLOOP adpcmLoop; // 0x44 + char pad[22]; // 0x4A + U32 id; +} snd; + +S32 sound_stream; + +S32 iSndPlaySound(xSndVoiceInfo* vp) +{ + vinfo* vi; + S32 vp_i; + U32 priority; + S32 i; + + if ((snd.id != vp->assetID) && (iSndLookup(vp->assetID), snd.id != vp->assetID)) + { + return 0; + } + + if (sound_stream != 0) + { + sound_stream = 0; + } + + vp_i = ((S32)vp - (S32)&gSnd.voice) / (S32)sizeof(xSndVoiceInfo); + + priority = vp->priority; + if (priority >= 0xFF) + { + priority = 0xFF; + } + priority >>= 3; + + i = vp_i - 6; + vi = &voices[i]; + if (vi->voice == NULL) + { + voices[i].aid = vp->assetID; + voices[i].xc = ((F32)snd.a * 1000.0f) / (F32)snd.c; + + AXPBADDR addr; + memcpy(&addr, &snd.addr, 0x10); + + if (snd.addr.loopFlag == 0) + { + U32 zero = zero_point; + addr.loopAddressHi = (U16)(zero >> 16); + addr.loopAddressLo = (U16)zero; + } + + if (priority == 0) + { + priority = 1; + } + + vi->voice = AXAcquireVoice(priority, dv_callback, vp_i); + if (vi->voice == NULL) + { + return 0; + } + else + { + S32 enabled = OSDisableInterrupts(); + AXSetVoiceAddr(vi->voice, &addr); + AXSetVoiceType(vi->voice, NULL); + AXSetVoiceAdpcm(vi->voice, &snd.adpcm); + AXSetVoiceSrcType(vi->voice, 1); + MIXInitChannel(vi->voice, 4, 0, 0xFFFFFC78, 0xFFFFFC78, 0x40, 0x7F, 0xFFFFFC78); + iSndVolUpdate(vp, vi); + F32 scale = std::powf(2.0f, vp->pitch / 12.0f); + F32 ratio = (snd.c * scale) / 32000.0f; + vi->voice->pb.src.ratioHi = ratio; + vi->voice->pb.src.ratioLo = ratio * 65536.0; + if (snd.addr.loopFlag) + { + AXSetVoiceAdpcmLoop(vi->voice, &snd.adpcmLoop); + } + vi->voice->sync |= 0x80000000; + MIXUnMute(vi->voice); + MIXUpdateSettings(); + AXSetVoiceState(vi->voice, 1); + OSRestoreInterrupts(enabled); + voices[i].flags &= 0xFFFFFFFE; + voices[i].flags |= 4; + return vp->sndID; + } + } + else + { + return 0; + } + + return vp_i; +} + S32 iSndPlay(xSndVoiceInfo* vp) { S32 offset = (S32)vp - (S32)gSnd.voice; From d92b39aae6aed0618ab9d15133d4cf02462aa34e Mon Sep 17 00:00:00 2001 From: escape209 Date: Thu, 27 Aug 2026 10:56:37 +0100 Subject: [PATCH 10/11] Equivalent match dump_flags --- src/SB/Core/gc/iSnd.cpp | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/SB/Core/gc/iSnd.cpp b/src/SB/Core/gc/iSnd.cpp index 82295e21b..6518bfd87 100644 --- a/src/SB/Core/gc/iSnd.cpp +++ b/src/SB/Core/gc/iSnd.cpp @@ -140,10 +140,30 @@ static void arq_callback(u32) static const char* dump_flags(U32 flags) { + char* ps; + char* pps; + static char str[0x40]; - memset(str, 0, sizeof(str)); + memset(str, 0, 0x40); + + char blah[5] = "-01X"; + + ps = &str[0]; - // TODO: + ps[0] = 'L'; + ps[1] = blah[(flags & 0x200) ? 1 : (flags & 0x400) ? 2 : 0]; + ps[2] = 'D'; + + pps = &ps[3]; // This doesn't work? + + pps[0] = blah[(flags & 0x1000) ? 1 : (flags & 0x2000) ? 2 : 0]; + pps[1] = 'P'; + pps[2] = blah[(flags & 0x4000) ? 1 : (flags & 0x8000) ? 2 : 0]; + pps[3] = (flags & 0x400000) ? 'F' : '-'; + pps[4] = 'R'; + pps[5] = (flags & 0x100) ? 'X' : '-'; + pps[6] = 'D'; + pps[7] = (flags & 0x800) ? 'X' : '-'; return str; } @@ -1035,7 +1055,7 @@ S32 iSndPlaySound(xSndVoiceInfo* vp) S32 vp_i; U32 priority; S32 i; - + if ((snd.id != vp->assetID) && (iSndLookup(vp->assetID), snd.id != vp->assetID)) { return 0; From bea7ace89d16f450ea6d327f3fce02c6c55d2638 Mon Sep 17 00:00:00 2001 From: escape209 Date: Thu, 27 Aug 2026 12:33:57 +0100 Subject: [PATCH 11/11] Match iSndPrepStream --- src/SB/Core/gc/iSnd.cpp | 42 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/src/SB/Core/gc/iSnd.cpp b/src/SB/Core/gc/iSnd.cpp index 6518bfd87..5b63a8cc0 100644 --- a/src/SB/Core/gc/iSnd.cpp +++ b/src/SB/Core/gc/iSnd.cpp @@ -42,9 +42,12 @@ struct vinfo struct UNK_STREAM { vinfo vinf; - U8 pad5[0x4]; + U32 x20; U32 x24; - U8 pad4[0x60]; + U32 x28; + U16 x2c; + U16 x2e; + U8 pad4[0x58]; U32 offset; U32 x8c; U32 x90; @@ -1035,6 +1038,7 @@ void iSndUpdate() } } +// Size: 0x180 struct { U32 a; // 0x00 @@ -1043,10 +1047,37 @@ struct AXPBADDR addr; // 0x0C AXPBADPCM adpcm; // 0x1C AXPBADPCMLOOP adpcmLoop; // 0x44 - char pad[22]; // 0x4A - U32 id; + char pad[0x16]; // 0x4A + U32 id; // 0x60 + char pad2[0xAC]; + void* ptr; // 0x110 } snd; +S32 iSndPrepStream(xSndVoiceInfo* vp) +{ + int vp_i = ((S32)vp - (S32)&gSnd.voice) / (S32)sizeof(xSndVoiceInfo); + UNK_STREAM* stream = &streams[vp_i]; + + if ((snd.id != vp->assetID) && (iSndLookup(vp->assetID), snd.id != vp->assetID)) + { + return 0x40; + } + + memcpy(&stream->x20, (void*)&snd, 100); + memcpy(&stream->fileInfo, &snd.ptr, 0x3C); + stream->fileInfo.cb.userData = (void*)stream; + stream->x8c = (stream->x24 + 1 >> 1) + 0x1f & 0xFFFFFFE0; + stream->vinf.flags |= 1; + stream->vinf.aid = snd.id; + + if ((stream->x2c != 0) || (vp->flags & 0x8000)) + { + stream->vinf.flags |= 0x10000; + } + + return vp_i; +} + S32 sound_stream; S32 iSndPlaySound(xSndVoiceInfo* vp) @@ -1080,7 +1111,8 @@ S32 iSndPlaySound(xSndVoiceInfo* vp) if (vi->voice == NULL) { voices[i].aid = vp->assetID; - voices[i].xc = ((F32)snd.a * 1000.0f) / (F32)snd.c; + voices[i].xc = ((F32)snd.a * 1000.0f); + voices[i].xc /= (F32)snd.c; AXPBADDR addr; memcpy(&addr, &snd.addr, 0x10);