diff --git a/Core/HW/SasAudio.cpp b/Core/HW/SasAudio.cpp index ceae931a55f6..46a23a85c48a 100644 --- a/Core/HW/SasAudio.cpp +++ b/Core/HW/SasAudio.cpp @@ -337,7 +337,6 @@ SasInstance::SasInstance() sendBuffer(0), sendBufferDownsampled(0), sendBufferProcessed(0), - resampleBuffer(0), grainSize(0) { #ifdef AUDIO_TO_FILE audioDump = fopen("D:\\audio.raw", "wb"); @@ -376,10 +375,8 @@ void SasInstance::ClearGrainSize() { delete[] sendBuffer; delete[] sendBufferDownsampled; delete[] sendBufferProcessed; - delete[] resampleBuffer; mixBuffer = nullptr; sendBuffer = nullptr; - resampleBuffer = nullptr; sendBufferDownsampled = nullptr; sendBufferProcessed = nullptr; } @@ -392,7 +389,6 @@ void SasInstance::SetGrainSize(int newGrainSize) { delete[] sendBuffer; delete[] sendBufferDownsampled; delete[] sendBufferProcessed; - delete[] resampleBuffer; mixBuffer = new s32[grainSize * 2]; sendBuffer = new s32[grainSize * 2]; @@ -402,10 +398,6 @@ void SasInstance::SetGrainSize(int newGrainSize) { memset(sendBuffer, 0, sizeof(int) * grainSize * 2); memset(sendBufferDownsampled, 0, sizeof(s16) * grainSize); memset(sendBufferProcessed, 0, sizeof(s16) * grainSize * 2); - - // 2 samples padding at the start, that's where we copy the two last samples from the channel - // so that we can do bicubic resampling if necessary. Plus 1 for smoothness hackery. - resampleBuffer = new s16[grainSize * 4 + 3]; } int SasInstance::EstimateMixUs() { @@ -459,9 +451,7 @@ void SasVoice::ReadSamples(s16 *output, int numSamples) { atrac3.getNextSamples(output, numSamples); break; default: - { - memset(output, 0, numSamples * sizeof(s16)); - } + memset(output, 0, numSamples * sizeof(s16)); break; } } @@ -493,47 +483,35 @@ void SasInstance::MixVoice(SasVoice &voice) { break; // else fallthrough! Don't change the check above. default: - // Load resample history (so we can use a wide filter) - resampleBuffer[0] = voice.resampleHist[0]; - resampleBuffer[1] = voice.resampleHist[1]; - - // Figure out number of samples to read. - // Actually this is not entirely correct - we need to get one extra sample, and store it - // for the next time around. A little complicated... - // But for now, see Smoothness HACKERY below :P - u32 numSamples = ((u32)voice.sampleFrac + (u32)grainSize * (u32)voice.pitch) >> PSP_SAS_PITCH_BASE_SHIFT; - if ((int)numSamples > grainSize * 4) { - ERROR_LOG(SASMIX, "numSamples too large, clamping: %i vs %i", numSamples, grainSize * 4); - numSamples = grainSize * 4; - } - // This feels a bit hacky. The first 32 samples after a keyon are 0s. - const bool ignorePitch = voice.type == VOICETYPE_PCM && voice.pitch > PSP_SAS_PITCH_BASE; + int delay = 0; if (voice.envelope.NeedsKeyOn()) { - int delay = ignorePitch ? 32 : (32 * (u32)voice.pitch) >> PSP_SAS_PITCH_BASE_SHIFT; + const bool ignorePitch = voice.type == VOICETYPE_PCM && voice.pitch > PSP_SAS_PITCH_BASE; + delay = ignorePitch ? 32 : (32 * (u32)voice.pitch) >> PSP_SAS_PITCH_BASE_SHIFT; // VAG seems to have an extra sample delay (not shared by PCM.) if (voice.type == VOICETYPE_VAG) ++delay; - voice.ReadSamples(resampleBuffer + 2 + delay, numSamples - delay); - } else { - voice.ReadSamples(resampleBuffer + 2, numSamples); } - // Smoothness HACKERY - resampleBuffer[2 + numSamples] = resampleBuffer[2 + numSamples - 1]; - - // Save resample history - voice.resampleHist[0] = resampleBuffer[2 + numSamples - 2]; - voice.resampleHist[1] = resampleBuffer[2 + numSamples - 1]; - // Resample to the correct pitch, writing exactly "grainSize" samples. - // This is a HORRIBLE resampler by the way. // TODO: Special case no-resample case (and 2x and 0.5x) for speed, it's not uncommon + int16_t temp[PSP_SAS_MAX_GRAIN + 2]; + // Two passes: First read, then resample. u32 sampleFrac = voice.sampleFrac; - for (int i = 0; i < grainSize; i++) { - // For now: nearest neighbour, not even using the resample history at all. - int sample = resampleBuffer[sampleFrac / PSP_SAS_PITCH_BASE + 2]; + temp[0] = voice.resampleHist[0]; + temp[1] = voice.resampleHist[1]; + + int samplesToRead = (sampleFrac + voice.pitch * (grainSize - delay)) >> PSP_SAS_PITCH_BASE_SHIFT; + voice.ReadSamples(&temp[2], samplesToRead); + int tempPos = 2 + samplesToRead; + + for (int i = delay; i < grainSize; i++) { + const int16_t *s = temp + (sampleFrac >> PSP_SAS_PITCH_BASE_SHIFT); + + // Linear interpolation. Good enough. Need to make resampleHist bigger if we want more. + int f = sampleFrac & PSP_SAS_PITCH_MASK; + int sample = (s[0] * (PSP_SAS_PITCH_MASK - f) + s[1] * f) >> PSP_SAS_PITCH_BASE_SHIFT; sampleFrac += voice.pitch; // The maximum envelope height (PSP_SAS_ENVELOPE_HEIGHT_MAX) is (1 << 30) - 1. @@ -549,21 +527,20 @@ void SasInstance::MixVoice(SasVoice &voice) { // We mix into this 32-bit temp buffer and clip in a second loop // Ideally, the shift right should be there too but for now I'm concerned about // not overflowing. - mixBuffer[i * 2] += (sample * voice.volumeLeft ) >> 12; + mixBuffer[i * 2] += (sample * voice.volumeLeft) >> 12; mixBuffer[i * 2 + 1] += (sample * voice.volumeRight) >> 12; sendBuffer[i * 2] += sample * voice.effectLeft >> 12; sendBuffer[i * 2 + 1] += sample * voice.effectRight >> 12; } - voice.sampleFrac = sampleFrac; - // Let's hope grainSize is a power of 2. - //voice.sampleFrac &= grainSize * PSP_SAS_PITCH_BASE - 1; - voice.sampleFrac -= numSamples * PSP_SAS_PITCH_BASE; + voice.resampleHist[0] = temp[tempPos - 2]; + voice.resampleHist[1] = temp[tempPos - 1]; + + voice.sampleFrac = sampleFrac - (tempPos - 2) * PSP_SAS_PITCH_BASE;; if (voice.HaveSamplesEnded()) voice.envelope.End(); - if (voice.envelope.HasEnded()) - { + if (voice.envelope.HasEnded()) { // NOTICE_LOG(SCESAS, "Hit end of envelope"); voice.playing = false; voice.on = false; @@ -711,8 +688,11 @@ void SasInstance::DoState(PointerWrap &p) { if (sendBuffer != NULL && grainSize > 0) { p.DoArray(sendBuffer, grainSize * 2); } - if (resampleBuffer != NULL && grainSize > 0) { - p.DoArray(resampleBuffer, grainSize * 4 + 3); + if (sendBuffer != NULL && grainSize > 0) { + // Backwards compat + int16_t *resampleBuf = new int16_t[grainSize * 4 + 3](); + p.DoArray(resampleBuf, grainSize * 4 + 3); + delete[] resampleBuf; } int n = PSP_SAS_VOICES_MAX; diff --git a/Core/HW/SasAudio.h b/Core/HW/SasAudio.h index fd4283e2f6b5..195056d47673 100644 --- a/Core/HW/SasAudio.h +++ b/Core/HW/SasAudio.h @@ -33,10 +33,12 @@ enum { PSP_SAS_PITCH_MIN = 0x0000, PSP_SAS_PITCH_BASE = 0x1000, + PSP_SAS_PITCH_MASK = 0xFFF, PSP_SAS_PITCH_BASE_SHIFT = 12, PSP_SAS_PITCH_MAX = 0x4000, PSP_SAS_VOL_MAX = 0x1000, + PSP_SAS_MAX_GRAIN = 1024, // VERY conservative! 256 is quite common but don't think I've ever seen bigger. PSP_SAS_ADSR_CURVE_MODE_LINEAR_INCREASE = 0, PSP_SAS_ADSR_CURVE_MODE_LINEAR_DECREASE = 1, @@ -250,7 +252,7 @@ struct SasVoice { int pcmLoopPos; int sampleRate; - int sampleFrac; + uint32_t sampleFrac; int pitch; bool loop; @@ -289,8 +291,6 @@ class SasInstance { s16 *sendBufferDownsampled; s16 *sendBufferProcessed; - s16 *resampleBuffer; - FILE *audioDump; void Mix(u32 outAddr, u32 inAddr = 0, int leftVol = 0, int rightVol = 0);