From dd7e1def3d2630e6b272ca97baad2bccdc0bae75 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 1 Mar 2025 05:05:50 -0500 Subject: [PATCH] new chan osc work in progress --- src/engine/dispatch.h | 65 ++++++++++++++++----- src/engine/engine.cpp | 4 +- src/engine/platform/abstract.cpp | 4 -- src/engine/platform/amiga.cpp | 15 ++++- src/engine/platform/ga20.cpp | 12 +++- src/engine/platform/pcspkr.cpp | 25 ++++---- src/engine/platform/snes.cpp | 10 +++- src/engine/playback.cpp | 4 +- src/gui/chanOsc.cpp | 99 ++++++++++++++++++++++---------- src/gui/debugWindow.cpp | 2 +- src/gui/gui.cpp | 5 +- 11 files changed, 171 insertions(+), 74 deletions(-) diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 5a4940019..91f430b4b 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -424,40 +424,79 @@ struct DivSamplePos { freq(0) {} }; +constexpr uintmax_t OSCBUF_PREC=(sizeof(uintmax_t)>=8)?32:16; +constexpr uintmax_t OSCBUF_MASK=(1UL<>OSCBUF_PREC); + if (val==-1) { + data[realPos]=0xfffe; return; } - data[needle+pos]=val; + lastSample=val; + data[realPos]=val; } inline void begin(unsigned short len) { + uintmax_t calc=(needleSub+len*rateMul)>>OSCBUF_PREC; + unsigned short start=needle; + unsigned short end=needle+calc; + + if (end=(OSCBUF_MASK+1UL)) { + needle++; + } + needleSub=(needleSub+calc)&OSCBUF_MASK; + needle+=calc>>OSCBUF_PREC; + data[needle]=lastSample; + } + void reset() { + memset(data,-1,65536*sizeof(short)); + needle=0; + readNeedle=0; + followNeedle=0; + needleSub=0; + lastSample=0; } void setRate(unsigned int r) { - + double rateMulD=65536.0/(double)r; + rateMulD*=(double)(1UL<getOscBuffer(dispatchChanOfChan[i]); if (buf!=NULL) { - memset(buf->data,0,65536*sizeof(short)); - buf->needle=0; - buf->readNeedle=0; + buf->reset(); } } BUSY_END; diff --git a/src/engine/platform/abstract.cpp b/src/engine/platform/abstract.cpp index 41662176b..73abebc30 100644 --- a/src/engine/platform/abstract.cpp +++ b/src/engine/platform/abstract.cpp @@ -134,10 +134,6 @@ bool DivDispatch::hasAcquireDirect() { return false; } -bool DivDispatch::isOscBufPositional() { - return false; -} - bool DivDispatch::getWantPreNote() { return false; } diff --git a/src/engine/platform/amiga.cpp b/src/engine/platform/amiga.cpp index 0c4022021..71f39b420 100644 --- a/src/engine/platform/amiga.cpp +++ b/src/engine/platform/amiga.cpp @@ -82,6 +82,10 @@ const char** DivPlatformAmiga::getRegisterSheet() { void DivPlatformAmiga::acquire(short** buf, size_t len) { thread_local int outL, outR, output; + for (int i=0; i<4; i++) { + oscBuf[i]->begin(len); + } + for (size_t h=0; h>7; outR+=(output*sep1)>>7; } - oscBuf[i]->data[oscBuf[i]->needle++]=(amiga.nextOut[i]*MIN(64,amiga.audVol[i]&127))<<1; + oscBuf[i]->putSample(h,(amiga.nextOut[i]*MIN(64,amiga.audVol[i]&127))<<1); } else { - oscBuf[i]->data[oscBuf[i]->needle++]=0; + // TODO: we can remove this! + oscBuf[i]->putSample(h,0); } } @@ -195,6 +200,10 @@ void DivPlatformAmiga::acquire(short** buf, size_t len) { buf[0][h]=filter[0][1]; buf[1][h]=filter[1][1]; } + + for (int i=0; i<4; i++) { + oscBuf[i]->end(len); + } } void DivPlatformAmiga::irq(int ch) { @@ -826,7 +835,7 @@ void DivPlatformAmiga::setFlags(const DivConfig& flags) { rate=chipClock/AMIGA_DIVIDER; for (int i=0; i<4; i++) { - oscBuf[i]->rate=rate; + oscBuf[i]->setRate(rate); } int sep=flags.getInt("stereoSep",0)&127; sep1=sep+127; diff --git a/src/engine/platform/ga20.cpp b/src/engine/platform/ga20.cpp index e5e3894da..94306cd98 100644 --- a/src/engine/platform/ga20.cpp +++ b/src/engine/platform/ga20.cpp @@ -60,6 +60,10 @@ void DivPlatformGA20::acquire(short** buf, size_t len) { } } + for (int i=0; i<4; i++) { + oscBuf[i]->begin(len); + } + for (size_t h=0; h>2; for (int i=0; i<4; i++) { - oscBuf[i]->data[oscBuf[i]->needle++]=ga20Buf[i][h]>>1; + oscBuf[i]->putSample(h,ga20Buf[i][h]>>1); } } + + for (int i=0; i<4; i++) { + oscBuf[i]->end(len); + } } u8 DivPlatformGA20::read_byte(u32 address) { @@ -403,7 +411,7 @@ void DivPlatformGA20::setFlags(const DivConfig& flags) { CHECK_CUSTOM_CLOCK; rate=chipClock/4; for (int i=0; i<4; i++) { - oscBuf[i]->rate=rate; + oscBuf[i]->setRate(rate); } } diff --git a/src/engine/platform/pcspkr.cpp b/src/engine/platform/pcspkr.cpp index 75f38d312..a41a18ead 100644 --- a/src/engine/platform/pcspkr.cpp +++ b/src/engine/platform/pcspkr.cpp @@ -196,6 +196,7 @@ void DivPlatformPCSpeaker::acquire_unfilt(blip_buffer_t** bb, size_t off, size_t int out=0; int freq1=freq+1; int timeToNextToggle=0; + oscBuf->begin(len); if (on) { // just in case if (pos>freq1) { @@ -210,11 +211,11 @@ void DivPlatformPCSpeaker::acquire_unfilt(blip_buffer_t** bb, size_t off, size_t } out=(posToggle && !isMuted[0])?32767:0; blip_add_delta(bb[0],off,out-oldOut); - oscBuf->data[oscBuf->needle++]=oscBufPos; oscBuf->data[oscBuf->needle++]=out; oldOut=out; if (freq>=1) { size_t boff=off; + size_t oscOff=0; size_t i=len; while (true) { if ((int)idata[oscBuf->needle++]=oscBufPos; - oscBuf->data[oscBuf->needle++]=out; + oscBuf->putSample(oscOff,out); oldOut=out; } } } else { out=0; blip_add_delta(bb[0],off,out-oldOut); + oscBuf->putSample(0,out); oldOut=out; } + oscBuf->end(len); } void DivPlatformPCSpeaker::acquire_cone(short** buf, size_t len) { + oscBuf->begin(len); for (size_t i=0; i1.0) out=1.0; if (out<-1.0) out=-1.0; buf[0][i]=out*32767; - oscBuf->data[oscBuf->needle++]=out*32767; + oscBuf->putSample(i,out*32767); } else { buf[0][i]=0; - oscBuf->data[oscBuf->needle++]=0; + oscBuf->putSample(i,0); } } + oscBuf->end(len); } void DivPlatformPCSpeaker::acquire_piezo(short** buf, size_t len) { + oscBuf->begin(len); for (size_t i=0; i1.0) out=1.0; if (out<-1.0) out=-1.0; buf[0][i]=out*32767; - oscBuf->data[oscBuf->needle++]=out*32767; + oscBuf->putSample(i,out*32767); } else { buf[0][i]=0; - oscBuf->data[oscBuf->needle++]=0; + oscBuf->putSample(i,0); } } + oscBuf->end(len); } void DivPlatformPCSpeaker::beepFreq(int freq, int delay) { @@ -670,7 +676,7 @@ void DivPlatformPCSpeaker::setFlags(const DivConfig& flags) { } else { rate=chipClock/PCSPKR_DIVIDER; } - oscBuf->rate=rate; + oscBuf->setRate(rate); switch (speakerType) { case 1: @@ -714,7 +720,6 @@ int DivPlatformPCSpeaker::init(DivEngine* p, int channels, int sugRate, const Di for (int i=0; i<1; i++) { isMuted[i]=false; } - oscBufPos=0; oscBuf=new DivDispatchOscBuffer; setFlags(flags); diff --git a/src/engine/platform/snes.cpp b/src/engine/platform/snes.cpp index ee8ef975f..1c4136f4d 100644 --- a/src/engine/platform/snes.cpp +++ b/src/engine/platform/snes.cpp @@ -71,6 +71,9 @@ const char** DivPlatformSNES::getRegisterSheet() { void DivPlatformSNES::acquire(short** buf, size_t len) { short out[2]; short chOut[16]; + for (int i=0; i<8; i++) { + oscBuf[i]->begin(len); + } for (size_t h=0; h32767) next=32767; - oscBuf[i]->data[oscBuf[i]->needle++]=next>>1; + oscBuf[i]->putSample(h,next>>1); } } + for (int i=0; i<8; i++) { + oscBuf[i]->end(len); + } } void DivPlatformSNES::tick(bool sysTick) { @@ -1058,7 +1064,7 @@ int DivPlatformSNES::init(DivEngine* p, int channels, int sugRate, const DivConf rate=chipClock/32; for (int i=0; i<8; i++) { oscBuf[i]=new DivDispatchOscBuffer; - oscBuf[i]->rate=rate; + oscBuf[i]->setRate(rate); isMuted[i]=false; } setFlags(flags); diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index dcdfcbf57..5a7461a74 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1986,9 +1986,7 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { for (int i=0; igetOscBuffer(dispatchChanOfChan[i]); if (buf!=NULL) { - memset(buf->data,0,65536*sizeof(short)); - buf->needle=0; - buf->readNeedle=0; + buf->reset(); } } return ret; diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index 074ff9b1e..ededa8646 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -102,14 +102,14 @@ void FurnaceGUI::calcChanOsc() { } if (buf!=NULL && e->curSubSong->chanShowChanOsc[i]) { // 30ms should be enough - int displaySize=(float)(buf->rate)*0.03f; + int displaySize=65536.0f*0.03f; if (e->isRunning()) { short minLevel=32767; short maxLevel=-32768; unsigned short needlePos=buf->needle; - needlePos-=displaySize; - for (unsigned short i=0; i<512; i++) { - short y=buf->data[(unsigned short)(needlePos+(i*displaySize/512))]; + for (unsigned short i=needlePos-displaySize; i!=needlePos; i++) { + short y=buf->data[i]; + if (y==-1) continue; if (minLevel>y) minLevel=y; if (maxLevelrate)*(fft->windowSize/1000.0f); + int displaySize=65536.0f*(fft->windowSize/1000.0f); + int displaySize2=65536.0f*(fft->windowSize/500.0f); fft->loudEnough=false; fft->needle=buf->needle; // first FFT - for (int j=0; jinBuf[j]=(double)buf->data[(unsigned short)(fft->needle-displaySize*2+((j*displaySize*2)/(FURNACE_FFT_SIZE)))]/32768.0; - if (fft->inBuf[j]>0.001 || fft->inBuf[j]<-0.001) fft->loudEnough=true; - fft->inBuf[j]*=0.55-0.45*cos(M_PI*(double)j/(double)(FURNACE_FFT_SIZE>>1)); + int k=0; + short lastSample=0; + memset(fft->inBuf,0,FURNACE_FFT_SIZE*sizeof(double)); + if (displaySize2data[(unsigned short)(fft->needle-displaySize2+((j*displaySize2)/(FURNACE_FFT_SIZE)))]; + if (newData!=-1) lastSample=newData; + fft->inBuf[j]=(double)lastSample/32768.0; + if (fft->inBuf[j]>0.001 || fft->inBuf[j]<-0.001) fft->loudEnough=true; + fft->inBuf[j]*=0.55-0.45*cos(M_PI*(double)j/(double)(FURNACE_FFT_SIZE>>1)); + } + } else { + for (unsigned short j=fft->needle-displaySize2; j!=fft->needle; j++, k++) { + const int kIn=(k*FURNACE_FFT_SIZE)/displaySize2; + if (kIn>=FURNACE_FFT_SIZE) break; + if (buf->data[j]!=-1) lastSample=buf->data[j]; + fft->inBuf[kIn]=(double)lastSample/32768.0; + if (fft->inBuf[kIn]>0.001 || fft->inBuf[kIn]<-0.001) fft->loudEnough=true; + fft->inBuf[kIn]*=0.55-0.45*cos(M_PI*(double)kIn/(double)(FURNACE_FFT_SIZE>>1)); + } } // only proceed if not quiet @@ -615,7 +634,8 @@ void FurnaceGUI::drawChanOsc() { } } } else { - int displaySize=(float)(buf->rate)*(chanOscWindowSize/1000.0f); + int displaySize=65536.0f*(chanOscWindowSize/1000.0f); + int displaySize2=65536.0f*(chanOscWindowSize/500.0f); float minLevel=1.0f; float maxLevel=-1.0f; @@ -654,7 +674,7 @@ void FurnaceGUI::drawChanOsc() { } } if (fft->loudEnough) { - String cPhase=fmt::sprintf("\n%.1f (b: %d t: %d)",fft->waveLen,fft->waveLenBottom,fft->waveLenTop); + String cPhase=fmt::sprintf("\n%.1f (b: %d t: %d)\nSIZES: %d, %d, %d",fft->waveLen,fft->waveLenBottom,fft->waveLenTop,displaySize,displaySize2,FURNACE_FFT_SIZE); dl->AddText(inRect.Min,0xffffffff,cPhase.c_str()); dl->AddLine( @@ -673,31 +693,48 @@ void FurnaceGUI::drawChanOsc() { } } } else { - for (unsigned short j=0; jdata[(unsigned short)(fft->needle+(j*displaySize/precision))]/32768.0f; - if (minLevel>y) minLevel=y; - if (maxLevelAddText(inRect.Min,0xffffffff,dStr.c_str()); + if (displaySizedata[(unsigned short)(fft->needle+(j*displaySize/precision))]; + if (y_s!=-1) { + y=(float)y_s/32768.0f; + if (minLevel>y) minLevel=y; + if (maxLevel0.5f) yOut=0.5f; + yOut*=chanOscAmplify*2.0f; + fft->oscTex[j]=yOut; + } + } else { + float y=0; + int k=0; + for (unsigned short j=fft->needle; j!=fft->needle+displaySize; j++, k++) { + const short y_s=buf->data[j]; + const int kTex=(k*precision)/displaySize; + if (kTex>=precision) break; + if (y_s!=-1) { + y=(float)y_s/32768.0f; + if (minLevel>y) minLevel=y; + if (maxLevel0.5f) yOut=0.5f; + yOut*=chanOscAmplify*2.0f; + fft->oscTex[kTex]=yOut; + } } dcOff=(minLevel+maxLevel)*0.5f; - if (rend->supportsDrawOsc() && settings.shaderOsc) { - for (unsigned short j=0; jdata[(unsigned short)(fft->needle+(j*displaySize/precision))]/32768.0f; - y-=dcOff; - if (y<-0.5f) y=-0.5f; - if (y>0.5f) y=0.5f; - y*=chanOscAmplify*2.0f; - fft->oscTex[j]=y; - } - } else { + if (!(rend->supportsDrawOsc() && settings.shaderOsc)) { for (unsigned short j=0; jdata[(unsigned short)(fft->needle+(j*displaySize/precision))]/32768.0f; - y-=dcOff; - if (y<-0.5f) y=-0.5f; - if (y>0.5f) y=0.5f; - y*=chanOscAmplify; - waveform[j]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-y)); + waveform[j]=ImLerp(inRect.Min,inRect.Max,ImVec2(x,0.5f-fft->oscTex[j]*0.5f)); } } } diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 89515ebfc..15f17f851 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -252,7 +252,7 @@ void FurnaceGUI::drawDebug() { ImGui::TableNextColumn(); ImGui::Text("Follow"); ImGui::TableNextColumn(); - ImGui::Text("Address"); + ImGui::Text("Needle"); ImGui::TableNextColumn(); ImGui::Text("Data"); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index a2402e553..60c245b86 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4181,8 +4181,9 @@ bool FurnaceGUI::loop() { for (int i=0; igetTotalChannelCount(); i++) { DivDispatchOscBuffer* buf=e->getOscBuffer(i); if (buf!=NULL) { - buf->needle=0; - buf->readNeedle=0; + //buf->needle=0; + //buf->readNeedle=0; + // TODO: should we reset here? } } });