mirror of
https://github.com/PCSX2/pcsx2.git
synced 2025-12-16 04:08:48 +00:00
Merge cbde6401d2 into d69c71e058
This commit is contained in:
commit
ea51820837
@ -247,7 +247,6 @@ set(pcsx2SPU2Sources
|
||||
SPU2/ADSR.cpp
|
||||
SPU2/Debug.cpp
|
||||
SPU2/Dma.cpp
|
||||
SPU2/Mixer.cpp
|
||||
SPU2/spu2.cpp
|
||||
SPU2/ReadInput.cpp
|
||||
SPU2/RegTable.cpp
|
||||
@ -258,6 +257,7 @@ set(pcsx2SPU2Sources
|
||||
)
|
||||
|
||||
set(pcsx2SPU2SourcesUnshared
|
||||
SPU2/Mixer.cpp
|
||||
SPU2/ReverbResample.cpp
|
||||
)
|
||||
|
||||
|
||||
@ -9,6 +9,28 @@
|
||||
|
||||
#include "common/Assertions.h"
|
||||
|
||||
// LOOP/END sets the ENDX bit and sets NAX to LSA, and the voice is muted if LOOP is not set
|
||||
// LOOP seems to only have any effect on the block with LOOP/END set, where it prevents muting the voice
|
||||
// (the documented requirement that every block in a loop has the LOOP bit set is nonsense according to tests)
|
||||
// LOOP/START sets LSA to NAX unless LSA was written manually since sound generation started
|
||||
// (see LoopMode, the method by which this is achieved on the real SPU2 is unknown)
|
||||
#define XAFLAG_LOOP_END (1ul << 0)
|
||||
#define XAFLAG_LOOP (1ul << 1)
|
||||
#define XAFLAG_LOOP_START (1ul << 2)
|
||||
|
||||
#if MULTI_ISA_COMPILE_ONCE
|
||||
// decoded pcm data, used to cache the decoded data so that it needn't be decoded
|
||||
// multiple times. Cache chunks are decoded when the mixer requests the blocks, and
|
||||
// invalided when DMA transfers and memory writes are performed.
|
||||
PcmCacheEntry pcm_cache_data[pcm_BlockCount];
|
||||
|
||||
int g_counter_cache_hits = 0;
|
||||
int g_counter_cache_misses = 0;
|
||||
int g_counter_cache_ignores = 0;
|
||||
#endif
|
||||
|
||||
MULTI_ISA_UNSHARED_START
|
||||
|
||||
static const s32 tbl_XA_Factor[16][2] =
|
||||
{
|
||||
{0, 0},
|
||||
@ -71,24 +93,6 @@ static void __forceinline IncrementNextA(V_Core& thiscore, uint voiceidx)
|
||||
vc.NextA &= 0xFFFFF;
|
||||
}
|
||||
|
||||
// decoded pcm data, used to cache the decoded data so that it needn't be decoded
|
||||
// multiple times. Cache chunks are decoded when the mixer requests the blocks, and
|
||||
// invalided when DMA transfers and memory writes are performed.
|
||||
PcmCacheEntry pcm_cache_data[pcm_BlockCount];
|
||||
|
||||
int g_counter_cache_hits = 0;
|
||||
int g_counter_cache_misses = 0;
|
||||
int g_counter_cache_ignores = 0;
|
||||
|
||||
// LOOP/END sets the ENDX bit and sets NAX to LSA, and the voice is muted if LOOP is not set
|
||||
// LOOP seems to only have any effect on the block with LOOP/END set, where it prevents muting the voice
|
||||
// (the documented requirement that every block in a loop has the LOOP bit set is nonsense according to tests)
|
||||
// LOOP/START sets LSA to NAX unless LSA was written manually since sound generation started
|
||||
// (see LoopMode, the method by which this is achieved on the real SPU2 is unknown)
|
||||
#define XAFLAG_LOOP_END (1ul << 0)
|
||||
#define XAFLAG_LOOP (1ul << 1)
|
||||
#define XAFLAG_LOOP_START (1ul << 2)
|
||||
|
||||
static __forceinline s32 GetNextDataBuffered(V_Core& thiscore, uint voiceidx)
|
||||
{
|
||||
V_Voice& vc(thiscore.Voices[voiceidx]);
|
||||
@ -434,8 +438,6 @@ static __forceinline StereoOut32 MixVoice(uint coreidx, uint voiceidx)
|
||||
return voiceOut;
|
||||
}
|
||||
|
||||
const VoiceMixSet VoiceMixSet::Empty((StereoOut32()), (StereoOut32())); // Don't use SteroOut32::Empty because C++ doesn't make any dep/order checks on global initializers.
|
||||
|
||||
static __forceinline void MixCoreVoices(VoiceMixSet& dest, const uint coreidx)
|
||||
{
|
||||
V_Core& thiscore(Cores[coreidx]);
|
||||
@ -453,40 +455,42 @@ static __forceinline void MixCoreVoices(VoiceMixSet& dest, const uint coreidx)
|
||||
}
|
||||
}
|
||||
|
||||
StereoOut32 V_Core::Mix(const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext)
|
||||
static __forceinline StereoOut32 MixCore(const uint coreidx, const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext)
|
||||
{
|
||||
MasterVol.Update();
|
||||
UpdateNoise(*this);
|
||||
V_Core& thiscore(Cores[coreidx]);
|
||||
|
||||
thiscore.MasterVol.Update();
|
||||
UpdateNoise(thiscore);
|
||||
|
||||
// Saturate final result to standard 16 bit range.
|
||||
const VoiceMixSet Voices(clamp_mix(inVoices.Dry), clamp_mix(inVoices.Wet));
|
||||
|
||||
// Write Mixed results To Output Area
|
||||
spu2M_WriteFast(((0 == Index) ? 0x1000 : 0x1800) + OutPos, Voices.Dry.Left);
|
||||
spu2M_WriteFast(((0 == Index) ? 0x1200 : 0x1A00) + OutPos, Voices.Dry.Right);
|
||||
spu2M_WriteFast(((0 == Index) ? 0x1400 : 0x1C00) + OutPos, Voices.Wet.Left);
|
||||
spu2M_WriteFast(((0 == Index) ? 0x1600 : 0x1E00) + OutPos, Voices.Wet.Right);
|
||||
spu2M_WriteFast(((0 == thiscore.Index) ? 0x1000 : 0x1800) + OutPos, Voices.Dry.Left);
|
||||
spu2M_WriteFast(((0 == thiscore.Index) ? 0x1200 : 0x1A00) + OutPos, Voices.Dry.Right);
|
||||
spu2M_WriteFast(((0 == thiscore.Index) ? 0x1400 : 0x1C00) + OutPos, Voices.Wet.Left);
|
||||
spu2M_WriteFast(((0 == thiscore.Index) ? 0x1600 : 0x1E00) + OutPos, Voices.Wet.Right);
|
||||
|
||||
// Write mixed results to logfile (if enabled)
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
WaveDump::WriteCore(Index, CoreSrc_DryVoiceMix, Voices.Dry);
|
||||
WaveDump::WriteCore(Index, CoreSrc_WetVoiceMix, Voices.Wet);
|
||||
WaveDump::WriteCore(thiscore.Index, CoreSrc_DryVoiceMix, Voices.Dry);
|
||||
WaveDump::WriteCore(thiscore.Index, CoreSrc_WetVoiceMix, Voices.Wet);
|
||||
#endif
|
||||
|
||||
// Mix in the Input data
|
||||
|
||||
StereoOut32 TD(
|
||||
Input.Left & DryGate.InpL,
|
||||
Input.Right & DryGate.InpR);
|
||||
Input.Left & thiscore.DryGate.InpL,
|
||||
Input.Right & thiscore.DryGate.InpR);
|
||||
|
||||
// Mix in the Voice data
|
||||
TD.Left += Voices.Dry.Left & DryGate.SndL;
|
||||
TD.Right += Voices.Dry.Right & DryGate.SndR;
|
||||
TD.Left += Voices.Dry.Left & thiscore.DryGate.SndL;
|
||||
TD.Right += Voices.Dry.Right & thiscore.DryGate.SndR;
|
||||
|
||||
// Mix in the External (nothing/core0) data
|
||||
TD.Left += Ext.Left & DryGate.ExtL;
|
||||
TD.Right += Ext.Right & DryGate.ExtR;
|
||||
TD.Left += Ext.Left & thiscore.DryGate.ExtL;
|
||||
TD.Right += Ext.Right & thiscore.DryGate.ExtR;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Reverberation Effects Processing
|
||||
@ -510,27 +514,27 @@ StereoOut32 V_Core::Mix(const VoiceMixSet& inVoices, const StereoOut32& Input, c
|
||||
|
||||
// Mix Input, Voice, and External data:
|
||||
|
||||
TW.Left = Input.Left & WetGate.InpL;
|
||||
TW.Right = Input.Right & WetGate.InpR;
|
||||
TW.Left = Input.Left & thiscore.WetGate.InpL;
|
||||
TW.Right = Input.Right & thiscore.WetGate.InpR;
|
||||
|
||||
TW.Left += Voices.Wet.Left & WetGate.SndL;
|
||||
TW.Right += Voices.Wet.Right & WetGate.SndR;
|
||||
TW.Left += Ext.Left & WetGate.ExtL;
|
||||
TW.Right += Ext.Right & WetGate.ExtR;
|
||||
TW.Left += Voices.Wet.Left & thiscore.WetGate.SndL;
|
||||
TW.Right += Voices.Wet.Right & thiscore.WetGate.SndR;
|
||||
TW.Left += Ext.Left & thiscore.WetGate.ExtL;
|
||||
TW.Right += Ext.Right & thiscore.WetGate.ExtR;
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
WaveDump::WriteCore(Index, CoreSrc_PreReverb, TW);
|
||||
WaveDump::WriteCore(thiscore.Index, CoreSrc_PreReverb, TW);
|
||||
#endif
|
||||
|
||||
StereoOut32 RV = DoReverb(TW);
|
||||
StereoOut32 RV = thiscore.DoReverb(TW);
|
||||
|
||||
#ifdef PCSX2_DEVBUILD
|
||||
WaveDump::WriteCore(Index, CoreSrc_PostReverb, RV);
|
||||
WaveDump::WriteCore(thiscore.Index, CoreSrc_PostReverb, RV);
|
||||
#endif
|
||||
|
||||
// Mix Dry + Wet
|
||||
// (master volume is applied later to the result of both outputs added together).
|
||||
return TD + ApplyVolume(RV, FxVol);
|
||||
return TD + ApplyVolume(RV, thiscore.FxVol);
|
||||
}
|
||||
|
||||
static StereoOut32 DCFilter(StereoOut32 input) {
|
||||
@ -546,7 +550,7 @@ static StereoOut32 DCFilter(StereoOut32 input) {
|
||||
return output;
|
||||
}
|
||||
|
||||
__forceinline void spu2Mix()
|
||||
void spu2Mix()
|
||||
{
|
||||
// Note: Playmode 4 is SPDIF, which overrides other inputs.
|
||||
StereoOut32 InputData[2] =
|
||||
@ -566,11 +570,12 @@ __forceinline void spu2Mix()
|
||||
#endif
|
||||
|
||||
// Todo: Replace me with memzero initializer!
|
||||
VoiceMixSet VoiceData[2] = {VoiceMixSet::Empty, VoiceMixSet::Empty}; // mixed voice data for each core.
|
||||
VoiceMixSet VoiceData[2] = {{StereoOut32(), StereoOut32()}, {StereoOut32(), StereoOut32()}}; // mixed voice data for each core.
|
||||
|
||||
MixCoreVoices(VoiceData[0], 0);
|
||||
MixCoreVoices(VoiceData[1], 1);
|
||||
|
||||
StereoOut32 Ext(Cores[0].Mix(VoiceData[0], InputData[0], StereoOut32::Empty));
|
||||
StereoOut32 Ext(MixCore(0, VoiceData[0], InputData[0], StereoOut32::Empty));
|
||||
|
||||
if ((PlayMode & 4) || (Cores[0].Mute != 0))
|
||||
Ext = StereoOut32::Empty;
|
||||
@ -588,7 +593,7 @@ __forceinline void spu2Mix()
|
||||
#endif
|
||||
|
||||
Ext = ApplyVolume(Ext, Cores[1].ExtVol);
|
||||
StereoOut32 Out(Cores[1].Mix(VoiceData[1], InputData[1], Ext));
|
||||
StereoOut32 Out(MixCore(1, VoiceData[1], InputData[1], Ext));
|
||||
|
||||
if (PlayMode & 8)
|
||||
{
|
||||
@ -645,3 +650,5 @@ __forceinline void spu2Mix()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MULTI_ISA_UNSHARED_END
|
||||
|
||||
@ -63,11 +63,12 @@ struct StereoOut32
|
||||
}
|
||||
};
|
||||
|
||||
extern void (*spu2Mix)();
|
||||
extern s16* GetMemPtr(u32 addr);
|
||||
extern s16 spu2M_Read(u32 addr);
|
||||
extern void spu2M_Write(u32 addr, s16 value);
|
||||
extern void spu2M_Write(u32 addr, u16 value);
|
||||
extern void spu2Mix();
|
||||
MULTI_ISA_DEF(void spu2Mix();)
|
||||
extern void spu2Output(StereoOut32 out);
|
||||
|
||||
static __forceinline s16 SignExtend16(u16 v)
|
||||
@ -404,7 +405,6 @@ struct V_CoreGates
|
||||
|
||||
struct VoiceMixSet
|
||||
{
|
||||
static const VoiceMixSet Empty;
|
||||
StereoOut32 Dry, Wet;
|
||||
|
||||
VoiceMixSet() {}
|
||||
@ -491,11 +491,6 @@ struct V_Core
|
||||
u16 psxSoundDataTransferControl;
|
||||
u16 psxSPUSTAT;
|
||||
|
||||
// HACK -- This is a temp buffer which is (or isn't?) used to circumvent some memory
|
||||
// corruption that originates elsewhere. >_< The actual ADMA buffer
|
||||
// is an area mapped to SPU2 main memory.
|
||||
//s16 ADMATempBuffer[0x1000];
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
// V_Core Methods
|
||||
// ----------------------------------------------------------------------------------
|
||||
@ -519,7 +514,6 @@ struct V_Core
|
||||
// Mixer Section
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
||||
StereoOut32 Mix(const VoiceMixSet& inVoices, const StereoOut32& Input, const StereoOut32& Ext);
|
||||
StereoOut32 DoReverb(StereoOut32 Input);
|
||||
s32 RevbGetIndexer(s32 offset);
|
||||
|
||||
@ -643,3 +637,6 @@ struct PcmCacheEntry
|
||||
};
|
||||
|
||||
extern PcmCacheEntry pcm_cache_data[pcm_BlockCount];
|
||||
extern int g_counter_cache_hits;
|
||||
extern int g_counter_cache_misses;
|
||||
extern int g_counter_cache_ignores;
|
||||
|
||||
@ -219,6 +219,10 @@ bool SPU2::IsAudioCaptureActive()
|
||||
|
||||
void SPU2::InternalReset(bool psxmode)
|
||||
{
|
||||
spu2Mix = MULTI_ISA_SELECT(spu2Mix);
|
||||
ReverbDownsample = MULTI_ISA_SELECT(ReverbDownsample);
|
||||
ReverbUpsample = MULTI_ISA_SELECT(ReverbUpsample);
|
||||
|
||||
s_current_chunk_pos = 0;
|
||||
s_psxmode = psxmode;
|
||||
if (!s_psxmode)
|
||||
|
||||
@ -38,6 +38,8 @@ static bool has_to_call_irq_dma[2] = { false, false };
|
||||
StereoOut32 (*ReverbUpsample)(V_Core& core);
|
||||
s32 (*ReverbDownsample)(V_Core& core, bool right);
|
||||
|
||||
// Function pointer for multi-isa mixer
|
||||
void (*spu2Mix)();
|
||||
|
||||
static bool psxmode = false;
|
||||
|
||||
@ -103,9 +105,6 @@ void V_Core::Init(int index)
|
||||
if (SPU2::MsgToConsole())
|
||||
SPU2::ConLog("* SPU2: Init SPU2 core %d \n", index);
|
||||
|
||||
ReverbDownsample = MULTI_ISA_SELECT(ReverbDownsample);
|
||||
ReverbUpsample = MULTI_ISA_SELECT(ReverbUpsample);
|
||||
|
||||
//memset(this, 0, sizeof(V_Core));
|
||||
// Explicitly initializing variables instead.
|
||||
Mute = false;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user