Skip to content

Commit

Permalink
PCE: Fixed sound mixing issue causing pops in ADPCM and CD audio
Browse files Browse the repository at this point in the history
  • Loading branch information
SourMesen committed Jun 7, 2024
1 parent d208fdc commit abe6f0f
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 27 deletions.
6 changes: 3 additions & 3 deletions Core/PCE/CdRom/PceAdpcm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ void PceAdpcm::PlaySample()
int8_t sign = data & 0x08 ? -1 : 1;

int16_t adjustment = _stepSize[(_magnitude << 3) | value] * sign;
_currentOutput = std::clamp(_currentOutput + adjustment, 0, 4095);
_currentOutput += adjustment;

_magnitude = std::clamp(_magnitude + _stepFactor[value], 0, 48);

Expand All @@ -333,7 +333,7 @@ void PceAdpcm::PlaySample()
SetEndReached(true);
}

int16_t out = (_currentOutput - 2048) * 10;
int16_t out = (std::clamp<int16_t>(_currentOutput, 0, 4095) - 2048) * 10;
_samplesToPlay.push_back(out);
_samplesToPlay.push_back(out);
}
Expand All @@ -344,7 +344,7 @@ void PceAdpcm::MixAudio(int16_t* out, uint32_t sampleCount, uint32_t sampleRate)
double volume = _cdrom->GetAudioFader().GetVolume(PceAudioFaderTarget::Adpcm);
_resampler.SetVolume(_emu->GetSettings()->GetPcEngineConfig().AdpcmVolume / 100.0 * volume);
_resampler.SetSampleRates(freq, sampleRate);
_resampler.Resample<true>(_samplesToPlay.data(), (uint32_t)_samplesToPlay.size() / 2, out, sampleCount);
_resampler.Resample<true>(_samplesToPlay.data(), (uint32_t)_samplesToPlay.size() / 2, out, sampleCount, _state.Playing);
_samplesToPlay.clear();
}

Expand Down
2 changes: 1 addition & 1 deletion Core/PCE/CdRom/PceCdAudioPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ void PceCdAudioPlayer::MixAudio(int16_t* out, uint32_t sampleCount, uint32_t sam
double volume = _cdrom->GetAudioFader().GetVolume(PceAudioFaderTarget::CdAudio);
_resampler.SetVolume(_emu->GetSettings()->GetPcEngineConfig().CdAudioVolume / 100.0 * volume);
_resampler.SetSampleRates(44100, sampleRate);
_resampler.Resample<true>(_samplesToPlay.data(), (uint32_t)_samplesToPlay.size() / 2, out, sampleCount);
_resampler.Resample<true>(_samplesToPlay.data(), (uint32_t)_samplesToPlay.size() / 2, out, sampleCount, _state.Status == CdAudioStatus::Playing);
_samplesToPlay.clear();
}

Expand Down
3 changes: 2 additions & 1 deletion Core/SMS/SmsFmAudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,13 @@ void SmsFmAudio::MixAudio(int16_t* out, uint32_t sampleCount, uint32_t sampleRat

if(_audioControl == 0 || _audioControl == 2) {
//FM audio is muted when 0 or 2
_samplesToPlay.clear();
return;
}

_resampler.SetSampleRates(_console->GetMasterClockRate() / 72.0, sampleRate);
_resampler.SetVolume(_emu->GetSettings()->GetSmsConfig().FmAudioVolume * 1.5 / 100.0);
_resampler.Resample<true>(_samplesToPlay.data(), (uint32_t)_samplesToPlay.size() / 2, out, sampleCount);
_resampler.Resample<true>(_samplesToPlay.data(), (uint32_t)_samplesToPlay.size() / 2, out, sampleCount, true);
_samplesToPlay.clear();
}

Expand Down
2 changes: 1 addition & 1 deletion Core/SNES/Coprocessors/SGB/SuperGameboy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ void SuperGameboy::MixAudio(int16_t* out, uint32_t sampleCount, uint32_t sampleR

if(!_spc->IsMuted()) {
_resampler.SetSampleRates(GbApu::SampleRate * _effectiveClockRate / _gameboy->GetMasterClockRate(), sampleRate);
_resampler.Resample<true>(gbSamples, gbSampleCount, out, sampleCount);
_resampler.Resample<true>(gbSamples, gbSampleCount, out, sampleCount, true);
}
}

Expand Down
51 changes: 31 additions & 20 deletions Utilities/Audio/HermiteResampler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ void HermiteResampler::WriteSample(int16_t* out, uint32_t pos, int16_t left, int
}

template<bool addMode>
uint32_t HermiteResampler::Resample(int16_t* in, uint32_t inSampleCount, int16_t* out, size_t maxOutSampleCount)
uint32_t HermiteResampler::Resample(int16_t* in, uint32_t inSampleCount, int16_t* out, size_t maxOutSampleCount, bool fillToMax)
{
maxOutSampleCount *= 2;
if(_pendingSamples.size() >= maxOutSampleCount) {
Expand All @@ -86,31 +86,42 @@ uint32_t HermiteResampler::Resample(int16_t* in, uint32_t inSampleCount, int16_t
_pendingSamples.push_back(in[i]);
_pendingSamples.push_back(in[i + 1]);
}
return (count + outPos) / 2;
}

for(uint32_t i = 0; i < inSampleCount * 2; i += 2) {
while(_fraction <= 1.0) {
//Generate interpolated samples until we have enough samples for the current source sample
if(outPos <= maxOutSampleCount - 2) {
WriteSample<addMode>(out, outPos, HermiteInterpolate(_prevLeft, _fraction), HermiteInterpolate(_prevRight, _fraction));
outPos += 2;
} else {
_pendingSamples.push_back(HermiteInterpolate(_prevLeft, _fraction));
_pendingSamples.push_back(HermiteInterpolate(_prevRight, _fraction));
_left = in[inSampleCount * 2 - 2];
_right = in[inSampleCount * 2 - 1];
outPos += count;
} else {
for(uint32_t i = 0; i < inSampleCount * 2; i += 2) {
while(_fraction <= 1.0) {
//Generate interpolated samples until we have enough samples for the current source sample
_left = HermiteInterpolate(_prevLeft, _fraction);
_right = HermiteInterpolate(_prevRight, _fraction);
if(outPos <= maxOutSampleCount - 2) {
WriteSample<addMode>(out, outPos, _left, _right);
outPos += 2;
} else {
_pendingSamples.push_back(_left);
_pendingSamples.push_back(_right);
}

_fraction += _rateRatio;
}

_fraction += _rateRatio;
//Move to the next source sample
PushSample(_prevLeft, in[i]);
PushSample(_prevRight, in[i + 1]);
_fraction -= 1.0;
}
}

//Move to the next source sample
PushSample(_prevLeft, in[i]);
PushSample(_prevRight, in[i + 1]);
_fraction -= 1.0;
if(fillToMax) {
while(outPos < maxOutSampleCount) {
WriteSample<addMode>(out, outPos, _left, _right);
outPos += 2;
}
}

return outPos / 2;
}

template uint32_t HermiteResampler::Resample<true>(int16_t* in, uint32_t inSampleCount, int16_t* out, size_t maxOutSampleCount);
template uint32_t HermiteResampler::Resample<false>(int16_t* in, uint32_t inSampleCount, int16_t* out, size_t maxOutSampleCount);
template uint32_t HermiteResampler::Resample<true>(int16_t* in, uint32_t inSampleCount, int16_t* out, size_t maxOutSampleCount, bool fillToMax);
template uint32_t HermiteResampler::Resample<false>(int16_t* in, uint32_t inSampleCount, int16_t* out, size_t maxOutSampleCount, bool fillToMax);
5 changes: 4 additions & 1 deletion Utilities/Audio/HermiteResampler.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ class HermiteResampler
double _rateRatio = 1.0;
double _fraction = 0.0;

int16_t _left = 0;
int16_t _right = 0;

vector<int16_t> _pendingSamples;

__forceinline int16_t HermiteInterpolate(double values[4], double mu);
Expand All @@ -26,5 +29,5 @@ class HermiteResampler
uint32_t GetPendingCount();

template<bool addMode>
uint32_t Resample(int16_t* in, uint32_t inSampleCount, int16_t* out, size_t maxOutSampleCount);
uint32_t Resample(int16_t* in, uint32_t inSampleCount, int16_t* out, size_t maxOutSampleCount, bool fillToMax = false);
};

0 comments on commit abe6f0f

Please sign in to comment.