From fc10af09a2f1c2c2be4e63adfbaab67b407b029c Mon Sep 17 00:00:00 2001 From: roeming Date: Fri, 14 Mar 2025 14:47:43 -0400 Subject: [PATCH 1/7] NES sound progress --- configure.py | 2 +- include/jaudio_NES/emusound.h | 7 + include/jaudio_NES/emusound.hpp | 48 ++ src/static/jaudio_NES/game/emusound.c | 1119 ++++++++++++++++++++++++- 4 files changed, 1174 insertions(+), 2 deletions(-) create mode 100644 include/jaudio_NES/emusound.hpp diff --git a/configure.py b/configure.py index 06e92d5f..c538f585 100644 --- a/configure.py +++ b/configure.py @@ -734,7 +734,7 @@ config.libs = [ "objects": [ Object(Matching, "jaudio_NES/game/audioheaders.c"), Object(Matching, "jaudio_NES/game/dummyprobe.c"), - Object(NonMatching, "jaudio_NES/game/emusound.c"), + Object(NonMatching, "jaudio_NES/game/emusound.c", extra_cflags=["-O4,s", "-fp_contract on", "-func_align 32"]), Object(NonMatching, "jaudio_NES/game/game64.c"), Object(Matching, "jaudio_NES/game/kappa.c"), Object(Matching, "jaudio_NES/game/melody.c"), diff --git a/include/jaudio_NES/emusound.h b/include/jaudio_NES/emusound.h index 81a38bcd..5ead686a 100644 --- a/include/jaudio_NES/emusound.h +++ b/include/jaudio_NES/emusound.h @@ -11,6 +11,13 @@ extern void EmuSound_Start(u8* noise_data); extern void EmuSound_Exit(); extern void Sound_Write(u16 event, u8 value, u16 maybe_frames); +extern void Sound_Reset(); +extern void Sound_Read(); +extern void Sound_SetC000(); +extern void Sound_SetE000(); +extern void Sound_SetMMC(); +extern void Sound_PlayMENUPCM(); + #ifdef __cplusplus } #endif diff --git a/include/jaudio_NES/emusound.hpp b/include/jaudio_NES/emusound.hpp new file mode 100644 index 00000000..0240b8ac --- /dev/null +++ b/include/jaudio_NES/emusound.hpp @@ -0,0 +1,48 @@ +#ifndef EMUSOUND_HPP +#define EMUSOUND_HPP + +#include "jaudio_NES/emusound.h" + +s32 __GetWave_Pulse(s32, s32); +u32 __PitchTo32_VRC_C(u16); +u32 __PitchTo32_VRC_PULSE(u16); +u32 __PitchTo32_HVC(u16); +void __Sound_Write_VRC(u16, u8); +void __Sound_Write_MMC5(u16, u8); +void __Sound_Write_A(u16, u8); +s16 __ProcessSoundA(); +void __Sound_Write_B(u16, u8); +s16 __ProcessSoundB(); +int __PitchTo32_HVC_D(u16); +void __Sound_Write_D(u16, u8); +s8 __GetNoise(u32); +s16 __ProcessSoundD(); +void MoveDeltaCounter(u8); +void MoveBias(); +void WriteBias(u16); +int MoveVoltage(); +u32 __PitchTo32_HVC_E(u16); +void __Sound_Write_E(u16, u8); +void StartE(); +void __ProcessSoundE(); +u8 __GetWave_Triangle(s32); +u32 __PitchTo32_HVC_C(u16); +void __Sound_Write_C(u16, u8); +void __ProcessSoundC(); +void __CreateDiskSubWave(); +void __CreateDiskSubWave(); +void __PitchTo32_DISKFM(u16); +void __Sound_Write_Disk(u16, u8); + +void HS_Event_Reset(); +void HS_Event_Update(); +void HS_Event_Write(u16, u8); +void ProcessPhaseCounter(); +void ForceProcessPhaseCounter(); +void Sound_Make_HVC(s32, s16*); +void Buffer_Reset(); +void Sample_Copy(u16, s16*); +void __FrameCallback(s32); +void __Sound_Write_HVC(u16, u8); + +#endif diff --git a/src/static/jaudio_NES/game/emusound.c b/src/static/jaudio_NES/game/emusound.c index 9b608ae7..8f7fe7df 100644 --- a/src/static/jaudio_NES/game/emusound.c +++ b/src/static/jaudio_NES/game/emusound.c @@ -1 +1,1118 @@ -#include "jaudio_NES/emusound.h" +#include "jaudio_NES/emusound.hpp" + +#define NES_CLOCK_SPEED 1789773 + +#define artificial_padding(lastOffset, currentOffset, typeOfLastMember) \ + u8 __##currentOffset##padding[currentOffset - lastOffset - sizeof(typeOfLastMember)] + +struct NESSoundStruct2 { + u8 _00; + artificial_padding(0, 0x24, u8); +}; +struct NESSoundStruct3 { + u8 _00; + artificial_padding(0, 0x18, u8); +}; +struct NESSoundStruct { + u8 _00; + // bad padding + union { + u32 _04; + struct { + u16 _04_hi; + u16 _04_lo; + } _04p; + }; + u32 _08; + u16 _0C; + // pad badding + u32 _10; + u32 _14; + u32 _18; + u8 _1C; + u8 _1D; + // bad padding + u32 _20; + u32 _24; + u8 _28; + // bad padding + u16 _2A; + u16 _2C; + // bad padding + u32 _30; + u32 _34; + u8 _38; + u8 _39; + u8 _3A; + u8 _3B; + u8 _3C; + // bad padding + u16 _3E; + u16 _40; + u16 _42; + u8 _44; + artificial_padding(0x44, 0x48, u8); + u16 _48; + // bad padding +}; // size 0x48 + +// bss +u8 PCMH2[16]; +NESSoundStruct SoundA, SoundB, SoundC, SoundD; +NESSoundStruct2 SoundE; +NESSoundStruct SoundX, SoundY, SoundZ; +NESSoundStruct SoundM, SoundN, SoundF; +NESSoundStruct3 SoundP; +u32 PHASE_SYNC_FLAG; + +// sdata +u32 NOISE_MASTER = 1; +u32 NOISE_SHIFT = 0x800; +u32 PHASE_SAMPLE = 0x85; +u32 FRAME_SAMPLE = 0x215; +const u64 _STOP = 0; + +// sbss +s8 NOISE_PULSE; +u32 delta_counter; +s8 delta_sign; +s32 bias; +s32 bias_move; +f32 voltage; +f32 voltage_out; + +// data + +// UNUSED +u8 LEN_TABLE[] = { 0x05, 0x7e, 0x0a, 0x01, 0x13, 0x02, 0x28, 0x03, 0x50, 0x04, 0x1e, 0x05, 0x07, 0x06, 0x0d, 0x07, + 0x06, 0x08, 0x0c, 0x09, 0x18, 0x0a, 0x30, 0x0b, 0x060, 0x0c, 0x24, 0x0d, 0x08, 0x0e, 0x10, 0x0f }; + +// UNUSED +f32 NOISE_FREQ_TABLE[] = { 4.f, 2.f, 1.f, 0.5f, 0.25f, 0.2f, 0.15f, 0.12f, + 0.1f, 0.08f, 0.07f, 0.06f, 0.05f, 0.04f, 0.03f, 0.03f }; + +// https://www.nesdev.org/wiki/APU_registers + +typedef struct _PulseChannel { + // $4000/$4004 + u8 Duty : 2; + u8 EnvelopeLoopCounter : 1; + u8 ConstantVolume : 1; + u8 EnvelopePeriod_Volume : 4; + // $4001/$4005 + u8 SweepUnitEnabled : 1; + u8 SweepUnitPeriod : 3; + u8 SweepUnitNegative : 1; + u8 SweepUnitShiftCount : 3; + // $4002/$4006 + u8 TimerLow : 8; + // $4003/$4007 + u8 LengthCounterLow : 5; + u8 TimerHigh : 3; +} PulseChannel; + +typedef struct _TriangleChannel { + // $4008 + u8 LengthCounter : 1; + u8 LinearCounterReloadVaue : 7; + // $4009 + u8 _unused_4009 : 8; + // $400A + u8 TimerLow : 8; + // $400B + u8 LengthCounterLoad : 5; + u8 TimerHigh : 3; +} TriangleChannel; + +typedef struct _NoiseChannel { + // $400C + u8 _unused_400C_high2 : 2; + u8 LoopEnvelope : 1; + u8 ConstantVolume : 1; + u8 EnvelopePeriod_Volume : 4; + // $400D + u8 _unused_400D : 8; + // $400E + u8 LoopNoise : 1; + u8 _unused_400E_3bits : 3; + u8 Period : 4; + // $400F + u8 LengthCounterLoad : 5; + u8 _unused_400F_low3 : 3; +} NoiseChannel; + +typedef struct _DMCChannel { + // $4010 + u8 IRQEnable : 1; + u8 LoopSample : 1; + u8 _unused_4010_middle2 : 2; + u8 FrequencyIndex : 4; + // $4011 + u8 _unused_4011_heigh : 1; + u8 DirectLoad : 7; + // $4012 + u8 SampleAddress : 8; + // $4013 + u8 SampleLength : 8; +} DMCChannel; + +typedef struct _APURegisters { + // $4000 + PulseChannel Pulse1; + // $4004 + PulseChannel Pulse2; + // $4008 + TriangleChannel Triangle; + // $400C + NoiseChannel Noise; + // $4010 + DMCChannel DMC; + // $4014 + u8 _unused_4014; + // $4015 + u8 DMCInterrupt : 1; + u8 FrameInterrupt : 1; + u8 _unused_4015_1bit : 1; + u8 LengthCounterStatus : 1; + u8 NoiseStatus : 1; + u8 TriangleStatus : 1; + u8 Pulse2Status : 1; + u8 Pulse1Status : 1; + // $4016 + u8 _unused_4016; + // $4017 + u8 FrameCounter_5FrameSequence : 1; + u8 FrameCounter_DisableFrameInterrupt : 1; + u8 _unused_4017_low : 6; + +} APURegisters; + +typedef struct _sbufferStruct { + APURegisters apu; + u8 buff[0x4100 - (0x4000 + sizeof(APURegisters))]; +} sbufferStruct; + +sbufferStruct sbuffer = { 0 }; +#define SBUFFER ((u8*)&sbuffer) + +u8 LEN_TABLE_HVC[] = { 0x05, 0x7e, 0x0a, 0x01, 0x13, 0x02, 0x28, 0x03, 0x50, 0x04, 0x1e, 0x05, 0x07, 0x06, 0x0d, 0x07, + 0x06, 0x08, 0x0c, 0x09, 0x18, 0x0a, 0x30, 0x0b, 0x60, 0x0c, 0x24, 0x0d, 0x08, 0x0e, 0x10, 0x0f }; + +u8 TRIANGLE_TABLE[] = { + 0x00, 0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69, 0x78, 0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, + 0x0f, 0x00, 0xef, 0xde, 0xcd, 0xbb, 0xaa, 0x99, 0x88, 0x88, 0x99, 0xaa, 0xbb, 0xcd, 0xde, 0xef +}; + +int NOISE_TABLE[] = { 0x000df86a, 0x0006fc35, 0x00037e1a, 0x0001bf0d, 0x0000df86, 0x00009504, 0x00006fc3, 0x00005969, + 0x000046d1, 0x00003852, 0x000025a5, 0x00001c29, 0x000012c6, 0x00000e14, 0x00000708, 0x000006fd }; + +u8 NOISE_PULSE_TABLE[] = { 0x30, 0x32, 0x34, 0x38, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x42, 0x44, 0x46, 0x48, 0x50, 0x60, 0x60 }; + +u32 DMOD_TABLE[] = { 0x000010bd, 0x000012db, 0x00001513, 0x00001663, 0x0000190d, 0x00001c36, 0x00001fb4, 0x00002115, + 0x000025b6, 0x00002cbf, 0x000032a4, 0x000037fb, 0x00004399, 0x00005475, 0x00006385, 0x000084b1 }; + +// UNUSED +u8 VOLTABLE_DELTAMOD[] = { + 0x00, 0x00, 0x00, 0xff, 0x01, 0xfc, 0x02, 0xf7, 0x03, 0xf0, 0x04, 0xe7, 0x05, 0xdc, 0x06, 0xcf, 0x07, 0xc0, 0x08, + 0xaf, 0x09, 0x9c, 0x0a, 0x87, 0x0b, 0x70, 0x0c, 0x57, 0x0d, 0x3c, 0x0e, 0x1f, 0x0f, 0x00, 0x0f, 0xdf, 0x10, 0xbc, + 0x11, 0x97, 0x12, 0x70, 0x13, 0x47, 0x14, 0x1c, 0x14, 0xef, 0x15, 0xc0, 0x16, 0x8f, 0x17, 0x5c, 0x18, 0x27, 0x18, + 0xf0, 0x19, 0xb7, 0x1a, 0x7c, 0x1b, 0x3f, 0x1c, 0x00, 0x1c, 0xbf, 0x1d, 0x7c, 0x1e, 0x37, 0x1e, 0xf0, 0x1f, 0xa7, + 0x20, 0x5c, 0x21, 0x0f, 0x21, 0xc0, 0x22, 0x6f, 0x23, 0x1c, 0x23, 0xc7, 0x24, 0x70, 0x25, 0x17, 0x25, 0xbc, 0x26, + 0x5f, 0x27, 0x00, 0x27, 0x9f, 0x28, 0x3c, 0x28, 0xd7, 0x29, 0x70, 0x2a, 0x07, 0x2a, 0x9c, 0x2b, 0x2f, 0x2b, 0xc0, + 0x2c, 0x4f, 0x2c, 0xdc, 0x2d, 0x67, 0x2d, 0xf0, 0x2e, 0x77, 0x2e, 0xfc, 0x2f, 0x7f, 0x30, 0x00, 0x30, 0x7f, 0x30, + 0xfc, 0x31, 0x77, 0x31, 0xf0, 0x32, 0x67, 0x32, 0xdc, 0x33, 0x4f, 0x33, 0xc0, 0x34, 0x2f, 0x34, 0x9c, 0x35, 0x07, + 0x35, 0x70, 0x35, 0xd7, 0x36, 0x3c, 0x36, 0x9f, 0x37, 0x00, 0x37, 0x5f, 0x37, 0xbc, 0x38, 0x17, 0x38, 0x70, 0x38, + 0xc7, 0x39, 0x1c, 0x39, 0x6f, 0x39, 0xc0, 0x3a, 0x0f, 0x3a, 0x5c, 0x3a, 0xa7, 0x3a, 0xf0, 0x3b, 0x37, 0x3b, 0x7c, + 0x3b, 0xbf, 0x3c, 0x00, 0x3c, 0x3f, 0x3c, 0x7c, 0x3c, 0xb7, 0x3c, 0xf0, 0x3d, 0x27, 0x3d, 0x5c, 0x3d, 0x8f, 0x3d, + 0xc0, 0x3d, 0xef, 0x3e, 0x1c, 0x3e, 0x47, 0x3e, 0x70, 0x3e, 0x97, 0x3e, 0xbc, 0x3e, 0xdf, 0x3f, 0x00, 0x3f, 0x1f, + 0x3f, 0x3c, 0x3f, 0x57, 0x3f, 0x70, 0x3f, 0x87, 0x3f, 0x9c, 0x3f, 0xaf, 0x3f, 0xc0, 0x3f, 0xcf, 0x3f, 0xdc, 0x3f, + 0xe7, 0x3f, 0xf0, 0x3f, 0xf7, 0x3f, 0xfc, 0x3f, 0xff +}; + +// UNUSED +u8 VOLTABLE_DISKFM[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, + 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, + 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c }; + +// UNUSED +u8 VOLTABLE_DISKFM_SUB[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20 }; + +// UNUSED +u32 DISKFM_GAINTABLE[] = { 30, 20, 15, 12 }; + +// UNUSED +u32 DEB1[4] = { 0, 0, 0, 0 }; + +f32 VOLTABLE_HVCPULSE[] = { 0.0f, 0.080128, 0.157051f, 0.224359f, 0.294872f, 0.365385f, + 0.435897f, 0.50641f, 0.592949f, 0.657051f, 0.730769f, 0.801282f, + 0.865385f, 0.929487f, 0.99359f, 1.064103f, 1.064103f }; + +u8 VOLTABLE_VRCPULSE[] = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, + 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, + 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f }; + +// UNUSED +void* PCM[9] = { (void*)&_STOP, (void*)&_STOP, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +// UNUSED +u32 PCMSIZE[9] = { sizeof(_STOP), sizeof(_STOP), 0, 0, 0, 0, 0, 0, 0 }; + +s32 __GetWave_Pulse(s32 a, s32 b) { + switch (a) { + + case 0: + if (b >= 4 && b <= 7) { + return 1; + } else { + return 0; + } + case 1: + return b <= 7; + case 2: + return b <= 15; + case 3: + return b > 7; + case 0xb: + return b & 0xff; + case 0xc: + return b <= 0 ? 127 : 0; + case 0xd: + return b <= 1 ? 127 : 0; + case 0xe: + return b <= 2 ? 127 : 0; + case 0xf: + return b <= 3 ? 127 : 0; + case 0x10: + return b <= 4 ? 127 : 0; + case 0x11: + return b <= 5 ? 0 : 127; + case 0x12: + return b <= 6 ? 0 : 127; + case 0x13: + return b <= 7 ? 0 : 127; + } + return a; +} + +u32 __PitchTo32_VRC_C(u16 pitch) { + f32 scalefactor = 2.f; + return (u32)((NES_CLOCK_SPEED - 0.25f) / scalefactor / (pitch + 1) / 1000.875f * 32768.f); +} + +u32 __PitchTo32_VRC_PULSE(u16 pitch) { + f32 scalefactor = 16.f; + return (u32)((NES_CLOCK_SPEED - 0.25f) / scalefactor / (pitch + 1) / 1000.875f * 32768.f); +} + +u32 __PitchTo32_HVC(u16 pitch) { + f32 scalefactor = 8.f; + return (u32)((NES_CLOCK_SPEED - 0.25f) / scalefactor / (pitch + 1) / 1000.875f * 32768.f); +} + +void __Sound_Write_VRC(u16 a, u8 b) { + NESSoundStruct* pSound; + u8* pBuffer; + int v; + int xyzIndex; + + u16 index = a - 0xc0; + if (index <= 3) { + pSound = &SoundX; + xyzIndex = 0; + pBuffer = &SBUFFER[192]; + } else if (index <= 7) { + pSound = &SoundY; + xyzIndex = 1; + pBuffer = &SBUFFER[196]; + } else { + pSound = &SoundZ; + xyzIndex = 2; + pBuffer = &SBUFFER[200]; + } + + if (index == 21) { + if (!(b & 1)) { + SoundX._00 = 0; + } + if (!(b & 2)) { + SoundY._00 = 0; + } + if (!(b & 4)) { + SoundZ._00 = 0; + } + return; + } + + switch (index & 3) { + case 0: + pSound->_3C = pBuffer[0] >> 4 & 7; + pSound->_28 = pBuffer[0] >> 7 & 1; + pSound->_1C = VOLTABLE_VRCPULSE[pBuffer[0] & 0xf]; + pSound->_1D = pBuffer[0] & 0xf; + pSound->_2A = pSound->_1D; + if (xyzIndex == 2) { + pSound->_24 = ((pSound->_3C & 3) << 4) | pSound->_2A; + pSound->_1C = (pSound->_24 * 7) / 3; + if (pSound->_1C >= 0x7f) { + pSound->_1C = 0x7f; + } + } + break; + case 2: + pSound->_0C = ((pBuffer[3] & 0xf) << 8) | pBuffer[2]; + if (xyzIndex == 2) { + pSound->_08 = __PitchTo32_VRC_C(pSound->_0C); + } else { + pSound->_08 = __PitchTo32_VRC_PULSE(pSound->_0C); + } + break; + case 3: + pSound->_0C = ((pBuffer[3] & 0xf) << 8) | pBuffer[2]; + if (xyzIndex == 2) { + pSound->_08 = __PitchTo32_VRC_C(pSound->_0C); + } else { + pSound->_08 = __PitchTo32_VRC_PULSE(pSound->_0C); + } + + if (!pSound->_00 && !pSound->_3E) { + pSound->_04 = 0; + } + + if (xyzIndex == 0) { + v = SBUFFER[213] & 1; + } + if (xyzIndex == 1) { + v = SBUFFER[213] >> 1 & 1; + } + if (xyzIndex == 2) { + v = SBUFFER[213] >> 2 & 1; + } + + if ((u8)v == 1 && (pBuffer[3] >> 7) & 1) { + pSound->_00 = 1; + } else { + pSound->_00 = 0; + } + + pSound->_2A = pSound->_1D; + pSound->_20 = 0; + + break; + } +} + +void __Sound_Write_MMC5(u16 a, u8 b) { + NESSoundStruct* pSound; + u8* pBuffer; + u32 v; + int xyzIndex; + + u16 index = a - 0xc0; + pBuffer = 0; + if (index <= 3) { + pSound = &SoundX; + xyzIndex = 0; + pBuffer = &SBUFFER[192]; + } else if (index <= 7) { + pSound = &SoundY; + xyzIndex = 1; + pBuffer = &SBUFFER[196]; + } + + if (index == 17) { + SoundZ._3E = (b << 6) & 0x3fc0; + } else if (index == 21) { + if (!(b & 1)) { + SoundX._00 = 0; + } + if (!(b & 2)) { + SoundY._00 = 0; + } + } else if (pBuffer) { + switch (index & 3) { + case 0: { + pSound->_3C = (pBuffer[0] >> 6) & 0x3; + v = pSound->_28; + pSound->_28 = (pBuffer[0] >> 4 & 1) ^ 1; + pSound->_14 = (pBuffer[0] >> 5 & 1); + pSound->_1D = VOLTABLE_HVCPULSE[pBuffer[0] & 0xf]; + if (pSound->_28 == 0 && pSound->_00 == 1) { + pSound->_1C = VOLTABLE_HVCPULSE[pBuffer[0] & 0xf]; + } else { + pSound->_24 = PHASE_SAMPLE * ((pBuffer[0] & 0xf) + 1); + if (v == 0) { + pSound->_2A = 0xf; + pSound->_20 = 0; + } + } + } break; + case 2: + pSound->_0C = ((pBuffer[3] & 0x7) << 8) | pBuffer[2]; + pSound->_08 = __PitchTo32_HVC_C(pSound->_0C); + break; + case 3: { + pSound->_0C = ((pBuffer[3] & 0x7) << 8) | pBuffer[2]; + pSound->_08 = __PitchTo32_HVC_C(pSound->_0C); + pSound->_18 = LEN_TABLE_HVC[(pBuffer[3] >> 3) & 0x1f]; + pSound->_10 = FRAME_SAMPLE * pSound->_18; + if (!pSound->_00 && !pSound->_3E) { + pSound->_04 = 0; + } + + if (xyzIndex == 0) { + v = SBUFFER[213] & 1; + } + if (xyzIndex == 1) { + v = SBUFFER[213] >> 1 & 1; + } + + if ((v & 0xff) != 0) { + pSound->_00 = 1; + } + + if ((pBuffer[0] >> 4 & 1) == 0) { + pSound->_1C = VOLTABLE_HVCPULSE[15]; + } else { + pSound->_1C = pSound->_1D; + } + + pSound->_2A = 0xf; + pSound->_20 = 0; + pSound->_30 = 0; + pSound->_3A = 0; + } break; + } + } +} + +void __Sound_Write_A(u16 a, u8 b) { + switch (a) { + case 0: { + SoundA._3C = sbuffer.apu.Pulse1.Duty; + u32 v = SoundA._28; + SoundA._28 = sbuffer.apu.Pulse1.ConstantVolume ^ 1; + SoundA._14 = sbuffer.apu.Pulse1.EnvelopeLoopCounter; + if (!SoundA._28) { + SoundA._2C = sbuffer.apu.Pulse1.EnvelopePeriod_Volume << 8; + } else { + SoundA._24 = sbuffer.apu.Pulse1.EnvelopePeriod_Volume + 1; + if (!v && SoundA._00) { + SoundA._2C = 0xf00; + SoundA._20 = 0; + } + } + } break; + case 1: { + SoundA._34 = (sbuffer.apu.Pulse1.SweepUnitPeriod + 1) << 1; + SoundA._39 = sbuffer.apu.Pulse1.SweepUnitNegative; + SoundA._38 = sbuffer.apu.Pulse1.SweepUnitShiftCount; + SoundA._30 = 0; + SoundA._3B = 0; + SoundA._3A = sbuffer.apu.Pulse1.SweepUnitEnabled; + } break; + case 2: { + SoundA._0C = SoundA._0C & 0xf00 | sbuffer.apu.Pulse1.TimerLow; + SoundA._08 = __PitchTo32_HVC(SoundA._0C); + } break; + case 3: { + SoundA._0C = (sbuffer.apu.Pulse1.TimerHigh << 8) | sbuffer.apu.Pulse1.TimerLow; + SoundA._08 = __PitchTo32_HVC(SoundA._0C); + SoundA._18 = LEN_TABLE_HVC[sbuffer.apu.Pulse1.LengthCounterLow]; + SoundA._10 = SoundA._18 << 2; + SoundA._04 = 0; + SoundA._48 = 0; + SoundA._3E = 0; + SoundA._2A = 0; + if (sbuffer.apu.Pulse1Status) { + SoundA._00 = 1; + } + if (!sbuffer.apu.Pulse1.ConstantVolume) { + SoundA._2C = 0xf00; + } else { + SoundA._2C = sbuffer.apu.Pulse1.EnvelopePeriod_Volume << 8; + } + SoundA._20 = 0; + SoundA._30 = 0; + SoundA._3B = 0; + SoundA._3A = sbuffer.apu.Pulse1.SweepUnitEnabled; + } break; + } +} + +s16 __ProcessSoundA() { + if (SoundA._3A) { + if (PHASE_SYNC_FLAG) { + SoundA._30++; + if (SoundA._30 % SoundA._34 == 0) { + SoundA._3B |= 1; + } + } + + if (SoundA._3B == 3) { + SoundA._3B = 0; + u32 c = SoundA._0C; + u16 j = SoundA._0C >> SoundA._38; + if (!SoundA._38) { + j = 0; + } + switch (SoundA._39) { + case 0: + SoundA._0C = SoundA._0C + j; + break; + case 1: + if (!SoundA._38) { + j = 0; + } + j = SoundA._0C - j; + SoundA._0C = j; + if (j && SoundA._38) { + SoundA._0C--; + } + } + if (SoundA._0C >= 0x800) { + SoundA._0C = 0x800; + } else { + SoundA._08 = __PitchTo32_HVC(SoundA._0C); + } + } + } + + if (!SoundA._00 && !SoundA._3E) { + return 0; + } + + if (SoundA._28 && PHASE_SYNC_FLAG) { + SoundA._20++; + if ((SoundA._20 % SoundA._24) == 0) { + switch (SoundA._14) { + case 0: + if (SoundA._2C) { + SoundA._2C -= 0x100; + } else { + SoundA._00 = 0; + } + break; + case 1: + if (SoundA._2C) { + SoundA._2C -= 0x100; + } else { + SoundA._2C = 0xf00; + } + break; + } + } + } + + if (SoundA._14 == 0) { + if (PHASE_SYNC_FLAG && SoundA._10) { + SoundA._10--; + } + if (SoundA._10 == 0) { + SoundA._00 = 0; + } + } + + if (SoundA._0C <= 7) { + SoundA._44 = 1; + } else if (SoundA._0C >= 0x800) { + SoundA._44 = 1; + } else { + SoundA._44 = 0; + } + + s8 c = __GetWave_Pulse(SoundA._3C, SoundA._04p._04_hi); + + if (SoundA._44) { + SoundA._04 += SoundA._40; + } else { + SoundA._04 += SoundA._08; + SoundA._40 = SoundA._08; + } + + if (SoundA._04 & 0xffe00000) { + SoundA._3B |= 2; + } + + SoundA._04 &= 0x1fffff; + if (SoundA._44 == 1 || !SoundA._00) { + if (SoundA._3E) { + SoundA._3E--; + } + } else { + if (SoundA._3E < 0x20) { + SoundA._3E++; + } + if (SoundA._3E < 0x20) { + SoundA._3E++; + } + } + + u32 _2a_6 = SoundA._2A >> 8 & 0xff; + f32 f_2a = (SoundA._2A & 0xff) / 256.f; + f32 param0 = VOLTABLE_HVCPULSE[_2a_6]; + f32 param1 = VOLTABLE_HVCPULSE[_2a_6 + 1]; + f32 f_sum = param0 * (1.f - f_2a) + param1 * f_2a; + + if (SoundA._2A != SoundA._2C) { + if (SoundA._2A > SoundA._2C) { + u16 diff = (SoundA._2A - SoundA._2C) >> 4; + if (!diff) { + SoundA._2A = SoundA._2C; + } else { + SoundA._2A -= diff; + } + } else if (SoundA._2A < SoundA._2C) { + u16 diff = (SoundA._2C - SoundA._2A) >> 4; + if (!diff) { + SoundA._2A = SoundA._2C; + } else { + SoundA._2A += diff; + } + } + } + + switch (c) { + case 0: + // almost 1. / 15.6 + f_sum = -0.064103; + break; + case 1: + f_sum = -0.064103 + f_sum; + break; + } + + s16 t = f_sum * 4096.f; + + t = (t * SoundA._3E) >> 5; + return t; +} + +void __Sound_Write_B(u16 a, u8 b) { + a -= 4; + switch (a) { + case 0: { + SoundB._3C = sbuffer.apu.Pulse2.Duty; + u32 v = SoundB._28; + SoundB._28 = sbuffer.apu.Pulse2.ConstantVolume ^ 1; + SoundB._14 = sbuffer.apu.Pulse2.EnvelopeLoopCounter; + if (!SoundB._28) { + SoundB._2C = sbuffer.apu.Pulse2.EnvelopePeriod_Volume << 8; + } else { + SoundB._24 = sbuffer.apu.Pulse2.EnvelopePeriod_Volume + 1; + if (!v && SoundB._00) { + SoundB._2C = 0xf00; + SoundB._20 = 0; + } + } + } break; + case 1: { + SoundB._34 = (sbuffer.apu.Pulse2.SweepUnitPeriod + 1) << 1; + SoundB._39 = sbuffer.apu.Pulse2.SweepUnitNegative; + SoundB._38 = sbuffer.apu.Pulse2.SweepUnitShiftCount; + SoundB._30 = 0; + SoundB._3B = 0; + SoundB._3A = sbuffer.apu.Pulse2.SweepUnitEnabled; + } break; + case 2: { + SoundB._0C = SoundB._0C & 0xf00 | sbuffer.apu.Pulse2.TimerLow; + SoundB._08 = __PitchTo32_HVC(SoundB._0C); + } break; + case 3: { + SoundB._0C = (sbuffer.apu.Pulse2.TimerHigh << 8) | sbuffer.apu.Pulse2.TimerLow; + SoundB._08 = __PitchTo32_HVC(SoundB._0C); + SoundB._18 = LEN_TABLE_HVC[sbuffer.apu.Pulse2.LengthCounterLow]; + SoundB._10 = SoundB._18 << 2; + SoundB._04 = 0; + SoundB._48 = 0; + SoundB._3E = 0; + SoundB._2A = 0; + if (sbuffer.apu.Pulse2Status) { + SoundB._00 = 1; + } + if (!sbuffer.apu.Pulse2.ConstantVolume) { + SoundB._2C = 0xf00; + } else { + SoundB._2C = sbuffer.apu.Pulse2.EnvelopePeriod_Volume << 8; + } + SoundB._20 = 0; + SoundB._30 = 0; + SoundB._3B = 0; + SoundB._3A = sbuffer.apu.Pulse2.SweepUnitEnabled; + } break; + } +} + +s16 __ProcessSoundB() { + if (SoundB._3A) { + if (PHASE_SYNC_FLAG) { + SoundB._30++; + if (SoundB._30 % SoundB._34 == 0) { + SoundB._3B |= 1; + } + } + + if (SoundB._3B == 3) { + SoundB._3B = 0; + u32 c = SoundB._0C; + u16 j = SoundB._0C >> SoundB._38; + if (!SoundB._38) { + j = 0; + } + switch (SoundB._39) { + case 0: + SoundB._0C = SoundB._0C + j; + break; + case 1: + if (!SoundB._38) { + j = 0; + } + + SoundB._0C = SoundB._0C - j; + } + if (SoundB._0C >= 0x800) { + SoundB._0C = 0x800; + } else { + SoundB._08 = __PitchTo32_HVC(SoundB._0C); + } + } + } + + if (!SoundB._00 && !SoundB._3E) { + return 0; + } + + if (SoundB._28 && PHASE_SYNC_FLAG) { + SoundB._20++; + if ((SoundB._20 % SoundB._24) == 0) { + switch (SoundB._14) { + case 0: + if (SoundB._2C) { + SoundB._2C -= 0x100; + } else { + SoundB._00 = 0; + } + break; + case 1: + if (SoundB._2C) { + SoundB._2C -= 0x100; + } else { + SoundB._2C = 0xf00; + } + break; + } + } + } + + if (SoundB._14 == 0) { + if (PHASE_SYNC_FLAG && SoundB._10) { + SoundB._10--; + } + if (SoundB._10 == 0) { + SoundB._00 = 0; + } + } + + if (SoundB._0C <= 7) { + SoundB._44 = 1; + } else if (SoundB._0C >= 0x800) { + SoundB._44 = 1; + } else { + SoundB._44 = 0; + } + + s8 c = __GetWave_Pulse(SoundB._3C, SoundB._04p._04_hi); + + if (SoundB._44) { + SoundB._04 += SoundB._40; + } else { + SoundB._04 += SoundB._08; + SoundB._40 = SoundB._08; + } + + if (SoundB._04 & 0xffe00000) { + SoundB._3B |= 2; + } + + SoundB._04 &= 0x1fffff; + if (SoundB._44 == 1 || !SoundB._00) { + if (SoundB._3E) { + SoundB._3E--; + } + } else { + if (SoundB._3E < 0x20) { + SoundB._3E++; + } + if (SoundB._3E < 0x20) { + SoundB._3E++; + } + } + + u32 _2a_6 = SoundB._2A >> 8 & 0xff; + f32 f_2a = (SoundB._2A & 0xff) / 256.f; + f32 param0 = VOLTABLE_HVCPULSE[_2a_6]; + f32 param1 = VOLTABLE_HVCPULSE[_2a_6 + 1]; + f32 f_sum = param0 * (1.f - f_2a) + param1 * f_2a; + + if (SoundB._2A != SoundB._2C) { + if (SoundB._2A > SoundB._2C) { + u16 diff = (SoundB._2A - SoundB._2C) >> 4; + if (!diff) { + SoundB._2A = SoundB._2C; + } else { + SoundB._2A -= diff; + } + } else if (SoundB._2A < SoundB._2C) { + u16 diff = (SoundB._2C - SoundB._2A) >> 4; + if (!diff) { + SoundB._2A = SoundB._2C; + } else { + SoundB._2A += diff; + } + } + } + + switch (c) { + case 0: + // almost 1. / 15.6 + f_sum = -0.064103; + break; + case 1: + f_sum = -0.064103 + f_sum; + break; + } + + s16 t = f_sum * 4096.f; + + t = (t * SoundB._3E) >> 5; + return t; +} + +int __PitchTo32_HVC_D(u16 a) { + return NOISE_TABLE[a]; +} + +void __Sound_Write_D(u16 a, u8 b) { + switch (a) { + case 0xc: + u32 v = SoundD._28; + SoundD._28 = sbuffer.apu.Noise.ConstantVolume ^ 1; + SoundD._14 = sbuffer.apu.Noise.LoopEnvelope; + SoundD._1D = (u8)(16.f * VOLTABLE_HVCPULSE[sbuffer.apu.Noise.EnvelopePeriod_Volume]); + if (!SoundD._28) { + SoundD._1C = SoundD._1D; + } else { + SoundD._24 = sbuffer.apu.Noise.EnvelopePeriod_Volume + 1; + if (!v) { + SoundD._2A = 0xf; + SoundD._20 = 0; + } + } + break; + case 0xe: + SoundD._0C = sbuffer.apu.Noise.Period; + if (sbuffer.apu.Noise.LoopNoise == 1u) { + SoundD._0C += 0x10; + NOISE_SHIFT = 0x40; + NOISE_MASTER = 1; + } else { + + NOISE_SHIFT = 0x4000; + } + NOISE_PULSE = NOISE_PULSE_TABLE[SoundD._0C & 0xf]; + SoundD._08 = __PitchTo32_HVC_D(SoundD._0C & 0xf); + break; + case 0xf: + SoundD._0C = sbuffer.apu.Noise.Period; + if (sbuffer.apu.Noise.LoopNoise == 1u) { + SoundD._0C += 0x10; + NOISE_SHIFT = 0x40; + NOISE_MASTER = 1; + } else { + NOISE_SHIFT = 0x4000; + } + NOISE_PULSE = NOISE_PULSE_TABLE[SoundD._0C % 16u]; + SoundD._08 = __PitchTo32_HVC_D(SoundD._0C % 16u); + SoundD._18 = LEN_TABLE_HVC[sbuffer.apu.Noise.LengthCounterLoad]; + SoundD._10 = SoundD._18 * 4; + if (sbuffer.apu.NoiseStatus != 0) { + SoundD._00 = '\x01'; + } + if (sbuffer.apu.Noise.ConstantVolume == 0) { + SoundD._1C = (u8)(16.f * VOLTABLE_HVCPULSE[15]); + } else { + SoundD._1C = SoundD._1D; + } + SoundD._2A = 0xf; + SoundD._20 = 0; + break; + } +} + +s8 __GetNoise(u32 a) { + static u8 data = 0; + + for (int i = 0; i < a >> 16; i++) { + data = NOISE_MASTER & 3; + switch (data) { + case 0: + case 3: + NOISE_MASTER = (NOISE_MASTER >> 1) | NOISE_SHIFT; + break; + case 1: + case 2: + NOISE_MASTER >>= 1; + } + } + + if (NOISE_MASTER & 1) { + return (s32)NOISE_PULSE; + } else { + return -(s32)NOISE_PULSE; + } +} + +s16 __ProcessSoundD() { + s16 ret; + if (!SoundD._00) { + if (!SoundD._3E) { + return 0; + } + SoundD._3E--; + SoundD._1C = SoundD._3E; + } + SoundD._04 += SoundD._08; + __GetNoise(SoundD._04); + SoundD._04 &= 0xffff; + SoundD._3E = SoundD._1C; + + if (!SoundD._14) { + if (PHASE_SYNC_FLAG && SoundD._10) { + SoundD._10--; + } + if (!SoundD._10) { + SoundD._00 = 0; + } + } + return ret; +} + +void MoveDeltaCounter(u8 a) { + if (a) { + delta_counter++; + delta_sign++; + } else { + delta_counter--; + delta_sign--; + } +} + +void MoveBias() { + s32 oldBias = bias; + bias += delta_sign * 2; + if (bias > 0x7f) { + bias = 0x7f; + } + if (bias < 0) { + bias = 0; + } + bias_move += bias - oldBias; + delta_sign = 0; +} + +void WriteBias(u16 a) { + bias_move = (s16)a - (s16)bias; + bias = (a & 0xffff); +} + +int MoveVoltage() { + voltage = 0.9994586f * voltage; + voltage += bias_move; + bias_move = 0; + if (voltage > 127.f) { + voltage = 127.f; + } + if (voltage < -127.f) { + voltage = -127.f; + } + voltage_out += (voltage - voltage_out) / 4.f; + + return (int)(216.f * voltage_out); +} + +u32 __PitchTo32_HVC_E(u16 a) { + return DMOD_TABLE[a]; +} + +void __Sound_Write_E(u16, u8) { +} + +void StartE() { +} +void __ProcessSoundE() { +} + +u8 __GetWave_Triangle(s32 a) { + return TRIANGLE_TABLE[a]; +} + +u32 __PitchTo32_HVC_C(u16 a) { + u32 pitch; + if (a == 0) { + return 0; + } else { + f32 scalefactor = 16.f; + return (u32)((NES_CLOCK_SPEED - 0.25f) / scalefactor / (a + 1) / 1000.875f * 32768.f); + } +} + +void __Sound_Write_C(u16, u8) { +} +void __ProcessSoundC() { +} +void __CreateDiskSubWave() { +} +void __PitchTo32_DISKFM(u16) { +} +void __Sound_Write_Disk(u16, u8) { +} +void HS_Event_Reset() { +} +void HS_Event_Update() { +} +void HS_Event_Write(u16, u8) { +} +void ProcessPhaseCounter() { +} +void ForceProcessPhaseCounter() { +} +void Sound_Make_HVC(s32, s16*) { +} +void Buffer_Reset() { +} +void Sample_Copy(u16, s16*) { +} +void Sound_Write(u16 event, u8 value, u16 maybe_frames) { +} +void Sound_Reset() { +} +void __FrameCallback(s32) { +} +void EmuSound_Start(u8* noise_data) { +} +void EmuSound_Exit() { +} +void Sound_Read() { +} +void Sound_SetC000() { +} +void Sound_SetE000() { +} +void Sound_SetMMC() { +} +void Sound_PlayMENUPCM() { +} +void __Sound_Write_HVC(u16, u8) { +} From 001b4b2c44147d6715a4c52d9932c16db26759b7 Mon Sep 17 00:00:00 2001 From: roeming Date: Sun, 16 Mar 2025 21:00:39 -0400 Subject: [PATCH 2/7] making progress --- include/jaudio_NES/emusound.hpp | 6 +- src/static/jaudio_NES/game/emusound.c | 384 +++++++++++++++++++++----- 2 files changed, 317 insertions(+), 73 deletions(-) diff --git a/include/jaudio_NES/emusound.hpp b/include/jaudio_NES/emusound.hpp index 0240b8ac..215e250c 100644 --- a/include/jaudio_NES/emusound.hpp +++ b/include/jaudio_NES/emusound.hpp @@ -25,13 +25,13 @@ u32 __PitchTo32_HVC_E(u16); void __Sound_Write_E(u16, u8); void StartE(); void __ProcessSoundE(); -u8 __GetWave_Triangle(s32); +s8 __GetWave_Triangle(s32); u32 __PitchTo32_HVC_C(u16); void __Sound_Write_C(u16, u8); -void __ProcessSoundC(); +int __ProcessSoundC(); void __CreateDiskSubWave(); void __CreateDiskSubWave(); -void __PitchTo32_DISKFM(u16); +u32 __PitchTo32_DISKFM(u16); void __Sound_Write_Disk(u16, u8); void HS_Event_Reset(); diff --git a/src/static/jaudio_NES/game/emusound.c b/src/static/jaudio_NES/game/emusound.c index 8f7fe7df..96f0f2c0 100644 --- a/src/static/jaudio_NES/game/emusound.c +++ b/src/static/jaudio_NES/game/emusound.c @@ -5,15 +5,37 @@ #define artificial_padding(lastOffset, currentOffset, typeOfLastMember) \ u8 __##currentOffset##padding[currentOffset - lastOffset - sizeof(typeOfLastMember)] -struct NESSoundStruct2 { +typedef struct _NESSoundStruct2 { u8 _00; - artificial_padding(0, 0x24, u8); -}; -struct NESSoundStruct3 { + // bad padding + union { + u32 _04; + struct { + u16 _04_hi; + u16 _04_lo; + } _04p; + }; + u32 _08; + u32 _0C; + u32 _10; + u32 _14; + u16 _18; + u16 _1A; + u8 _1C; + u8 _1D; + s16 _1E; + u8 _20; + u8 _21; + u8 _22; + u8 _23; +} NESSoundStruct2; + +typedef struct _NESSoundStruct3 { u8 _00; artificial_padding(0, 0x18, u8); -}; -struct NESSoundStruct { +} NESSoundStruct3; + +typedef struct _NESSoundStruct { u8 _00; // bad padding union { @@ -53,8 +75,9 @@ struct NESSoundStruct { u8 _44; artificial_padding(0x44, 0x48, u8); u16 _48; + u8 _4A; // bad padding -}; // size 0x48 +} NESSoundStruct; // size 0x48 // bss u8 PCMH2[16]; @@ -198,7 +221,7 @@ sbufferStruct sbuffer = { 0 }; u8 LEN_TABLE_HVC[] = { 0x05, 0x7e, 0x0a, 0x01, 0x13, 0x02, 0x28, 0x03, 0x50, 0x04, 0x1e, 0x05, 0x07, 0x06, 0x0d, 0x07, 0x06, 0x08, 0x0c, 0x09, 0x18, 0x0a, 0x30, 0x0b, 0x60, 0x0c, 0x24, 0x0d, 0x08, 0x0e, 0x10, 0x0f }; -u8 TRIANGLE_TABLE[] = { +s8 TRIANGLE_TABLE[] = { 0x00, 0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a, 0x69, 0x78, 0x78, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f, 0x00, 0xef, 0xde, 0xcd, 0xbb, 0xaa, 0x99, 0x88, 0x88, 0x99, 0xaa, 0xbb, 0xcd, 0xde, 0xef }; @@ -263,36 +286,49 @@ u32 PCMSIZE[9] = { sizeof(_STOP), sizeof(_STOP), 0, 0, 0, 0, 0, 0, 0 }; s32 __GetWave_Pulse(s32 a, s32 b) { switch (a) { - case 0: + case 0: { if (b >= 4 && b <= 7) { return 1; } else { return 0; } - case 1: + } + case 1: { return b <= 7; - case 2: + } + case 2: { return b <= 15; - case 3: + } + case 3: { return b > 7; - case 0xb: + } + case 0xb: { return b & 0xff; - case 0xc: + } + case 0xc: { return b <= 0 ? 127 : 0; - case 0xd: + } + case 0xd: { return b <= 1 ? 127 : 0; - case 0xe: + } + case 0xe: { return b <= 2 ? 127 : 0; - case 0xf: + } + case 0xf: { return b <= 3 ? 127 : 0; - case 0x10: + } + case 0x10: { return b <= 4 ? 127 : 0; - case 0x11: + } + case 0x11: { return b <= 5 ? 0 : 127; - case 0x12: + } + case 0x12: { return b <= 6 ? 0 : 127; - case 0x13: + } + case 0x13: { return b <= 7 ? 0 : 127; + } } return a; } @@ -347,7 +383,7 @@ void __Sound_Write_VRC(u16 a, u8 b) { } switch (index & 3) { - case 0: + case 0: { pSound->_3C = pBuffer[0] >> 4 & 7; pSound->_28 = pBuffer[0] >> 7 & 1; pSound->_1C = VOLTABLE_VRCPULSE[pBuffer[0] & 0xf]; @@ -360,16 +396,16 @@ void __Sound_Write_VRC(u16 a, u8 b) { pSound->_1C = 0x7f; } } - break; - case 2: + } break; + case 2: { pSound->_0C = ((pBuffer[3] & 0xf) << 8) | pBuffer[2]; if (xyzIndex == 2) { pSound->_08 = __PitchTo32_VRC_C(pSound->_0C); } else { pSound->_08 = __PitchTo32_VRC_PULSE(pSound->_0C); } - break; - case 3: + } break; + case 3: { pSound->_0C = ((pBuffer[3] & 0xf) << 8) | pBuffer[2]; if (xyzIndex == 2) { pSound->_08 = __PitchTo32_VRC_C(pSound->_0C); @@ -399,8 +435,7 @@ void __Sound_Write_VRC(u16 a, u8 b) { pSound->_2A = pSound->_1D; pSound->_20 = 0; - - break; + } break; } } @@ -449,10 +484,10 @@ void __Sound_Write_MMC5(u16 a, u8 b) { } } } break; - case 2: + case 2: { pSound->_0C = ((pBuffer[3] & 0x7) << 8) | pBuffer[2]; pSound->_08 = __PitchTo32_HVC_C(pSound->_0C); - break; + } break; case 3: { pSound->_0C = ((pBuffer[3] & 0x7) << 8) | pBuffer[2]; pSound->_08 = __PitchTo32_HVC_C(pSound->_0C); @@ -559,10 +594,10 @@ s16 __ProcessSoundA() { j = 0; } switch (SoundA._39) { - case 0: + case 0: { SoundA._0C = SoundA._0C + j; - break; - case 1: + } break; + case 1: { if (!SoundA._38) { j = 0; } @@ -571,6 +606,7 @@ s16 __ProcessSoundA() { if (j && SoundA._38) { SoundA._0C--; } + } break; } if (SoundA._0C >= 0x800) { SoundA._0C = 0x800; @@ -588,20 +624,20 @@ s16 __ProcessSoundA() { SoundA._20++; if ((SoundA._20 % SoundA._24) == 0) { switch (SoundA._14) { - case 0: + case 0: { if (SoundA._2C) { SoundA._2C -= 0x100; } else { SoundA._00 = 0; } - break; - case 1: + } break; + case 1: { if (SoundA._2C) { SoundA._2C -= 0x100; } else { SoundA._2C = 0xf00; } - break; + } break; } } } @@ -675,13 +711,13 @@ s16 __ProcessSoundA() { } switch (c) { - case 0: + case 0: { // almost 1. / 15.6 f_sum = -0.064103; - break; - case 1: + } break; + case 1: { f_sum = -0.064103 + f_sum; - break; + } break; } s16 t = f_sum * 4096.f; @@ -762,15 +798,16 @@ s16 __ProcessSoundB() { j = 0; } switch (SoundB._39) { - case 0: + case 0: { SoundB._0C = SoundB._0C + j; - break; - case 1: + } break; + case 1: { if (!SoundB._38) { j = 0; } SoundB._0C = SoundB._0C - j; + } break; } if (SoundB._0C >= 0x800) { SoundB._0C = 0x800; @@ -788,20 +825,20 @@ s16 __ProcessSoundB() { SoundB._20++; if ((SoundB._20 % SoundB._24) == 0) { switch (SoundB._14) { - case 0: + case 0: { if (SoundB._2C) { SoundB._2C -= 0x100; } else { SoundB._00 = 0; } - break; - case 1: + } break; + case 1: { if (SoundB._2C) { SoundB._2C -= 0x100; } else { SoundB._2C = 0xf00; } - break; + } break; } } } @@ -875,13 +912,13 @@ s16 __ProcessSoundB() { } switch (c) { - case 0: + case 0: { // almost 1. / 15.6 f_sum = -0.064103; - break; - case 1: + } break; + case 1: { f_sum = -0.064103 + f_sum; - break; + } break; } s16 t = f_sum * 4096.f; @@ -896,7 +933,7 @@ int __PitchTo32_HVC_D(u16 a) { void __Sound_Write_D(u16 a, u8 b) { switch (a) { - case 0xc: + case 0xc: { u32 v = SoundD._28; SoundD._28 = sbuffer.apu.Noise.ConstantVolume ^ 1; SoundD._14 = sbuffer.apu.Noise.LoopEnvelope; @@ -910,8 +947,8 @@ void __Sound_Write_D(u16 a, u8 b) { SoundD._20 = 0; } } - break; - case 0xe: + } break; + case 0xe: { SoundD._0C = sbuffer.apu.Noise.Period; if (sbuffer.apu.Noise.LoopNoise == 1u) { SoundD._0C += 0x10; @@ -923,8 +960,8 @@ void __Sound_Write_D(u16 a, u8 b) { } NOISE_PULSE = NOISE_PULSE_TABLE[SoundD._0C & 0xf]; SoundD._08 = __PitchTo32_HVC_D(SoundD._0C & 0xf); - break; - case 0xf: + } break; + case 0xf: { SoundD._0C = sbuffer.apu.Noise.Period; if (sbuffer.apu.Noise.LoopNoise == 1u) { SoundD._0C += 0x10; @@ -947,7 +984,7 @@ void __Sound_Write_D(u16 a, u8 b) { } SoundD._2A = 0xf; SoundD._20 = 0; - break; + } break; } } @@ -958,12 +995,13 @@ s8 __GetNoise(u32 a) { data = NOISE_MASTER & 3; switch (data) { case 0: - case 3: + case 3: { NOISE_MASTER = (NOISE_MASTER >> 1) | NOISE_SHIFT; - break; + } break; case 1: - case 2: + case 2: { NOISE_MASTER >>= 1; + } break; } } @@ -984,10 +1022,34 @@ s16 __ProcessSoundD() { SoundD._1C = SoundD._3E; } SoundD._04 += SoundD._08; - __GetNoise(SoundD._04); - SoundD._04 &= 0xffff; + ret = __GetNoise(SoundD._04); + ret *= SoundD._1C; + SoundD._04p._04_hi = 0; SoundD._3E = SoundD._1C; + if (SoundD._28 && PHASE_SYNC_FLAG) { + SoundD._20++; + if (SoundD._20 % SoundD._24 == 0) { + switch (SoundD._14) { + case 0: { + if (SoundD._2A) { + SoundD._2A--; + } else { + SoundD._00 = 0; + } + } break; + case 1: { + if (SoundD._2A) { + SoundD._2A--; + } else { + SoundD._2A = 0xf; + } + } break; + } + SoundD._1C = (u8)(16.f * VOLTABLE_HVCPULSE[SoundD._2A]); + } + } + if (!SoundD._14) { if (PHASE_SYNC_FLAG && SoundD._10) { SoundD._10--; @@ -1046,15 +1108,79 @@ u32 __PitchTo32_HVC_E(u16 a) { return DMOD_TABLE[a]; } -void __Sound_Write_E(u16, u8) { +void __Sound_Write_E(u16 a, u8 b) { + switch (a) { + case 0x10: { + SoundE._08 = __PitchTo32_HVC_E(sbuffer.apu.DMC.FrequencyIndex); + } break; + case 0x11: { + SoundE._1E = sbuffer.apu.DMC.DirectLoad; + WriteBias(SoundE._1E); + } break; + case 0x12: { + SoundE._18 = sbuffer.apu.DMC.SampleAddress << 6; + } break; + case 0x13: { + SoundE._10 = sbuffer.apu.DMC.SampleLength << 4; + } break; + } } void StartE() { -} -void __ProcessSoundE() { + SoundE._00 = 1; + SoundE._14 = (SoundE._10 + 1) * 8; + SoundE._04 = 0; + SoundE._1A = 0; + SoundE._20 = 0; + delta_counter = 0; + bias_move = 0; } -u8 __GetWave_Triangle(s32 a) { +u8* ROM_TOP_C000 = (u8*)&DEB1; +u8* ROM_TOP_E000 = (u8*)&DEB1; + +void __ProcessSoundE() { + if (SoundE._00) { + for (int i = 0; i < 2u; i++) { + SoundE._04 += SoundE._08; + if (SoundE._04p._04_hi != SoundE._1A) { + u32 vv = SoundE._1A & 7; + u32 offset = (SoundE._1A >> 3 & 0x1fff); + if (!vv) { + if (SoundE._18 + offset < 0x2000) { + SoundE._1C = ROM_TOP_C000[SoundE._18 + offset]; + } else { + SoundE._1C = ROM_TOP_E000[SoundE._18 + offset - 0x2000]; + } + } + MoveDeltaCounter((SoundE._1C << vv) & 0x80); + SoundE._1A = SoundE._04p._04_hi; + if (SoundE._14) { + SoundE._14--; + } + if (!SoundE._14) { + switch (sbuffer.apu.DMC.LoopSample) { + case 0: { + SoundE._00 = 0; + if (sbuffer.apu.DMC.IRQEnable == 1) { + SoundE._20 = 1; + } + } break; + case 1: { + SoundE._14 = (SoundE._10 + 1) * 8; + SoundE._04p._04_hi = 0; + SoundE._1A = 0; + } break; + } + } + } + } + } + MoveBias(); + MoveVoltage(); +} + +s8 __GetWave_Triangle(s32 a) { return TRIANGLE_TABLE[a]; } @@ -1067,15 +1193,133 @@ u32 __PitchTo32_HVC_C(u16 a) { return (u32)((NES_CLOCK_SPEED - 0.25f) / scalefactor / (a + 1) / 1000.875f * 32768.f); } } +u32 sample_timer = 0; +u32 abs_timer = 0; -void __Sound_Write_C(u16, u8) { +void __Sound_Write_C(u16 a, u8 b) { + switch (a) { + case 0x8: { + u8 v = SoundC._14; + if (sbuffer.apu.Triangle.LinearCounterReloadVaue) { + SoundC._24 = sbuffer.apu.Triangle.LinearCounterReloadVaue + 1; + } else { + SoundC._24 = 0; + } + + if (SoundC._00 && SoundC._4A) { + SoundC._14 = sbuffer.apu.Triangle.LengthCounter; + SoundC._20 = SoundC._24; + } else if (SoundC._00) { + if (v && !sbuffer.apu.Triangle.LengthCounter) { + SoundC._14 = sbuffer.apu.Triangle.LengthCounter; + SoundC._20 = SoundC._24; + SoundC._4A = 0x80; + } else if (v) { + SoundC._20 = SoundC._24; + } + } else if (SoundC._4A) { + SoundC._14 = sbuffer.apu.Triangle.LengthCounter; + SoundC._20 = SoundC._24; + if (sbuffer.apu.TriangleStatus) { + SoundC._00 = 1; + } + } + + if (!sbuffer.apu.Triangle.LinearCounterReloadVaue && !SoundC._14) { + SoundC._00 = 0; + } + } break; + case 0xa: { + SoundC._0C = (sbuffer.apu.Triangle.TimerHigh << 8) | sbuffer.apu.Triangle.TimerLow; + SoundC._08 = __PitchTo32_HVC_C(SoundC._0C); + } break; + case 0xb: { + sample_timer = 0; + SoundC._0C = (sbuffer.apu.Triangle.TimerHigh << 8) | sbuffer.apu.Triangle.TimerLow; + SoundC._18 = LEN_TABLE_HVC[sbuffer.apu.Triangle.LengthCounterLoad]; + SoundC._10 = SoundC._18 * 4; + if (!SoundC._00 || !SoundC._20) { + SoundC._04 = 0; + SoundC._1C = (127 - bias >> 3) + 16; + SoundC._48 = 0; + SoundC._08 = __PitchTo32_HVC_C(SoundC._0C); + } else { + SoundC._08 = __PitchTo32_HVC_C(SoundC._0C); + } + SoundC._4A = 60; + SoundC._14 = sbuffer.apu.Triangle.LengthCounter; + SoundC._20 = SoundC._24; + if (sbuffer.apu.TriangleStatus && sbuffer.apu.Triangle.LinearCounterReloadVaue) { + if (!SoundC._00) { + SoundC._00 = 1; + } + } else { + SoundC._00 = 0; + } + } break; + } } -void __ProcessSoundC() { + +int __ProcessSoundC() { + static s16 timer = 0; + sample_timer++; + abs_timer++; + + u16 v = SoundC._08; + if (!SoundC._00 || !SoundC._20) { + if (SoundC._3E) { + SoundC._3E--; + } + } else if (SoundC._3E < 0x20) { + SoundC._3E++; + } + + s16 b = (int)__GetWave_Triangle(SoundC._04p._04_hi); + SoundC._1C = (127 - bias >> 3) + 0x10; + b *= SoundC._1C; + SoundC._04 = SoundC._04 + SoundC._08; + SoundC._04 &= 0x1fffff; + SoundC._40 = v; + + if (!SoundC._14) { + if (PHASE_SYNC_FLAG && SoundC._10) { + SoundC._10--; + } + if (!SoundC._10 && !SoundC._14) { + SoundC._00 = 0; + } + if (SoundC._20 && PHASE_SYNC_FLAG) { + SoundC._20--; + } + } + + if (!SoundC._20 && !SoundC._14) { + SoundC._00 = 0; + } + + if (SoundC._4A) { + SoundC._4A--; + } + + s16 ret = (b * SoundC._3E) >> 5; + return ret; } + +u8 DISKSUB_TABLE[32]; +s16 disksubwave[32][2]; +s8 DISK_SUB_GAIN[] = { 0, 1, 2, 4, 0, -4, -2, -1 }; + void __CreateDiskSubWave() { + for (int i = 0; i < 32; i++) { + disksubwave[i][0] = DISK_SUB_GAIN[DISKSUB_TABLE[i]]; + disksubwave[i][1] = DISK_SUB_GAIN[DISKSUB_TABLE[i]]; + } } -void __PitchTo32_DISKFM(u16) { + +u32 __PitchTo32_DISKFM(u16 v) { + return (0.85343015f * (int)v) / 500.4375f * 32768.f; } + void __Sound_Write_Disk(u16, u8) { } void HS_Event_Reset() { From f8034c5dfa6ad67561aa40c65450cfbc04856b1c Mon Sep 17 00:00:00 2001 From: roeming Date: Wed, 19 Mar 2025 19:49:41 -0400 Subject: [PATCH 3/7] emusound almost done --- include/jaudio_NES/emusound.h | 10 +- include/jaudio_NES/emusound.hpp | 10 +- src/static/jaudio_NES/game/emusound.c | 585 +++++++++++++++++++++++++- 3 files changed, 574 insertions(+), 31 deletions(-) diff --git a/include/jaudio_NES/emusound.h b/include/jaudio_NES/emusound.h index 5ead686a..98859ee1 100644 --- a/include/jaudio_NES/emusound.h +++ b/include/jaudio_NES/emusound.h @@ -12,11 +12,11 @@ extern void EmuSound_Exit(); extern void Sound_Write(u16 event, u8 value, u16 maybe_frames); extern void Sound_Reset(); -extern void Sound_Read(); -extern void Sound_SetC000(); -extern void Sound_SetE000(); -extern void Sound_SetMMC(); -extern void Sound_PlayMENUPCM(); +extern u8 Sound_Read(u16 param_1, u32 param_2, u32 param_3, u32 param_4, u32 param_5); +extern void Sound_SetC000(u8* romTop); +extern void Sound_SetE000(u8* romTop); +extern void Sound_SetMMC(u8 mmcMode); +extern void Sound_PlayMENUPCM(u8 v); #ifdef __cplusplus } diff --git a/include/jaudio_NES/emusound.hpp b/include/jaudio_NES/emusound.hpp index 215e250c..67752753 100644 --- a/include/jaudio_NES/emusound.hpp +++ b/include/jaudio_NES/emusound.hpp @@ -10,13 +10,13 @@ u32 __PitchTo32_HVC(u16); void __Sound_Write_VRC(u16, u8); void __Sound_Write_MMC5(u16, u8); void __Sound_Write_A(u16, u8); -s16 __ProcessSoundA(); +int __ProcessSoundA(); void __Sound_Write_B(u16, u8); -s16 __ProcessSoundB(); +int __ProcessSoundB(); int __PitchTo32_HVC_D(u16); void __Sound_Write_D(u16, u8); s8 __GetNoise(u32); -s16 __ProcessSoundD(); +int __ProcessSoundD(); void MoveDeltaCounter(u8); void MoveBias(); void WriteBias(u16); @@ -24,7 +24,7 @@ int MoveVoltage(); u32 __PitchTo32_HVC_E(u16); void __Sound_Write_E(u16, u8); void StartE(); -void __ProcessSoundE(); +int __ProcessSoundE(); s8 __GetWave_Triangle(s32); u32 __PitchTo32_HVC_C(u16); void __Sound_Write_C(u16, u8); @@ -42,7 +42,7 @@ void ForceProcessPhaseCounter(); void Sound_Make_HVC(s32, s16*); void Buffer_Reset(); void Sample_Copy(u16, s16*); -void __FrameCallback(s32); +s16* __FrameCallback(s32); void __Sound_Write_HVC(u16, u8); #endif diff --git a/src/static/jaudio_NES/game/emusound.c b/src/static/jaudio_NES/game/emusound.c index 96f0f2c0..595fa9da 100644 --- a/src/static/jaudio_NES/game/emusound.c +++ b/src/static/jaudio_NES/game/emusound.c @@ -1,4 +1,7 @@ #include "jaudio_NES/emusound.hpp" +#include "dolphin/os.h" +#include "jaudio_NES/aictrl.h" +#include "jaudio_NES/sample.h" #define NES_CLOCK_SPEED 1789773 @@ -32,7 +35,11 @@ typedef struct _NESSoundStruct2 { typedef struct _NESSoundStruct3 { u8 _00; - artificial_padding(0, 0x18, u8); + u32 _04; + artificial_padding(0x4, 0xd, u32); + u8 _0D; + u16 _0E; + artificial_padding(0xe, 0x18, u16); } NESSoundStruct3; typedef struct _NESSoundStruct { @@ -47,7 +54,7 @@ typedef struct _NESSoundStruct { }; u32 _08; u16 _0C; - // pad badding + u16 _0E; u32 _10; u32 _14; u32 _18; @@ -73,21 +80,72 @@ typedef struct _NESSoundStruct { u16 _40; u16 _42; u8 _44; - artificial_padding(0x44, 0x48, u8); + artificial_padding(0x44, 0x47, u8); + u8 _47; u16 _48; u8 _4A; // bad padding } NESSoundStruct; // size 0x48 +typedef struct _NESSoundStructF { + u8 _00; + // bad padding + union { + u32 _04; + struct { + u16 _04_hi; + u16 _04_lo; + } _04p; + }; + u32 _08; + u16 _0C; + u16 _0E; + u32 _10; + u32 _14; + u32 _18; + u8 _1C; + u8 _1D; + // bad padding + u32 _20; + u32 _24; + u8 _28; + // bad padding + u16 _2A; + u8 _2C; + u8 _2D; + u8 _2E; + u8 _2F; + // bad padding + u8 _30[9]; + u8 _39; + u8 _3A; + u8 _3B; + u16 _3C; + // bad padding + u16 _3E; + u16 _40; + u16 _42; + u8 _44; + artificial_padding(0x44, 0x47, u8); + u8 _47; + u16 _48; + u8 _4A; + // bad padding +} NESSoundStructF; // size 0x48 + // bss u8 PCMH2[16]; NESSoundStruct SoundA, SoundB, SoundC, SoundD; NESSoundStruct2 SoundE; NESSoundStruct SoundX, SoundY, SoundZ; -NESSoundStruct SoundM, SoundN, SoundF; +NESSoundStruct SoundM, SoundN; +NESSoundStructF SoundF; NESSoundStruct3 SoundP; +u32 FRAME_SYNC_FLAG; +u32 FRAME_SYNC_COUNTER; u32 PHASE_SYNC_FLAG; - +u32 PHASE_SYNC_COUNTER; +u8 DUMMY_ACTIVE[9]; // sdata u32 NOISE_MASTER = 1; u32 NOISE_SHIFT = 0x800; @@ -265,6 +323,7 @@ u8 VOLTABLE_DISKFM_SUB[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x0 // UNUSED u32 DISKFM_GAINTABLE[] = { 30, 20, 15, 12 }; +u8 DISKFM_TABLE[0x40]; // UNUSED u32 DEB1[4] = { 0, 0, 0, 0 }; @@ -577,7 +636,7 @@ void __Sound_Write_A(u16 a, u8 b) { } } -s16 __ProcessSoundA() { +int __ProcessSoundA() { if (SoundA._3A) { if (PHASE_SYNC_FLAG) { SoundA._30++; @@ -781,7 +840,7 @@ void __Sound_Write_B(u16 a, u8 b) { } } -s16 __ProcessSoundB() { +int __ProcessSoundB() { if (SoundB._3A) { if (PHASE_SYNC_FLAG) { SoundB._30++; @@ -1012,7 +1071,7 @@ s8 __GetNoise(u32 a) { } } -s16 __ProcessSoundD() { +int __ProcessSoundD() { s16 ret; if (!SoundD._00) { if (!SoundD._3E) { @@ -1139,7 +1198,7 @@ void StartE() { u8* ROM_TOP_C000 = (u8*)&DEB1; u8* ROM_TOP_E000 = (u8*)&DEB1; -void __ProcessSoundE() { +int __ProcessSoundE() { if (SoundE._00) { for (int i = 0; i < 2u; i++) { SoundE._04 += SoundE._08; @@ -1177,7 +1236,7 @@ void __ProcessSoundE() { } } MoveBias(); - MoveVoltage(); + return MoveVoltage(); } s8 __GetWave_Triangle(s32 a) { @@ -1259,6 +1318,7 @@ void __Sound_Write_C(u16 a, u8 b) { } break; } } +u32 exitflag; int __ProcessSoundC() { static s16 timer = 0; @@ -1308,7 +1368,10 @@ int __ProcessSoundC() { u8 DISKSUB_TABLE[32]; s16 disksubwave[32][2]; s8 DISK_SUB_GAIN[] = { 0, 1, 2, 4, 0, -4, -2, -1 }; +u8* NOISE_DTABLE; +MixCallback old_mixcall; +u8 old_mixmode; void __CreateDiskSubWave() { for (int i = 0; i < 32; i++) { disksubwave[i][0] = DISK_SUB_GAIN[DISKSUB_TABLE[i]]; @@ -1320,43 +1383,523 @@ u32 __PitchTo32_DISKFM(u16 v) { return (0.85343015f * (int)v) / 500.4375f * 32768.f; } -void __Sound_Write_Disk(u16, u8) { +void __Sound_Write_Disk(u16 a, u8 b) { + static int shiftr = 0; + ((u8*)&sbuffer)[a] = b; + if (a == 0x23) { + if (!(b & 2)) { + SoundF._2D = 0; + SoundF._2C = 0; + } + } else if (a >= 0x40 && a <= 0x7f) { + DISKFM_TABLE[a - 0x40] = SBUFFER[a] & 0x3f; + } else { + switch (a) { + case 0x80: { + s8 c = -((char)SBUFFER[128] >> 7); + SoundF._2E = SBUFFER[128] >> 6 & 1; + if (c == 1) { + SoundF._2E = SBUFFER[128] & 0x3F; + } + } break; + case 0x82: { + s8 c = -((char)SBUFFER[128] >> 7); + SoundF._2E = SBUFFER[128] >> 6 & 1; + if (c == 1) { + SoundF._2E = SBUFFER[128] & 0x3F; + } + } break; + case 0x83: { + s8 c = -((char)SBUFFER[128] >> 7); + SoundF._2E = SBUFFER[128] >> 6 & 1; + if (c == 1) { + SoundF._2E = SBUFFER[128] & 0x3F; + } + } break; + case 0x84: { + s8 c = -((char)SBUFFER[128] >> 7); + SoundF._2E = SBUFFER[128] >> 6 & 1; + if (c == 1) { + SoundF._2E = SBUFFER[128] & 0x3F; + } + } break; + case 0x85: { + s8 c = -((char)SBUFFER[128] >> 7); + SoundF._2E = SBUFFER[128] >> 6 & 1; + if (c == 1) { + SoundF._2E = SBUFFER[128] & 0x3F; + } + } break; + case 0x86: { + s8 c = -((char)SBUFFER[128] >> 7); + SoundF._2E = SBUFFER[128] >> 6 & 1; + if (c == 1) { + SoundF._2E = SBUFFER[128] & 0x3F; + } + } break; + case 0x87: { + s8 c = -((char)SBUFFER[128] >> 7); + SoundF._2E = SBUFFER[128] >> 6 & 1; + if (c == 1) { + SoundF._2E = SBUFFER[128] & 0x3F; + } + } break; + case 0x88: { + s8 c = -((char)SBUFFER[128] >> 7); + SoundF._2E = SBUFFER[128] >> 6 & 1; + if (c == 1) { + SoundF._2E = SBUFFER[128] & 0x3F; + } + } break; + case 0x89: { + s8 c = -((char)SBUFFER[128] >> 7); + SoundF._2E = SBUFFER[128] >> 6 & 1; + if (c == 1) { + SoundF._2E = SBUFFER[128] & 0x3F; + } + } break; + case 0x8a: { + s8 c = -((char)SBUFFER[128] >> 7); + SoundF._2E = SBUFFER[128] >> 6 & 1; + if (c == 1) { + SoundF._2E = SBUFFER[128] & 0x3F; + } + } break; + } + } } +OSMessageQueue SoundQ; +OSMessage SoundQbuf[0x1000]; + void HS_Event_Reset() { + OSInitMessageQueue(&SoundQ, SoundQbuf, ARRAY_COUNT(SoundQbuf)); } + void HS_Event_Update() { + //! TODO: this has to be wrong + typedef struct { + u8 a, b; + } tempBuf; + tempBuf message; + + while (1) { + // this should take a void** for message, and it fills out the OSMessage(which is a void*) + if (!OSReceiveMessage(&SoundQ, (OSMessage*)&message, 0)) { + break; + } + __Sound_Write_HVC(message.a, message.b); + } } -void HS_Event_Write(u16, u8) { + +void HS_Event_Write(u16 a, u8 b) { + if (a >= 0x5000 && a <= 0x5015) { + a = (a - 0xf40); + } + + OSSendMessage(&SoundQ, (OSMessage)((a - 0x4000) << 0x18 | b << 0x10), 0); + switch (a & 0xff) { + case 3: { + DUMMY_ACTIVE[0] = 2; + } break; + case 7: { + DUMMY_ACTIVE[1] = 2; + } break; + case 0xb: { + DUMMY_ACTIVE[2] = 2; + } break; + case 0xf: { + DUMMY_ACTIVE[3] = 2; + } break; + case 0x15: { + if (!(b & 1)) { + DUMMY_ACTIVE[0] = 1; + } + if (!(b & 2)) { + DUMMY_ACTIVE[1] = 1; + } + if (!(b & 4)) { + DUMMY_ACTIVE[2] = 1; + } + if (!(b & 8)) { + DUMMY_ACTIVE[3] = 1; + } + if (!(b & 0x10)) { + DUMMY_ACTIVE[4] = 1; + } + if (b & 0x10) { + DUMMY_ACTIVE[4] = 2; + } + } break; + case 0xc3: { + DUMMY_ACTIVE[6] = 2; + } break; + case 0xc7: { + DUMMY_ACTIVE[7] = 2; + } break; + case 0xcb: { + DUMMY_ACTIVE[8] = 2; + } break; + case 0xd5: { + if (!(b & 1)) { + DUMMY_ACTIVE[6] = 1; + } + if (!(b & 2)) { + DUMMY_ACTIVE[7] = 1; + } + if (!(b & 4)) { + DUMMY_ACTIVE[8] = 1; + } + } break; + } } + void ProcessPhaseCounter() { + if (PHASE_SYNC_COUNTER != 0) { + PHASE_SYNC_COUNTER--; + } + if (PHASE_SYNC_COUNTER == 0) { + PHASE_SYNC_FLAG = 1; + PHASE_SYNC_COUNTER = PHASE_SAMPLE; + } + + if (PHASE_SYNC_FLAG) { + if (FRAME_SYNC_COUNTER != 0) { + FRAME_SYNC_COUNTER--; + } + if (FRAME_SYNC_COUNTER == 0) { + FRAME_SYNC_FLAG = 1; + FRAME_SYNC_COUNTER = 4; + } + } } + void ForceProcessPhaseCounter() { + PHASE_SYNC_COUNTER = 0; + ProcessPhaseCounter(); } -void Sound_Make_HVC(s32, s16*) { + +void Sound_Make_HVC(s32 count, s16* v) { + static int lastsample; + int j; + int a, b, c, d, e; + int i; + HS_Event_Update(); + for (i = 0; i < count; i++) { + ProcessPhaseCounter(); + a = __ProcessSoundA(); + b = __ProcessSoundB(); + c = __ProcessSoundC(); + d = __ProcessSoundD(); + e = __ProcessSoundE(); + j = (s16)a + (s16)b - (s16)c - (s16)d + (s16)e; + if (j >= 0x7fff) { + j = 0x7fff; + } else if (j <= -0x7fff) { + j = -0x7fff; + } + lastsample += (j - lastsample) / 2; + v[i] = lastsample; + PHASE_SYNC_FLAG = 0; + FRAME_SYNC_FLAG = 0; + } + DUMMY_ACTIVE[0] = 0; + DUMMY_ACTIVE[1] = 0; + DUMMY_ACTIVE[2] = 0; + DUMMY_ACTIVE[3] = 0; + DUMMY_ACTIVE[4] = 0; + DUMMY_ACTIVE[5] = 0; + DUMMY_ACTIVE[6] = 0; + DUMMY_ACTIVE[7] = 0; + DUMMY_ACTIVE[8] = 0; } + +s16 sound_loop_buffer[0x2000]; + +int read_pointer; +int write_pointer = 0x690; +int buffer_remain = 0x690; + void Buffer_Reset() { + for (int i = 0; i < ARRAY_COUNT(sound_loop_buffer); i++) { + sound_loop_buffer[i] = 0; + } + read_pointer = 0; + write_pointer = 0x690; + buffer_remain = 0x690; } -void Sample_Copy(u16, s16*) { + +void Sample_Copy(u16 count, s16* v) { + u32 i; + for (i = 0; i < count; i++, buffer_remain--) { + if (buffer_remain == 0) { + Buffer_Reset(); + break; + } + v[i] = sound_loop_buffer[read_pointer]; + sound_loop_buffer[read_pointer] = 0; + if (++read_pointer == 0x2000) { + read_pointer = 0; + } + } + + for (i; i < count; i++) { + v[i] = 0; + } } + void Sound_Write(u16 event, u8 value, u16 maybe_frames) { + if (event == 0) { + static f32 create_counter = 0; + static f32 create_speed; + int interrupts = OSDisableInterrupts(); + if (buffer_remain < 0x460) { + create_speed = 2.038168f * ((5.f * (0x460 - buffer_remain) + 1680.f) / 1680.f); + if (create_speed > 2.5) { + create_speed = 2.5f; + } + } else if (buffer_remain > 1680) { + create_speed = 2.038168f * (1680.f / ((-0x690 + buffer_remain) * 5 + 0x690)); + } else { + create_speed = 2.038168f; + } + create_counter += create_speed; + int c = (int)create_counter; + create_counter -= c; + static s16 buf[0x10]; + Sound_Make_HVC(c, buf); + if (c != 0) { + for (u32 i = 0; i < c; i++) { + if (buffer_remain == 0x2000) { + break; + } + sound_loop_buffer[write_pointer] = buf[i]; + if (++write_pointer == 0x2000) { + write_pointer = 0; + } + buffer_remain++; + } + } + OSRestoreInterrupts(interrupts); + } else { + HS_Event_Write(event, value); + } } + void Sound_Reset() { + HS_Event_Reset(); + Jac_bzero(&SoundA, sizeof(SoundA)); + Jac_bzero(&SoundB, sizeof(SoundB)); + Jac_bzero(&SoundC, sizeof(SoundC)); + Jac_bzero(&SoundD, sizeof(SoundD)); + Jac_bzero(&SoundX, sizeof(SoundX)); + Jac_bzero(&SoundY, sizeof(SoundY)); + Jac_bzero(&SoundZ, sizeof(SoundZ)); + Jac_bzero(&SoundM, sizeof(SoundM)); + Jac_bzero(&SoundN, sizeof(SoundN)); + Jac_bzero(&SoundE, sizeof(SoundE)); + Jac_bzero(&SoundF, sizeof(SoundF)); + Jac_bzero(&SoundP, sizeof(SoundP)); + SoundA._3E = 0; + SoundB._3E = 0; + SoundC._3E = 0; + SoundD._3E = 0; + SoundF._3C = 0; + SoundP._0E = 0; + + SoundX._3E = 0; + SoundY._3E = 0; + SoundZ._3E = 0; + + SoundA._04 = 0; + SoundB._04 = 0; + SoundC._04 = 0; + SoundD._04 = 0; + SoundE._04 = 0; + SoundF._04 = 0; + SoundP._04 = 0; + + SoundA._48 = 0; + SoundB._48 = 0; + SoundC._48 = 0; + SoundX._04 = 0; + SoundY._04 = 0; + SoundZ._04 = 0; + SoundP._0D = 0; + WriteBias(0); + Buffer_Reset(); } -void __FrameCallback(s32) { + +u8 move_to_50; + +s16* __FrameCallback(s32 a) { + static s16 buf[0x320]; + if (move_to_50) { + move_to_50--; + if (move_to_50 == 0) { + FRAME_SAMPLE = 0x280; + PHASE_SAMPLE = 0xa0; + } + } + Sample_Copy(a, buf); + if (exitflag) { + f32 f2 = 1.f; + f32 f = 1.f / a; + Jac_RegisterMixcallback(old_mixcall, old_mixmode); + exitflag = FALSE; + for (int i = 0; i < a; i++) { + f32 f3 = f2 * buf[i]; + f2 -= f; + buf[i] = f3; + } + } + return buf; } + void EmuSound_Start(u8* noise_data) { + NOISE_DTABLE = noise_data; + Sound_Reset(); + exitflag = 0; + old_mixcall = Jac_GetMixcallback(&old_mixmode); + Jac_RegisterMixcallback(__FrameCallback, 0); } + void EmuSound_Exit() { + exitflag = TRUE; } -void Sound_Read() { + +u8 Sound_Read(u16 param_1, u32 param_2, u32 param_3, u32 param_4, u32 param_5) { + u8 a, b, c, d, e; + if (param_1 == 0x5015) { + if (!DUMMY_ACTIVE[6]) { + param_3 = SoundX._00; + } + if (!DUMMY_ACTIVE[7]) { + param_4 = SoundY._00; + } + if (!DUMMY_ACTIVE[8]) { + param_5 = SoundZ._00; + } + return (u8)param_5 << 2 | (u8)param_4 << 1 | (param_3); + } else if (param_1 == 0x4015) { + a = SoundA._00; + if (DUMMY_ACTIVE[0]) { + a = DUMMY_ACTIVE[0] - 1; + } + b = SoundB._00; + if (DUMMY_ACTIVE[1]) { + b = DUMMY_ACTIVE[1] - 1; + } + c = SoundC._00; + if (DUMMY_ACTIVE[2]) { + c = DUMMY_ACTIVE[2] - 1; + } + d = SoundD._00; + if (DUMMY_ACTIVE[3]) { + d = DUMMY_ACTIVE[3] - 1; + } + e = SoundE._00; + if (DUMMY_ACTIVE[4]) { + e = DUMMY_ACTIVE[4] - 1; + } + return SoundE._20 << 7 | e << 4 | d << 3 | c << 2 | b << 1 | a; + } else { + switch (param_1 & 0xff) { + case 0x90: + return SoundF._2D; + case 0x92: + return SoundF._39; + default: + return 0; + } + } } -void Sound_SetC000() { + +void Sound_SetC000(u8* romTop) { + ROM_TOP_C000 = romTop; } -void Sound_SetE000() { +void Sound_SetE000(u8* romTop) { + ROM_TOP_E000 = romTop; } -void Sound_SetMMC() { + +u8 MMC_MODE; +u8 beforemode; + +void Sound_SetMMC(u8 mmcMode) { + FRAME_SAMPLE = 0x280; + PHASE_SAMPLE = 0xa0; + beforemode = 0; + MMC_MODE = mmcMode; + Sound_Reset(); } -void Sound_PlayMENUPCM() { + +void Sound_PlayMENUPCM(u8 v) { + SoundP._0D = v; } -void __Sound_Write_HVC(u16, u8) { + +void __Sound_Write_HVC(u16 index, u8 v) { + ((u8*)&sbuffer)[index] = v; + if (index >= 0xc0) { + switch (MMC_MODE) { + case 1: { + __Sound_Write_VRC(index, v); + } break; + case 0: { + __Sound_Write_MMC5(index, v); + } break; + } + } else if (index > 0x17) { + __Sound_Write_Disk(index, v); + } else { + switch (index >> 2) { + case 0: { + __Sound_Write_A(index, v); + } break; + case 1: { + __Sound_Write_B(index, v); + } break; + case 2: { + __Sound_Write_C(index, v); + } break; + case 3: { + __Sound_Write_D(index, v); + } break; + case 4: { + __Sound_Write_E(index, v); + } break; + + case 5: { + if (index == 0x17) { + if (v & 0x80) { + FRAME_SAMPLE = 0x280; + PHASE_SAMPLE = 0xa0; + beforemode = 0; + } else { + FRAME_SAMPLE = 0x215; + PHASE_SAMPLE = 0x85; + beforemode = 1; + } + ForceProcessPhaseCounter(); + } else { + if (!(v & 1)) { + SoundA._00 = 0; + } + if (!(v & 2)) { + SoundB._00 = 0; + } + if (!(v & 4)) { + SoundC._00 = 0; + } + if (!(v & 8)) { + SoundD._00 = 0; + } + if (!(v & 0x10)) { + SoundE._00 = 0; + } + if ((v & 0x10) && !SoundE._00) { + StartE(); + } + } + } break; + } + } } From c9bb307991efcdd2db08d03f75366616a56e47dd Mon Sep 17 00:00:00 2001 From: roeming Date: Fri, 21 Mar 2025 17:30:18 -0400 Subject: [PATCH 4/7] equivalent, down to regswaps --- src/static/jaudio_NES/game/emusound.c | 329 ++++++++++++++++---------- 1 file changed, 203 insertions(+), 126 deletions(-) diff --git a/src/static/jaudio_NES/game/emusound.c b/src/static/jaudio_NES/game/emusound.c index 595fa9da..e5d921bd 100644 --- a/src/static/jaudio_NES/game/emusound.c +++ b/src/static/jaudio_NES/game/emusound.c @@ -98,25 +98,24 @@ typedef struct _NESSoundStructF { } _04p; }; u32 _08; - u16 _0C; - u16 _0E; + u32 _0C; u32 _10; - u32 _14; + u16 _14; + u16 _16; u32 _18; - u8 _1C; - u8 _1D; + u16 _1C; // bad padding u32 _20; u32 _24; - u8 _28; - // bad padding - u16 _2A; + u32 _28; u8 _2C; u8 _2D; u8 _2E; u8 _2F; // bad padding - u8 _30[9]; + u32 _30; + u32 _34; + u8 _38; u8 _39; u8 _3A; u8 _3B; @@ -124,11 +123,14 @@ typedef struct _NESSoundStructF { // bad padding u16 _3E; u16 _40; - u16 _42; - u8 _44; - artificial_padding(0x44, 0x47, u8); + u8 _42; + u8 _43; + s8 _44; + u8 _45; + u8 _46; u8 _47; - u16 _48; + u8 _48; + u8 _49; u8 _4A; // bad padding } NESSoundStructF; // size 0x48 @@ -141,26 +143,25 @@ NESSoundStruct SoundX, SoundY, SoundZ; NESSoundStruct SoundM, SoundN; NESSoundStructF SoundF; NESSoundStruct3 SoundP; -u32 FRAME_SYNC_FLAG; -u32 FRAME_SYNC_COUNTER; -u32 PHASE_SYNC_FLAG; -u32 PHASE_SYNC_COUNTER; + u8 DUMMY_ACTIVE[9]; // sdata u32 NOISE_MASTER = 1; u32 NOISE_SHIFT = 0x800; u32 PHASE_SAMPLE = 0x85; u32 FRAME_SAMPLE = 0x215; -const u64 _STOP = 0; +u32 _STOP[2] = { 0 }; // sbss +u8 beforemode; +u8 move_to_50; +u8 MMC_MODE; +u8* NOISE_DTABLE; +u32 PHASE_SYNC_FLAG; +u32 FRAME_SYNC_FLAG; +u32 PHASE_SYNC_COUNTER; +u32 FRAME_SYNC_COUNTER; s8 NOISE_PULSE; -u32 delta_counter; -s8 delta_sign; -s32 bias; -s32 bias_move; -f32 voltage; -f32 voltage_out; // data @@ -237,6 +238,22 @@ typedef struct _DMCChannel { u8 SampleLength : 8; } DMCChannel; +typedef struct _WaveTableEntry { + u8 Read : 2; + u8 Sample : 6; +} WaveTableEntry; + +typedef struct _unknown_C0 { + u8 _0_7 : 1; // 10000000 + u8 _0_6 : 3; // 01000000 + u8 _0_3 : 4; // 00001111 + u8 _1; + u8 _2; + u8 _3_7 : 1; // 10000000 + u8 _3_6 : 3; // 01000000 + u8 _3_3 : 4; // 00001111 +} Unknown_VRC; + typedef struct _APURegisters { // $4000 PulseChannel Pulse1; @@ -266,15 +283,66 @@ typedef struct _APURegisters { u8 FrameCounter_DisableFrameInterrupt : 1; u8 _unused_4017_low : 6; + artificial_padding(0x17, 0x40, u8); + // $4040 - $4079 https://www.nesdev.org/wiki/FDS_audio#Wavetable_RAM_($4040-$407F) + WaveTableEntry WaveTable[0x40]; + // $4080 https://www.nesdev.org/wiki/FDS_audio#Volume_envelope_($4080) + u8 VolumeEnvelopeEnabled : 1; + u8 VolumeEnvelopeIncreasing : 1; + u8 VolumeEnvelopeGainAndSpeed : 6; + // $4081 + u8 _unused_4081; + // $4082 https://www.nesdev.org/wiki/FDS_audio#Frequency_low_($4082) + u8 FrequencyLow; + // $4083 https://www.nesdev.org/wiki/FDS_audio#Frequency_high_($4083) + u8 HighSpeedFrequency : 1; + u8 DisableSweepAndEnvelope : 1; + u8 _unused_4083_midbits : 2; + u8 FrequencyHigh : 4; + // $4084 https://www.nesdev.org/wiki/FDS_audio#Mod_envelope_($4084) + u8 ModEnvelopeEnabled : 1; + u8 ModEnvelopeIncreasing : 1; + u8 ModEnvelopeGainAndSpeed : 6; + // $4085 https://www.nesdev.org/wiki/FDS_audio#Mod_counter_($4085) + u8 _unused_4085_high : 1; + u8 ModCounter : 7; + // $4086 https://www.nesdev.org/wiki/FDS_audio#Mod_frequency_low_($4086) + u8 ModFrequencyLow; + // $4087 https://www.nesdev.org/wiki/FDS_audio#Mod_frequency_high_($4087) + u8 HaltModTableCounter : 1; + u8 ForceAccumulatorStepOut : 1; + u8 _unused_4087_mid : 2; + u8 ModFrequencyHigh : 4; + // $4088 https://www.nesdev.org/wiki/FDS_audio#Mod_table_write_($4088) + // unused in the following code + u8 _unused_4088_high : 5; + u8 ModulationTableWrite : 3; + // $4089 https://www.nesdev.org/wiki/FDS_audio#Wave_write_/_master_volume_($4089) + u8 WaveTableWriteEnable : 1; + u8 _unused_4089_midbits : 5; + u8 WaveTableMasterVolume : 2; + // $408A https://www.nesdev.org/wiki/FDS_audio#Envelope_speed_($408A) + u8 EnvelopeSpeed; + + artificial_padding(0x8a, 0xc0, u8); + + Unknown_VRC _C0; + Unknown_VRC _C4; + Unknown_VRC _C8; + artificial_padding(0xc8, 0xd5, Unknown_VRC); + u8 _unused_D5_high : 5; + u8 _D5_2 : 1; + u8 _D5_1 : 1; + u8 _D5_0 : 1; + } APURegisters; -typedef struct _sbufferStruct { +typedef union _sbufferStruct { APURegisters apu; - u8 buff[0x4100 - (0x4000 + sizeof(APURegisters))]; + u8 buff[0x4100 - 0x4000]; } sbufferStruct; sbufferStruct sbuffer = { 0 }; -#define SBUFFER ((u8*)&sbuffer) u8 LEN_TABLE_HVC[] = { 0x05, 0x7e, 0x0a, 0x01, 0x13, 0x02, 0x28, 0x03, 0x50, 0x04, 0x1e, 0x05, 0x07, 0x06, 0x0d, 0x07, 0x06, 0x08, 0x0c, 0x09, 0x18, 0x0a, 0x30, 0x0b, 0x60, 0x0c, 0x24, 0x0d, 0x08, 0x0e, 0x10, 0x0f }; @@ -336,12 +404,6 @@ u8 VOLTABLE_VRCPULSE[] = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f }; -// UNUSED -void* PCM[9] = { (void*)&_STOP, (void*)&_STOP, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; - -// UNUSED -u32 PCMSIZE[9] = { sizeof(_STOP), sizeof(_STOP), 0, 0, 0, 0, 0, 0, 0 }; - s32 __GetWave_Pulse(s32 a, s32 b) { switch (a) { @@ -409,7 +471,7 @@ u32 __PitchTo32_HVC(u16 pitch) { void __Sound_Write_VRC(u16 a, u8 b) { NESSoundStruct* pSound; - u8* pBuffer; + Unknown_VRC* pBuffer; int v; int xyzIndex; @@ -417,15 +479,15 @@ void __Sound_Write_VRC(u16 a, u8 b) { if (index <= 3) { pSound = &SoundX; xyzIndex = 0; - pBuffer = &SBUFFER[192]; + pBuffer = &sbuffer.apu._C0; } else if (index <= 7) { pSound = &SoundY; xyzIndex = 1; - pBuffer = &SBUFFER[196]; + pBuffer = &sbuffer.apu._C4; } else { pSound = &SoundZ; xyzIndex = 2; - pBuffer = &SBUFFER[200]; + pBuffer = &sbuffer.apu._C8; } if (index == 21) { @@ -443,10 +505,10 @@ void __Sound_Write_VRC(u16 a, u8 b) { switch (index & 3) { case 0: { - pSound->_3C = pBuffer[0] >> 4 & 7; - pSound->_28 = pBuffer[0] >> 7 & 1; - pSound->_1C = VOLTABLE_VRCPULSE[pBuffer[0] & 0xf]; - pSound->_1D = pBuffer[0] & 0xf; + pSound->_3C = pBuffer->_0_6; + pSound->_28 = pBuffer->_0_7; + pSound->_1C = VOLTABLE_VRCPULSE[pBuffer->_0_3]; + pSound->_1D = pBuffer->_0_3; pSound->_2A = pSound->_1D; if (xyzIndex == 2) { pSound->_24 = ((pSound->_3C & 3) << 4) | pSound->_2A; @@ -457,7 +519,7 @@ void __Sound_Write_VRC(u16 a, u8 b) { } } break; case 2: { - pSound->_0C = ((pBuffer[3] & 0xf) << 8) | pBuffer[2]; + pSound->_0C = (pBuffer->_3_3 << 8) | pBuffer->_2; if (xyzIndex == 2) { pSound->_08 = __PitchTo32_VRC_C(pSound->_0C); } else { @@ -465,7 +527,7 @@ void __Sound_Write_VRC(u16 a, u8 b) { } } break; case 3: { - pSound->_0C = ((pBuffer[3] & 0xf) << 8) | pBuffer[2]; + pSound->_0C = (pBuffer->_3_3 << 8) | pBuffer->_2; if (xyzIndex == 2) { pSound->_08 = __PitchTo32_VRC_C(pSound->_0C); } else { @@ -477,16 +539,16 @@ void __Sound_Write_VRC(u16 a, u8 b) { } if (xyzIndex == 0) { - v = SBUFFER[213] & 1; + v = sbuffer.apu._D5_0; } if (xyzIndex == 1) { - v = SBUFFER[213] >> 1 & 1; + v = sbuffer.apu._D5_1; } if (xyzIndex == 2) { - v = SBUFFER[213] >> 2 & 1; + v = sbuffer.apu._D5_2; } - if ((u8)v == 1 && (pBuffer[3] >> 7) & 1) { + if ((u8)v == 1 && pBuffer->_3_7) { pSound->_00 = 1; } else { pSound->_00 = 0; @@ -500,7 +562,7 @@ void __Sound_Write_VRC(u16 a, u8 b) { void __Sound_Write_MMC5(u16 a, u8 b) { NESSoundStruct* pSound; - u8* pBuffer; + PulseChannel* pBuffer; u32 v; int xyzIndex; @@ -509,15 +571,15 @@ void __Sound_Write_MMC5(u16 a, u8 b) { if (index <= 3) { pSound = &SoundX; xyzIndex = 0; - pBuffer = &SBUFFER[192]; + pBuffer = (PulseChannel*)&sbuffer.apu._C0; } else if (index <= 7) { pSound = &SoundY; xyzIndex = 1; - pBuffer = &SBUFFER[196]; + pBuffer = (PulseChannel*)&sbuffer.apu._C4; } if (index == 17) { - SoundZ._3E = (b << 6) & 0x3fc0; + SoundZ._3E = (b & 0xff) << 6; } else if (index == 21) { if (!(b & 1)) { SoundX._00 = 0; @@ -528,15 +590,15 @@ void __Sound_Write_MMC5(u16 a, u8 b) { } else if (pBuffer) { switch (index & 3) { case 0: { - pSound->_3C = (pBuffer[0] >> 6) & 0x3; + pSound->_3C = pBuffer->Duty; v = pSound->_28; - pSound->_28 = (pBuffer[0] >> 4 & 1) ^ 1; - pSound->_14 = (pBuffer[0] >> 5 & 1); - pSound->_1D = VOLTABLE_HVCPULSE[pBuffer[0] & 0xf]; + pSound->_28 = pBuffer->ConstantVolume ^ 1; + pSound->_14 = pBuffer->EnvelopeLoopCounter; + pSound->_1D = VOLTABLE_HVCPULSE[pBuffer->EnvelopePeriod_Volume]; if (pSound->_28 == 0 && pSound->_00 == 1) { - pSound->_1C = VOLTABLE_HVCPULSE[pBuffer[0] & 0xf]; + pSound->_1C = VOLTABLE_HVCPULSE[pBuffer->EnvelopePeriod_Volume]; } else { - pSound->_24 = PHASE_SAMPLE * ((pBuffer[0] & 0xf) + 1); + pSound->_24 = PHASE_SAMPLE * (pBuffer->EnvelopePeriod_Volume + 1); if (v == 0) { pSound->_2A = 0xf; pSound->_20 = 0; @@ -544,30 +606,30 @@ void __Sound_Write_MMC5(u16 a, u8 b) { } } break; case 2: { - pSound->_0C = ((pBuffer[3] & 0x7) << 8) | pBuffer[2]; + pSound->_0C = pBuffer->TimerHigh << 8 | pBuffer->TimerLow; pSound->_08 = __PitchTo32_HVC_C(pSound->_0C); } break; case 3: { - pSound->_0C = ((pBuffer[3] & 0x7) << 8) | pBuffer[2]; + pSound->_0C = pBuffer->TimerHigh << 8 | pBuffer->TimerLow; pSound->_08 = __PitchTo32_HVC_C(pSound->_0C); - pSound->_18 = LEN_TABLE_HVC[(pBuffer[3] >> 3) & 0x1f]; + pSound->_18 = LEN_TABLE_HVC[pBuffer->LengthCounterLow]; pSound->_10 = FRAME_SAMPLE * pSound->_18; if (!pSound->_00 && !pSound->_3E) { pSound->_04 = 0; } if (xyzIndex == 0) { - v = SBUFFER[213] & 1; + v = sbuffer.apu._D5_0; } if (xyzIndex == 1) { - v = SBUFFER[213] >> 1 & 1; + v = sbuffer.apu._D5_1; } if ((v & 0xff) != 0) { pSound->_00 = 1; } - if ((pBuffer[0] >> 4 & 1) == 0) { + if (pBuffer->ConstantVolume == 0) { pSound->_1C = VOLTABLE_HVCPULSE[15]; } else { pSound->_1C = pSound->_1D; @@ -1071,6 +1133,13 @@ s8 __GetNoise(u32 a) { } } +u32 delta_counter; +s8 delta_sign; +s32 bias_move; +s32 bias; +f32 voltage; +f32 voltage_out; + int __ProcessSoundD() { s16 ret; if (!SoundD._00) { @@ -1318,7 +1387,6 @@ void __Sound_Write_C(u16 a, u8 b) { } break; } } -u32 exitflag; int __ProcessSoundC() { static s16 timer = 0; @@ -1368,10 +1436,7 @@ int __ProcessSoundC() { u8 DISKSUB_TABLE[32]; s16 disksubwave[32][2]; s8 DISK_SUB_GAIN[] = { 0, 1, 2, 4, 0, -4, -2, -1 }; -u8* NOISE_DTABLE; -MixCallback old_mixcall; -u8 old_mixmode; void __CreateDiskSubWave() { for (int i = 0; i < 32; i++) { disksubwave[i][0] = DISK_SUB_GAIN[DISKSUB_TABLE[i]]; @@ -1383,6 +1448,8 @@ u32 __PitchTo32_DISKFM(u16 v) { return (0.85343015f * (int)v) / 500.4375f * 32768.f; } +u32 DISK_FRAME_SAMPLE = 0x215; + void __Sound_Write_Disk(u16 a, u8 b) { static int shiftr = 0; ((u8*)&sbuffer)[a] = b; @@ -1392,78 +1459,86 @@ void __Sound_Write_Disk(u16 a, u8 b) { SoundF._2C = 0; } } else if (a >= 0x40 && a <= 0x7f) { - DISKFM_TABLE[a - 0x40] = SBUFFER[a] & 0x3f; + DISKFM_TABLE[a - 0x40] = ((WaveTableEntry*)&sbuffer.buff[a])->Sample; } else { switch (a) { case 0x80: { - s8 c = -((char)SBUFFER[128] >> 7); - SoundF._2E = SBUFFER[128] >> 6 & 1; - if (c == 1) { - SoundF._2E = SBUFFER[128] & 0x3F; + u32 old_2c = SoundF._2C; + SoundF._2C = sbuffer.apu.VolumeEnvelopeEnabled; + SoundF._2E = sbuffer.apu.VolumeEnvelopeIncreasing; + if (SoundF._2C == 1) { + SoundF._2D = sbuffer.apu.VolumeEnvelopeGainAndSpeed; + } else { + SoundF._28 = (DISK_FRAME_SAMPLE * (sbuffer.apu.VolumeEnvelopeGainAndSpeed + 1)) >> 4; + } + if (SoundF._2C != old_2c) { + SoundF._24 = 0; } } break; case 0x82: { - s8 c = -((char)SBUFFER[128] >> 7); - SoundF._2E = SBUFFER[128] >> 6 & 1; - if (c == 1) { - SoundF._2E = SBUFFER[128] & 0x3F; - } + SoundF._14 = sbuffer.apu.FrequencyHigh << 8 | sbuffer.apu.FrequencyLow; + SoundF._10 = __PitchTo32_DISKFM(SoundF._14); } break; case 0x83: { - s8 c = -((char)SBUFFER[128] >> 7); - SoundF._2E = SBUFFER[128] >> 6 & 1; - if (c == 1) { - SoundF._2E = SBUFFER[128] & 0x3F; + SoundF._14 = sbuffer.apu.FrequencyHigh << 8 | sbuffer.apu.FrequencyLow; + SoundF._10 = __PitchTo32_DISKFM(SoundF._14); + if (sbuffer.apu.HighSpeedFrequency) { + SoundF._04 = 0; } } break; case 0x84: { - s8 c = -((char)SBUFFER[128] >> 7); - SoundF._2E = SBUFFER[128] >> 6 & 1; - if (c == 1) { - SoundF._2E = SBUFFER[128] & 0x3F; + u32 c = SoundF._38; + SoundF._38 = sbuffer.apu.ModEnvelopeEnabled; + SoundF._3A = sbuffer.apu.ModEnvelopeIncreasing; + if (SoundF._38 == 1) { + SoundF._39 = sbuffer.apu.ModEnvelopeGainAndSpeed; + } else { + SoundF._34 = (DISK_FRAME_SAMPLE * (sbuffer.apu.ModEnvelopeGainAndSpeed + 1)) >> 4; + } + if (SoundF._38 != c) { + SoundF._30 = 0; } } break; case 0x85: { - s8 c = -((char)SBUFFER[128] >> 7); - SoundF._2E = SBUFFER[128] >> 6 & 1; - if (c == 1) { - SoundF._2E = SBUFFER[128] & 0x3F; + SoundF._44 = sbuffer.apu.ModCounter; + if (SoundF._44 & 0x40) { + SoundF._44 |= 0x80; } } break; case 0x86: { - s8 c = -((char)SBUFFER[128] >> 7); - SoundF._2E = SBUFFER[128] >> 6 & 1; - if (c == 1) { - SoundF._2E = SBUFFER[128] & 0x3F; - } + SoundF._1C = sbuffer.apu.ModFrequencyHigh << 8 | sbuffer.apu.ModFrequencyLow; + SoundF._18 = __PitchTo32_DISKFM(SoundF._1C); } break; case 0x87: { - s8 c = -((char)SBUFFER[128] >> 7); - SoundF._2E = SBUFFER[128] >> 6 & 1; - if (c == 1) { - SoundF._2E = SBUFFER[128] & 0x3F; + u32 c = sbuffer.apu.HaltModTableCounter; + SoundF._1C = sbuffer.apu.ModFrequencyHigh << 8 | sbuffer.apu.ModFrequencyLow; + SoundF._18 = __PitchTo32_DISKFM(SoundF._1C); + SoundF._46 = sbuffer.apu.HaltModTableCounter; + if (!SoundF._46 && c == 1) { + __CreateDiskSubWave(); } + if (SoundF._46) { + shiftr = 0; + } + SoundF._0C = -1; + SoundF._08 = 0; + SoundF._47 = 0; + } break; case 0x88: { - s8 c = -((char)SBUFFER[128] >> 7); - SoundF._2E = SBUFFER[128] >> 6 & 1; - if (c == 1) { - SoundF._2E = SBUFFER[128] & 0x3F; + if (shiftr < 0x20) { + DISKSUB_TABLE[shiftr & 0x1f] = b & 7; + if (++shiftr == 0x20) { + __CreateDiskSubWave(); + } } } break; case 0x89: { - s8 c = -((char)SBUFFER[128] >> 7); - SoundF._2E = SBUFFER[128] >> 6 & 1; - if (c == 1) { - SoundF._2E = SBUFFER[128] & 0x3F; - } + SoundF._43 = DISKFM_GAINTABLE[sbuffer.apu.WaveTableMasterVolume]; + SoundF._45 = sbuffer.apu.WaveTableWriteEnable; } break; case 0x8a: { - s8 c = -((char)SBUFFER[128] >> 7); - SoundF._2E = SBUFFER[128] >> 6 & 1; - if (c == 1) { - SoundF._2E = SBUFFER[128] & 0x3F; - } + SoundF._48 = sbuffer.apu.EnvelopeSpeed; } break; } } @@ -1580,18 +1655,15 @@ void ForceProcessPhaseCounter() { void Sound_Make_HVC(s32 count, s16* v) { static int lastsample; - int j; - int a, b, c, d, e; - int i; HS_Event_Update(); - for (i = 0; i < count; i++) { + for (int i = 0; i < count; i++) { ProcessPhaseCounter(); - a = __ProcessSoundA(); - b = __ProcessSoundB(); - c = __ProcessSoundC(); - d = __ProcessSoundD(); - e = __ProcessSoundE(); - j = (s16)a + (s16)b - (s16)c - (s16)d + (s16)e; + int a = __ProcessSoundA(); + int b = __ProcessSoundB(); + int c = __ProcessSoundC(); + int d = __ProcessSoundD(); + int e = __ProcessSoundE(); + int j = (s16)a + (s16)b - (s16)c - (s16)d + (s16)e; if (j >= 0x7fff) { j = 0x7fff; } else if (j <= -0x7fff) { @@ -1729,7 +1801,9 @@ void Sound_Reset() { Buffer_Reset(); } -u8 move_to_50; +u32 exitflag; +MixCallback old_mixcall; +u8 old_mixmode; s16* __FrameCallback(s32 a) { static s16 buf[0x320]; @@ -1821,9 +1895,6 @@ void Sound_SetE000(u8* romTop) { ROM_TOP_E000 = romTop; } -u8 MMC_MODE; -u8 beforemode; - void Sound_SetMMC(u8 mmcMode) { FRAME_SAMPLE = 0x280; PHASE_SAMPLE = 0xa0; @@ -1903,3 +1974,9 @@ void __Sound_Write_HVC(u16 index, u8 v) { } } } + +// UNUSED +void* PCM[9] = { (void*)&_STOP, (void*)&_STOP, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; + +// UNUSED +u32 PCMSIZE[9] = { sizeof(_STOP), sizeof(_STOP), 0, 0, 0, 0, 0, 0, 0 }; From 2ead77759e5b0c0f7cd6adbd385fa444ffc2bfb4 Mon Sep 17 00:00:00 2001 From: roeming Date: Fri, 21 Mar 2025 22:16:18 -0400 Subject: [PATCH 5/7] fix sbss/data ordering, 1 func left --- include/jaudio_NES/emusound.hpp | 2 +- src/static/jaudio_NES/game/emusound.c | 60 +++++++++++++++------------ 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/include/jaudio_NES/emusound.hpp b/include/jaudio_NES/emusound.hpp index 67752753..e38266bf 100644 --- a/include/jaudio_NES/emusound.hpp +++ b/include/jaudio_NES/emusound.hpp @@ -39,7 +39,7 @@ void HS_Event_Update(); void HS_Event_Write(u16, u8); void ProcessPhaseCounter(); void ForceProcessPhaseCounter(); -void Sound_Make_HVC(s32, s16*); +int Sound_Make_HVC(s32, s16*); void Buffer_Reset(); void Sample_Copy(u16, s16*); s16* __FrameCallback(s32); diff --git a/src/static/jaudio_NES/game/emusound.c b/src/static/jaudio_NES/game/emusound.c index e5d921bd..46e2f609 100644 --- a/src/static/jaudio_NES/game/emusound.c +++ b/src/static/jaudio_NES/game/emusound.c @@ -145,12 +145,6 @@ NESSoundStructF SoundF; NESSoundStruct3 SoundP; u8 DUMMY_ACTIVE[9]; -// sdata -u32 NOISE_MASTER = 1; -u32 NOISE_SHIFT = 0x800; -u32 PHASE_SAMPLE = 0x85; -u32 FRAME_SAMPLE = 0x215; -u32 _STOP[2] = { 0 }; // sbss u8 beforemode; @@ -245,12 +239,12 @@ typedef struct _WaveTableEntry { typedef struct _unknown_C0 { u8 _0_7 : 1; // 10000000 - u8 _0_6 : 3; // 01000000 + u8 _0_6 : 3; // 01100000 u8 _0_3 : 4; // 00001111 u8 _1; u8 _2; u8 _3_7 : 1; // 10000000 - u8 _3_6 : 3; // 01000000 + u8 _3_6 : 3; // 01110000 u8 _3_3 : 4; // 00001111 } Unknown_VRC; @@ -352,8 +346,9 @@ s8 TRIANGLE_TABLE[] = { 0x0f, 0x00, 0xef, 0xde, 0xcd, 0xbb, 0xaa, 0x99, 0x88, 0x88, 0x99, 0xaa, 0xbb, 0xcd, 0xde, 0xef }; -int NOISE_TABLE[] = { 0x000df86a, 0x0006fc35, 0x00037e1a, 0x0001bf0d, 0x0000df86, 0x00009504, 0x00006fc3, 0x00005969, - 0x000046d1, 0x00003852, 0x000025a5, 0x00001c29, 0x000012c6, 0x00000e14, 0x00000708, 0x000006fd }; +static int NOISE_TABLE[] = { 0x000df86a, 0x0006fc35, 0x00037e1a, 0x0001bf0d, 0x0000df86, 0x00009504, + 0x00006fc3, 0x00005969, 0x000046d1, 0x00003852, 0x000025a5, 0x00001c29, + 0x000012c6, 0x00000e14, 0x00000708, 0x000006fd }; u8 NOISE_PULSE_TABLE[] = { 0x30, 0x32, 0x34, 0x38, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x42, 0x44, 0x46, 0x48, 0x50, 0x60, 0x60 }; @@ -394,7 +389,20 @@ u32 DISKFM_GAINTABLE[] = { 30, 20, 15, 12 }; u8 DISKFM_TABLE[0x40]; // UNUSED -u32 DEB1[4] = { 0, 0, 0, 0 }; + +u8 DEB1[16] = { 0 }; +// sdata +s8 DISK_SUB_GAIN[] = { 0, 1, 2, 4, 0, -4, -2, -1 }; +u8* ROM_TOP_C000 = DEB1; +u8* ROM_TOP_E000 = DEB1; +u32 DISK_FRAME_SAMPLE = 0x215; +u32 FRAME_SAMPLE = 0x215; +u32 PHASE_SAMPLE = 0x85; +u32 NOISE_MASTER = 1; +u32 NOISE_SHIFT = 0x800; +int write_pointer = 0x690; +int buffer_remain = 0x690; +u32 _STOP[2] = { 0 }; f32 VOLTABLE_HVCPULSE[] = { 0.0f, 0.080128, 0.157051f, 0.224359f, 0.294872f, 0.365385f, 0.435897f, 0.50641f, 0.592949f, 0.657051f, 0.730769f, 0.801282f, @@ -1264,9 +1272,6 @@ void StartE() { bias_move = 0; } -u8* ROM_TOP_C000 = (u8*)&DEB1; -u8* ROM_TOP_E000 = (u8*)&DEB1; - int __ProcessSoundE() { if (SoundE._00) { for (int i = 0; i < 2u; i++) { @@ -1435,7 +1440,6 @@ int __ProcessSoundC() { u8 DISKSUB_TABLE[32]; s16 disksubwave[32][2]; -s8 DISK_SUB_GAIN[] = { 0, 1, 2, 4, 0, -4, -2, -1 }; void __CreateDiskSubWave() { for (int i = 0; i < 32; i++) { @@ -1448,11 +1452,9 @@ u32 __PitchTo32_DISKFM(u16 v) { return (0.85343015f * (int)v) / 500.4375f * 32768.f; } -u32 DISK_FRAME_SAMPLE = 0x215; - void __Sound_Write_Disk(u16 a, u8 b) { static int shiftr = 0; - ((u8*)&sbuffer)[a] = b; + sbuffer.buff[a] = b; if (a == 0x23) { if (!(b & 2)) { SoundF._2D = 0; @@ -1653,7 +1655,7 @@ void ForceProcessPhaseCounter() { ProcessPhaseCounter(); } -void Sound_Make_HVC(s32 count, s16* v) { +int Sound_Make_HVC(s32 count, s16* v) { static int lastsample; HS_Event_Update(); for (int i = 0; i < count; i++) { @@ -1688,8 +1690,6 @@ void Sound_Make_HVC(s32 count, s16* v) { s16 sound_loop_buffer[0x2000]; int read_pointer; -int write_pointer = 0x690; -int buffer_remain = 0x690; void Buffer_Reset() { for (int i = 0; i < ARRAY_COUNT(sound_loop_buffer); i++) { @@ -1821,9 +1821,8 @@ s16* __FrameCallback(s32 a) { Jac_RegisterMixcallback(old_mixcall, old_mixmode); exitflag = FALSE; for (int i = 0; i < a; i++) { - f32 f3 = f2 * buf[i]; + buf[i] = f2 * buf[i]; f2 -= f; - buf[i] = f3; } } return buf; @@ -1859,18 +1858,25 @@ u8 Sound_Read(u16 param_1, u32 param_2, u32 param_3, u32 param_4, u32 param_5) { if (DUMMY_ACTIVE[0]) { a = DUMMY_ACTIVE[0] - 1; } - b = SoundB._00; + if (DUMMY_ACTIVE[1]) { b = DUMMY_ACTIVE[1] - 1; + } else { + b = SoundB._00; } - c = SoundC._00; + if (DUMMY_ACTIVE[2]) { c = DUMMY_ACTIVE[2] - 1; + } else { + c = SoundC._00; } - d = SoundD._00; + if (DUMMY_ACTIVE[3]) { d = DUMMY_ACTIVE[3] - 1; + } else { + d = SoundD._00; } + e = SoundE._00; if (DUMMY_ACTIVE[4]) { e = DUMMY_ACTIVE[4] - 1; @@ -1908,7 +1914,7 @@ void Sound_PlayMENUPCM(u8 v) { } void __Sound_Write_HVC(u16 index, u8 v) { - ((u8*)&sbuffer)[index] = v; + sbuffer.buff[index] = v; if (index >= 0xc0) { switch (MMC_MODE) { case 1: { From 320d02452a61777fe903004a8b7f3735229b5ffb Mon Sep 17 00:00:00 2001 From: roeming Date: Sat, 22 Mar 2025 10:58:51 -0400 Subject: [PATCH 6/7] link emusound --- configure.py | 2 +- src/static/jaudio_NES/game/emusound.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/configure.py b/configure.py index c538f585..b999b4cc 100644 --- a/configure.py +++ b/configure.py @@ -734,7 +734,7 @@ config.libs = [ "objects": [ Object(Matching, "jaudio_NES/game/audioheaders.c"), Object(Matching, "jaudio_NES/game/dummyprobe.c"), - Object(NonMatching, "jaudio_NES/game/emusound.c", extra_cflags=["-O4,s", "-fp_contract on", "-func_align 32"]), + Object(Matching, "jaudio_NES/game/emusound.c", extra_cflags=["-O4,s", "-fp_contract on", "-func_align 32", "-vector on"]), Object(NonMatching, "jaudio_NES/game/game64.c"), Object(Matching, "jaudio_NES/game/kappa.c"), Object(Matching, "jaudio_NES/game/melody.c"), diff --git a/src/static/jaudio_NES/game/emusound.c b/src/static/jaudio_NES/game/emusound.c index 46e2f609..9cc35398 100644 --- a/src/static/jaudio_NES/game/emusound.c +++ b/src/static/jaudio_NES/game/emusound.c @@ -615,11 +615,11 @@ void __Sound_Write_MMC5(u16 a, u8 b) { } break; case 2: { pSound->_0C = pBuffer->TimerHigh << 8 | pBuffer->TimerLow; - pSound->_08 = __PitchTo32_HVC_C(pSound->_0C); + pSound->_08 = __PitchTo32_HVC(pSound->_0C); } break; case 3: { pSound->_0C = pBuffer->TimerHigh << 8 | pBuffer->TimerLow; - pSound->_08 = __PitchTo32_HVC_C(pSound->_0C); + pSound->_08 = __PitchTo32_HVC(pSound->_0C); pSound->_18 = LEN_TABLE_HVC[pBuffer->LengthCounterLow]; pSound->_10 = FRAME_SAMPLE * pSound->_18; if (!pSound->_00 && !pSound->_3E) { @@ -1909,9 +1909,11 @@ void Sound_SetMMC(u8 mmcMode) { Sound_Reset(); } +#pragma force_active on void Sound_PlayMENUPCM(u8 v) { SoundP._0D = v; } +#pragma force_active reset void __Sound_Write_HVC(u16 index, u8 v) { sbuffer.buff[index] = v; From fcd788f44c336d99a3daf1dc28ad44138e483611 Mon Sep 17 00:00:00 2001 From: roeming Date: Sat, 22 Mar 2025 11:37:20 -0400 Subject: [PATCH 7/7] adding comments to apu registers --- src/static/jaudio_NES/game/emusound.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/static/jaudio_NES/game/emusound.c b/src/static/jaudio_NES/game/emusound.c index 9cc35398..37a481bf 100644 --- a/src/static/jaudio_NES/game/emusound.c +++ b/src/static/jaudio_NES/game/emusound.c @@ -170,6 +170,7 @@ f32 NOISE_FREQ_TABLE[] = { 4.f, 2.f, 1.f, 0.5f, 0.25f, 0.2f, 0.15f, 0.12f // https://www.nesdev.org/wiki/APU_registers typedef struct _PulseChannel { + // https://www.nesdev.org/wiki/APU_Pulse // $4000/$4004 u8 Duty : 2; u8 EnvelopeLoopCounter : 1; @@ -188,6 +189,7 @@ typedef struct _PulseChannel { } PulseChannel; typedef struct _TriangleChannel { + // https://www.nesdev.org/wiki/APU_Triangle // $4008 u8 LengthCounter : 1; u8 LinearCounterReloadVaue : 7; @@ -201,6 +203,7 @@ typedef struct _TriangleChannel { } TriangleChannel; typedef struct _NoiseChannel { + // https://www.nesdev.org/wiki/APU_Noise // $400C u8 _unused_400C_high2 : 2; u8 LoopEnvelope : 1; @@ -218,6 +221,7 @@ typedef struct _NoiseChannel { } NoiseChannel; typedef struct _DMCChannel { + // https://www.nesdev.org/wiki/APU_DMC // $4010 u8 IRQEnable : 1; u8 LoopSample : 1; @@ -261,6 +265,7 @@ typedef struct _APURegisters { DMCChannel DMC; // $4014 u8 _unused_4014; + // https://www.nesdev.org/wiki/APU#Status_($4015) // $4015 u8 DMCInterrupt : 1; u8 FrameInterrupt : 1; @@ -272,6 +277,7 @@ typedef struct _APURegisters { u8 Pulse1Status : 1; // $4016 u8 _unused_4016; + // https://www.nesdev.org/wiki/APU#Frame_Counter_($4017) // $4017 u8 FrameCounter_5FrameSequence : 1; u8 FrameCounter_DisableFrameInterrupt : 1;