Dr. Hell noise generator

This commit is contained in:
johnbaumann 2023-04-07 13:38:50 -05:00
parent 94e5216579
commit ba04d30728
7 changed files with 60 additions and 22 deletions

View file

@ -75,5 +75,6 @@ smf
iCatButler
Neill Corlett
Vincent "Yaz0r" Hamm
Dokta Jigokusai / Dr. Hell
)"

View file

@ -125,8 +125,14 @@ typedef Protobuf::Field<Protobuf::Int32, TYPESTRING("cbVoiceInd"), 13> CBVoiceIn
typedef Protobuf::Field<Protobuf::FixedBytes<1024 * 16 * 2>, TYPESTRING("CBLeft"), 14> CBCDLeft;
typedef Protobuf::Field<Protobuf::FixedBytes<1024 * 16 * 2>, TYPESTRING("CBRight"), 15> CBCDRight;
// global noise generator
typedef Protobuf::Field<Protobuf::UInt32, TYPESTRING("noiseClock"), 16> SPUNoiseClock;
typedef Protobuf::Field<Protobuf::UInt32, TYPESTRING("noiseCount"), 17> SPUNoiseCount;
typedef Protobuf::Field<Protobuf::UInt32, TYPESTRING("noiseVal"), 18> SPUNoiseVal;
typedef Protobuf::Message<TYPESTRING("SPU"), SPURam, SPUPorts, XAField, SPUIrq, SPUIrqPtr, Channels, SPUAddr, SPUCtrl,
SPUStat, CBStartIndex, CBCurrIndex, CBEndIndex, CBVoiceIndex, CBCDLeft, CBCDRight>
SPUStat, CBStartIndex, CBCurrIndex, CBEndIndex, CBVoiceIndex, CBCDLeft, CBCDRight,
SPUNoiseClock, SPUNoiseCount, SPUNoiseVal>
SPU;
typedef Protobuf::MessageField<SPU, TYPESTRING("spu"), 6> SPUField;

View file

@ -83,6 +83,10 @@ void PCSX::SPU::impl::save(SaveStates::SPU &spu) {
spu.get<SaveStates::SPUCtrl>().value = spuCtrl;
spu.get<SaveStates::SPUStat>().value = spuStat;
spu.get<SaveStates::SPUNoiseClock>().value = m_noiseClock;
spu.get<SaveStates::SPUNoiseCount>().value = m_noiseCount;
spu.get<SaveStates::SPUNoiseVal>().value = m_noiseVal;
SetupThread();
}
@ -131,6 +135,10 @@ void PCSX::SPU::impl::load(const SaveStates::SPU &spu) {
spuCtrl = spu.get<SaveStates::SPUCtrl>().value;
spuStat = spu.get<SaveStates::SPUStat>().value;
m_noiseClock = spu.get<SaveStates::SPUNoiseClock>().value;
m_noiseCount = spu.get<SaveStates::SPUNoiseCount>().value;
m_noiseVal = spu.get<SaveStates::SPUNoiseVal>().value;
// repair some globals
for (unsigned i = 0; i <= 62; i += 2) writeRegister(H_Reverb + i, regArea[(H_Reverb + i - 0xc00) >> 1]);
writeRegister(H_SPUReverbAddr, regArea[(H_SPUReverbAddr - 0xc00) >> 1]);

View file

@ -138,6 +138,7 @@ class impl final : public SPUInterface {
int iGetNoiseVal(SPUCHAN *pChannel);
void StoreInterpolationVal(SPUCHAN *pChannel, int fa);
int iGetInterpolationVal(SPUCHAN *pChannel);
void NoiseClock();
// registers
void SoundOn(int start, int end, uint16_t val);
@ -199,7 +200,9 @@ class impl final : public SPUInterface {
SPUCHAN s_chan[MAXCHAN + 1]; // channel + 1 infos (1 is security for fmod handling)
REVERBInfo rvb;
uint32_t dwNoiseVal = 1; // global noise generator
uint32_t m_noiseClock = 0; // global noise generator
uint32_t m_noiseCount = 0; // global noise generator
uint32_t m_noiseVal = 1; // global noise generator
uint16_t spuCtrl = 0; // some vars to store psx reg infos
uint16_t spuStat = 0;

View file

@ -195,6 +195,7 @@ void PCSX::SPU::impl::writeRegister(uint32_t reg, uint16_t val) {
case H_SPUctrl:
spuCtrl = val;
m_noiseClock = (spuCtrl & (ControlFlags::NoiseShift | ControlFlags::NoiseStep)) >> 8;
break;
case H_SPUstat:

View file

@ -291,23 +291,7 @@ inline void PCSX::SPU::impl::FModChangeFrequency(SPUCHAN *pChannel, int ns) {
inline int PCSX::SPU::impl::iGetNoiseVal(SPUCHAN *pChannel) {
auto &SB = pChannel->data.get<PCSX::SPU::Chan::SB>().value;
int fa;
if ((dwNoiseVal <<= 1) & 0x80000000L) {
dwNoiseVal ^= 0x0040001L;
fa = ((dwNoiseVal >> 2) & 0x7fff);
fa = -fa;
} else
fa = (dwNoiseVal >> 2) & 0x7fff;
static constexpr uint16_t noiseMask = ControlFlags::NoiseShift | ControlFlags::NoiseStep;
// mmm... depending on the noise freq we allow bigger/smaller changes to the previous val
fa = pChannel->data.get<PCSX::SPU::Chan::OldNoise>().value +
((fa - pChannel->data.get<PCSX::SPU::Chan::OldNoise>().value) / ((0x001f - ((spuCtrl & noiseMask) >> 9)) + 1));
if (fa > 32767L) fa = 32767L;
if (fa < -32767L) fa = -32767L;
pChannel->data.get<PCSX::SPU::Chan::OldNoise>().value = fa;
const int fa = (int16_t)m_noiseVal;
if (settings.get<Interpolation>() < 2) // no gauss/cubic interpolation?
SB[29].value = fa; // -> store noise val in "current sample" slot
@ -316,6 +300,40 @@ inline int PCSX::SPU::impl::iGetNoiseVal(SPUCHAN *pChannel) {
////////////////////////////////////////////////////////////////////////
void PCSX::SPU::impl::NoiseClock() {
// Noise Waveform - Dr. Hell (Xebra)
static constexpr char NoiseWaveAdd[64] = {1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1,
1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0,
1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1};
static constexpr unsigned short NoiseFreqAdd[5] = {0, 84, 140, 180, 210};
unsigned int level;
level = 0x8000 >> (m_noiseClock >> 2);
level <<= 16;
m_noiseCount += 0x10000;
// Dr. Hell - fraction
m_noiseCount += NoiseFreqAdd[m_noiseClock & 3];
if ((m_noiseCount & 0xffff) >= NoiseFreqAdd[4]) {
m_noiseCount += 0x10000;
m_noiseCount -= NoiseFreqAdd[m_noiseClock & 3];
}
if (m_noiseCount >= level) {
while (m_noiseCount >= level) {
m_noiseCount -= level;
}
// Dr. Hell - form
m_noiseVal = (m_noiseVal << 1) | NoiseWaveAdd[(m_noiseVal >> 10) & 63];
}
}
////////////////////////////////////////////////////////////////////////
inline void PCSX::SPU::impl::StoreInterpolationVal(SPUCHAN *pChannel, int fa) {
auto &SB = pChannel->data.get<PCSX::SPU::Chan::SB>().value;
if (pChannel->data.get<PCSX::SPU::Chan::FMod>().value == 2) // fmod freq channel
@ -510,6 +528,8 @@ void PCSX::SPU::impl::MainThread() {
while (ns < NSSIZE) // loop until 1 ms of data is reached
{
NoiseClock();
if (pChannel->data.get<PCSX::SPU::Chan::FMod>().value == 1 && iFMod[ns]) // fmod freq channel
FModChangeFrequency(pChannel, ns);

View file

@ -124,12 +124,11 @@ typedef Protobuf::Field<Protobuf::Bool, TYPESTRING("noise"), 28> Noise;
typedef Protobuf::Field<Protobuf::Int32, TYPESTRING("fmod"), 29> FMod;
// another reverb helper
typedef Protobuf::Field<Protobuf::Int32, TYPESTRING("rvb_num"), 30> RVBNum;
// old noise val for this channel
typedef Protobuf::Field<Protobuf::Int32, TYPESTRING("old_noise"), 31> OldNoise;
// skip id 31
typedef Protobuf::Message<TYPESTRING("ChannelData"), New, SBPos, spos, sinc, SB, sval, StartPtr, CurrPtr, LoopPtr, On,
Stop, Reverb, ActFreq, UsedFreq, LeftVolume, LeftVolRaw, IgnoreLoop, Mute, RightVolume,
RightVolRaw, RawPitch, IrqDone, s_1, s_2, RVBActive, RVBOffset, RVBRepeat, Noise, FMod,
RVBNum, OldNoise>
RVBNum>
Data;
} // namespace Chan