From ad09ed4e509171910b1a3675294c85f4fb6f4485 Mon Sep 17 00:00:00 2001 From: Aikku93 Date: Sat, 3 Sep 2022 14:40:14 +1000 Subject: [PATCH 1/2] Ensure capture is always processed If the buffer is still being filled, it should move the DAD forward anyway or it will fall out of sync. --- desmume/src/SPU.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/desmume/src/SPU.cpp b/desmume/src/SPU.cpp index 4045be3c6..5a3288547 100644 --- a/desmume/src/SPU.cpp +++ b/desmume/src/SPU.cpp @@ -1465,22 +1465,15 @@ static void SPU_MixAudio_Advanced(bool actuallyMix, SPU_struct *SPU, int length) //Instead, what we do here is delay the capture by 16 samples to create a similar effect. //Subjectively, it seems to be working. - //Don't do anything until the fifo is filled, so as to delay it - if (cap.runtime.fifo.size < 16) - { - cap.runtime.fifo.enqueue(capout[capchan]); - continue; - } - - //(actually capture sample from fifo instead of most recently generated) - u32 multiplier; - s32 sample = cap.runtime.fifo.dequeue(); + //Fetch the FIFO-buffered sample and enqueue the most recently generated sample + s32 sample = (cap.runtime.fifo.size >= 16) ? cap.runtime.fifo.dequeue() : 0; cap.runtime.fifo.enqueue(capout[capchan]); //static FILE* fp = NULL; //if(!fp) fp = fopen("d:\\capout.raw","wb"); //fwrite(&sample,2,1,fp); + u32 multiplier; if (cap.bits8) { s8 sample8 = sample >> 8; From ae627d68473a7e6bb41baaceb9e4d6356a6b92f8 Mon Sep 17 00:00:00 2001 From: Aikku93 Date: Sat, 3 Sep 2022 18:52:17 +1000 Subject: [PATCH 2/2] Further fix for #589 Commit ad09ed4e only partially fixed the issue. This should fix it for good. --- desmume/src/SPU.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/desmume/src/SPU.cpp b/desmume/src/SPU.cpp index 5a3288547..6f331cb60 100644 --- a/desmume/src/SPU.cpp +++ b/desmume/src/SPU.cpp @@ -472,6 +472,22 @@ void SPU_struct::KeyOn(int channel) thischan.status = CHANSTAT_STOPPED; } } + + // If we are targetting data that is being played back by a + // channel, then make sure to delay it by at least 4 samples + // so that we don't get ourselves into buffer overrun. + // This (and the corresponding fixup in ProbeCapture()) are a + // nasty hack, but it's about all we can do, really :/ + if(channel == 1 || channel == 3) { + const SPU_struct::REGS::CAP *cap = ®s.cap[(channel == 1) ? 0 : 1]; + if(cap->active && (cap->runtime.maxdad - cap->len*4) == thischan.addr) { + // We are assuming that the channel and capture have the same length + int capLen_shifted = cap->len * (32 / (cap->bits8 ? 8 : 16)); + int d = cap->runtime.sampcntInt - thischan.sampcntInt; + if(d < 0) d += capLen_shifted; + if(d < 4) thischan.sampcntInt -= 4 - d; + } + } } ////////////////////////////////////////////////////////////////////////////// @@ -767,6 +783,15 @@ void SPU_struct::ProbeCapture(int which) cap.runtime.maxdad = cap.dad + len*4; cap.runtime.sampcntFrac = cap.runtime.sampcntInt = 0; cap.runtime.fifo.reset(); + + // Fix playback position for feedback capture - see notes in KeyProbe() + const channel_struct *ch = &channels[(which == 0) ? 1 : 3]; + if(ch->status == CHANSTAT_PLAY && ch->addr == cap.dad) { + int capLen_shifted = cap.len * (32 / (cap.bits8 ? 8 : 16)); + int d = cap.runtime.sampcntInt - ch->sampcntInt; // cap.runtime.sampcntInt - ch->sampcntInt, wrapped around + if(d < 0) d += capLen_shifted; + if(d < 4) cap.runtime.sampcntInt += 4 - d; + } } void SPU_struct::WriteByte(u32 addr, u8 val)