diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 847824fd..12fe249f 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2668,10 +2668,17 @@ void DivEngine::previewSampleNoLock(int sample, int note, int pStart, int pEnd) if (rate<=0) rate=song.sample[sample]->centerRate; } if (rate<100) rate=100; + double rateOrig=rate; + sPreview.rateMul=1; + while (sPreview.rateMul<0x40000000 && rate=0)?sPreview.pBegin:0; + sPreview.posSub=0; sPreview.sample=sample; sPreview.wave=-1; sPreview.dir=false; @@ -2696,10 +2703,17 @@ void DivEngine::previewWaveNoLock(int wave, int note) { blip_clear(samp_bb); double rate=song.wave[wave]->len*((song.tuning*0.0625)*pow(2.0,(double)(note+3)/12.0)); if (rate<100) rate=100; + double rateOrig=rate; + sPreview.rateMul=1; + while (sPreview.rateMul<0x40000000 && ratesoftLocked=true; e->isBusy.lock(); #define EXTERN_BUSY_END e->isBusy.unlock(); e->softLocked=false; -#define DIV_VERSION "dev152" -#define DIV_ENGINE_VERSION 152 +#define DIV_VERSION "dev153" +#define DIV_ENGINE_VERSION 153 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 @@ -414,6 +414,7 @@ class DivEngine { int wave; int pos; int pBegin, pEnd; + int rateMul, posSub; bool dir; SamplePreview(): rate(0.0), @@ -422,6 +423,8 @@ class DivEngine { pos(0), pBegin(-1), pEnd(-1), + rateMul(1), + posSub(0), dir(false) {} } sPreview; diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 0ca5dff6..c184d20a 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -2715,6 +2715,15 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } } + // SrgaPCM slide compat + if (ds.version<153) { + for (int i=0; icalcArp(chan[i].note,chan[i].std.arp.val)<<6); + chan[i].baseFreq=(parent->calcArp(chan[i].note,chan[i].std.arp.val)<<7); } chan[i].freqChanged=true; } @@ -106,21 +106,22 @@ void DivPlatformSegaPCM::tick(bool sysTick) { } if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) { - chan[i].freq=chan[i].baseFreq+(chan[i].pitch>>1)-64; + chan[i].freq=chan[i].baseFreq+(chan[i].pitch)-128+(oldSlides?0:chan[i].pitch2); if (!parent->song.oldArpStrategy) { if (chan[i].fixedArp) { - chan[i].freq=(chan[i].baseNoteOverride<<6)+(chan[i].pitch>>1)-64+chan[i].pitch2; + chan[i].freq=(chan[i].baseNoteOverride<<7)+chan[i].pitch-128+(chan[i].pitch2<<(oldSlides?1:0)); } else { - chan[i].freq+=chan[i].arpOff<<6; + chan[i].freq+=chan[i].arpOff<<7; } } + if (oldSlides) chan[i].freq&=~1; if (chan[i].furnacePCM) { double off=1.0; if (chan[i].pcm.sample>=0 && chan[i].pcm.samplesong.sampleLen) { DivSample* s=parent->getSample(chan[i].pcm.sample); off=(double)s->centerRate/8363.0; } - chan[i].pcm.freq=MIN(255,(15625+(off*parent->song.tuning*pow(2.0,double(chan[i].freq+256)/(64.0*12.0)))*255)/31250)+chan[i].pitch2; + chan[i].pcm.freq=MIN(255,(15625+(off*parent->song.tuning*pow(2.0,double(chan[i].freq+512)/(128.0*12.0)))*255)/31250)+(oldSlides?chan[i].pitch2:0); rWrite(7+(i<<3),chan[i].pcm.freq); } chan[i].freqChanged=false; @@ -201,7 +202,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { } if (c.value!=DIV_NOTE_NULL) { chan[c.chan].note=c.value; - chan[c.chan].baseFreq=(c.value<<6); + chan[c.chan].baseFreq=(c.value<<7); chan[c.chan].freqChanged=true; } chan[c.chan].furnacePCM=true; @@ -289,17 +290,18 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { break; } case DIV_CMD_NOTE_PORTA: { - int destFreq=(c.value2<<6); + int destFreq=(c.value2<<7); int newFreq; + int mul=(oldSlides || parent->song.linearPitch!=2)?8:1; bool return2=false; if (destFreq>chan[c.chan].baseFreq) { - newFreq=chan[c.chan].baseFreq+c.value*4; + newFreq=chan[c.chan].baseFreq+c.value*mul; if (newFreq>=destFreq) { newFreq=destFreq; return2=true; } } else { - newFreq=chan[c.chan].baseFreq-c.value*4; + newFreq=chan[c.chan].baseFreq-c.value*mul; if (newFreq<=destFreq) { newFreq=destFreq; return2=true; @@ -314,7 +316,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { break; } case DIV_CMD_LEGATO: { - chan[c.chan].baseFreq=(c.value<<6); + chan[c.chan].baseFreq=(c.value<<7); chan[c.chan].freqChanged=true; break; } @@ -337,7 +339,7 @@ int DivPlatformSegaPCM::dispatch(DivCommand c) { return 127; break; case DIV_CMD_PRE_PORTA: - if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=(chan[c.chan].note<<6); + if (!chan[c.chan].inPorta && c.value && !parent->song.brokenPortaArp && chan[c.chan].std.arp.will && !NEW_ARP_STRAT) chan[c.chan].baseFreq=(chan[c.chan].note<<7); chan[c.chan].inPorta=c.value; break; case DIV_CMD_PRE_NOTE: @@ -504,6 +506,8 @@ void DivPlatformSegaPCM::setFlags(const DivConfig& flags) { for (int i=0; i<16; i++) { oscBuf[i]->rate=rate; } + + oldSlides=flags.getBool("oldSlides",false); } int DivPlatformSegaPCM::getOutputCount() { diff --git a/src/engine/platform/segapcm.h b/src/engine/platform/segapcm.h index 9e2ad5df..b818306b 100644 --- a/src/engine/platform/segapcm.h +++ b/src/engine/platform/segapcm.h @@ -65,6 +65,7 @@ class DivPlatformSegaPCM: public DivDispatch { segapcm_device pcm; int delay; int pcmL, pcmR, pcmCycles; + bool oldSlides; unsigned char sampleBank; unsigned char lastBusy; diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 1ca9df58..808e2b15 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -1541,10 +1541,13 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi samp_temp=0; } else { samp_temp=s->data16[sPreview.pos]; - if (sPreview.dir) { - sPreview.pos--; - } else { - sPreview.pos++; + if (--sPreview.posSub<=0) { + sPreview.posSub=sPreview.rateMul; + if (sPreview.dir) { + sPreview.pos--; + } else { + sPreview.pos++; + } } } blip_add_delta(samp_bb,i,samp_temp-samp_prevSample); @@ -1649,8 +1652,11 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } else { samp_temp=((MIN(wave->data[sPreview.pos],wave->max)<<14)/wave->max)-8192; } - if (++sPreview.pos>=wave->len) { - sPreview.pos=0; + if (--sPreview.posSub<=0) { + sPreview.posSub=sPreview.rateMul; + if (++sPreview.pos>=wave->len) { + sPreview.pos=0; + } } blip_add_delta(samp_bb,i,samp_temp-samp_prevSample); samp_prevSample=samp_temp; diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index ae1a1dfc..7eb3906a 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -540,9 +540,23 @@ void FurnaceGUI::drawDebug() { } if (ImGui::TreeNode("Performance")) { double perfFreq=SDL_GetPerformanceFrequency()/1000000.0; + int lastProcTime=(int)e->processTime/1000; + TAAudioDesc& audioGot=e->getAudioDescGot(); + + ImGui::Text("video frame: %.0fµs",ImGui::GetIO().DeltaTime*1000000.0); + ImGui::Text("audio frame: %.0fµs",1000000.0*(double)audioGot.bufsize/(double)audioGot.rate); + ImGui::Separator(); + + ImGui::Text("audio: %dµs",lastProcTime); ImGui::Text("render: %.0fµs",(double)renderTimeDelta/perfFreq); ImGui::Text("layout: %.0fµs",(double)layoutTimeDelta/perfFreq); ImGui::Text("event: %.0fµs",(double)eventTimeDelta/perfFreq); + ImGui::Separator(); + + ImGui::Text("details:"); + for (int i=0; igetTotalTicks(); int totalSeconds=e->getTotalSeconds(); @@ -4269,36 +4331,38 @@ bool FurnaceGUI::loop() { if (e->isPlaying()) monitorPos+=ImGui::GetIO().DeltaTime; } - drawSampleList(); - drawSampleEdit(); - drawWaveList(); - drawWaveEdit(); - drawInsList(); - drawInsEdit(); - drawMixer(); + MEASURE(sampleList,drawSampleList()); + MEASURE(sampleEdit,drawSampleEdit()); + MEASURE(waveList,drawWaveList()); + MEASURE(waveEdit,drawWaveEdit()); + MEASURE(insList,drawInsList()); + MEASURE(insEdit,drawInsEdit()); + MEASURE(mixer,drawMixer()); - readOsc(); + MEASURE(readOsc,readOsc()); - drawOsc(); - drawChanOsc(); - drawVolMeter(); - drawSettings(); - drawDebug(); - drawStats(); - if (!basicMode) drawCompatFlags(); - drawPiano(); - drawNotes(); + MEASURE(osc,drawOsc()); + MEASURE(chanOsc,drawChanOsc()); + MEASURE(volMeter,drawVolMeter()); + MEASURE(settings,drawSettings()); + MEASURE(debug,drawDebug()); + MEASURE(stats,drawStats()); if (!basicMode) { - drawChannels(); + MEASURE(compatFlags,drawCompatFlags()); } - drawPatManager(); + MEASURE(piano,drawPiano()); + MEASURE(notes,drawNotes()); if (!basicMode) { - drawSysManager(); + MEASURE(channels,drawChannels()); } - drawClock(); - drawRegView(); - drawLog(); - drawEffectList(); + MEASURE(patManager,drawPatManager()); + if (!basicMode) { + MEASURE(sysManager,drawSysManager()); + } + MEASURE(clock,drawClock()); + MEASURE(regView,drawRegView()); + MEASURE(log,drawLog()); + MEASURE(effectList,drawEffectList()); } activateTutorial(GUI_TUTORIAL_OVERVIEW); @@ -4960,6 +5024,8 @@ bool FurnaceGUI::loop() { } if (aboutOpen) drawAbout(); + MEASURE_BEGIN(popup); + if (ImGui::BeginPopupModal("Rendering...",NULL,ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::Text("Please wait..."); if (ImGui::Button("Abort")) { @@ -5491,12 +5557,16 @@ bool FurnaceGUI::loop() { ImGui::EndPopup(); } + MEASURE_END(popup); + if (!tutorial.introPlayed || settings.alwaysPlayIntro!=0) { + MEASURE_BEGIN(intro); initialScreenWipe=0; if (settings.alwaysPlayIntro==1) { shortIntro=true; } drawIntro(introPos); + MEASURE_END(intro); } else { introPos=12.0; } @@ -6577,6 +6647,7 @@ FurnaceGUI::FurnaceGUI(): eventTimeBegin(0), eventTimeEnd(0), eventTimeDelta(0), + perfMetricsLen(0), chanToMove(-1), sysToMove(-1), sysToDelete(-1), diff --git a/src/gui/gui.h b/src/gui/gui.h index 75bd3d26..3e3478cc 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1154,6 +1154,17 @@ struct FurnaceGUIImage { ch(0) {} }; +struct FurnaceGUIPerfMetric { + const char* name; + int elapsed; + FurnaceGUIPerfMetric(const char* n, int t): + name(n), + elapsed(t) {} + FurnaceGUIPerfMetric(): + name(NULL), + elapsed(0) {} +}; + class FurnaceGUI { DivEngine* e; @@ -1739,6 +1750,12 @@ class FurnaceGUI { int renderTimeBegin, renderTimeEnd, renderTimeDelta; int eventTimeBegin, eventTimeEnd, eventTimeDelta; + FurnaceGUIPerfMetric perfMetrics[64]; + int perfMetricsLen; + + FurnaceGUIPerfMetric perfMetricsLast[64]; + int perfMetricsLastLen; + std::map images; int chanToMove, sysToMove, sysToDelete, opToMove; diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 31f66e0a..251ae960 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -1770,6 +1770,21 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo } break; } + case DIV_SYSTEM_SEGAPCM: + case DIV_SYSTEM_SEGAPCM_COMPAT: { + bool oldSlides=flags.getBool("oldSlides",false); + + if (ImGui::Checkbox("Legacy slides and pitch (compatibility)",&oldSlides)) { + altered=true; + } + + if (altered) { + e->lockSave([&]() { + flags.set("oldSlides",oldSlides); + }); + } + break; + } case DIV_SYSTEM_SM8521:/* { bool noAntiClick=flags.getBool("noAntiClick",false);