diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 0f1c30822..b7935803d 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -264,6 +264,19 @@ double DivEngine::benchmarkSeek() { return tAvg; } +double DivEngine::benchmarkWalk() { + std::chrono::high_resolution_clock::time_point timeStart=std::chrono::high_resolution_clock::now(); + + // benchmark + calcSongTimestamps(); + + std::chrono::high_resolution_clock::time_point timeEnd=std::chrono::high_resolution_clock::now(); + + double t=(double)(std::chrono::duration_cast(timeEnd-timeStart).count())/1000000.0; + printf("[RESULT] %fs\n",t); + return t; +} + void DivEngine::notifyInsChange(int ins) { BUSY_BEGIN; for (int i=0; i #include TimeMicros DivSongTimestamps::getTimes(int order, int row) { @@ -347,22 +348,40 @@ void DivSubSong::calcTimestamps(int chans, std::vector& groove // MAKE IT WORK while (!endOfSong) { + // heuristic + int advance=(curVirtualTempoD*ticks)/curVirtualTempoN; + for (int i=0; i0) { + if (rowDelay[i]0) { - if (--rowDelay[i]==0) { + rowDelay[i]-=advance; + if (rowDelay[i]==0) { tinyProcessRow(i,true); } } } // run virtual tempo - tempoAccum+=curVirtualTempoN; + tempoAccum+=curVirtualTempoN*advance; while (tempoAccum>=curVirtualTempoD) { - tempoAccum-=curVirtualTempoD; + int ticksToRun=tempoAccum/curVirtualTempoD; + tempoAccum%=curVirtualTempoD; // tick counter - if (--ticks<=0) { + ticks-=ticksToRun; + if (ticks<0) { + // if ticks is negative, we must call ticks back + tempoAccum+=-ticks*curVirtualTempoD; + } + if (ticks<=0) { if (shallStopSched) { shallStop=true; break; @@ -400,8 +419,8 @@ void DivSubSong::calcTimestamps(int chans, std::vector& groove if (!endOfSong) { // update playback time - double dt=divider;//*((double)virtualTempoN/(double)MAX(1,virtualTempoD)); - ts.totalTicks++; + double dt=divider/(double)advance;//*((double)virtualTempoN/(double)MAX(1,virtualTempoD)); + ts.totalTicks+=advance; ts.totalTime.micros+=1000000/dt; totalMicrosOff+=fmod(1000000.0,dt); @@ -410,9 +429,10 @@ void DivSubSong::calcTimestamps(int chans, std::vector& groove ts.totalTime.micros++; } if (ts.totalTime.micros>=1000000) { - ts.totalTime.micros-=1000000; // who's gonna play a song for 68 years? - if (ts.totalTime.seconds<0x7fffffff) ts.totalTime.seconds++; + ts.totalTime.seconds+=ts.totalTime.micros/1000000; + if (ts.totalTime.seconds<0) ts.totalTime.seconds=INT_MAX; + ts.totalTime.micros%=1000000; } } if (ts.maxRow[curOrder]& groove std::chrono::high_resolution_clock::time_point timeEnd=std::chrono::high_resolution_clock::now(); logV("calcTimestamps() took %dµs",std::chrono::duration_cast(timeEnd-timeStart).count()); + logV("song length: %s; %" PRIu64 " ticks",ts.totalTime.toString(6,TA_TIME_FORMAT_AUTO),ts.totalTicks); } void DivSubSong::clearData() { diff --git a/src/engine/song.h b/src/engine/song.h index 437e1159e..4b6e1b7fc 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -171,7 +171,7 @@ struct DivGroovePattern { struct DivSongTimestamps { // song duration (in seconds and microseconds) TimeMicros totalTime; - int totalTicks; + uint64_t totalTicks; int totalRows; // loop region (order/row positions) diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 1b3ba9259..dfd809e84 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -21,7 +21,7 @@ #include "guiConst.h" #include "debug.h" #include "IconsFontAwesome4.h" -#include +#include #include #include "imgui.h" #include "imgui_internal.h" @@ -208,7 +208,7 @@ void FurnaceGUI::drawDebug() { DivSongTimestamps& ts=e->curSubSong->ts; String timeFormatted=ts.totalTime.toString(-1,TA_TIME_FORMAT_AUTO); - ImGui::Text("song duration: %s (%d ticks; %d rows)",timeFormatted.c_str(),ts.totalTicks,ts.totalRows); + ImGui::Text("song duration: %s (%" PRIu64 " ticks; %d rows)",timeFormatted.c_str(),ts.totalTicks,ts.totalRows); if (ts.isLoopDefined) { ImGui::Text("loop region is defined"); } else { diff --git a/src/main.cpp b/src/main.cpp index 28706699e..51bc477f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -539,8 +539,10 @@ TAParamResult pBenchmark(String val) { benchMode=1; } else if (val=="seek") { benchMode=2; + } else if (val=="walk") { + benchMode=3; } else { - logE("invalid value for benchmark! valid values are: render and seek."); + logE("invalid value for benchmark! valid values are: render, seek and walk."); return TA_PARAM_ERROR; } e.setAudio(DIV_AUDIO_DUMMY); @@ -653,7 +655,7 @@ void initParams() { params.push_back(TAParam("S","safemode",false,pSafeMode,"","enable safe mode (software rendering and no audio)")); params.push_back(TAParam("A","safeaudio",false,pSafeModeAudio,"","enable safe mode (with audio")); - params.push_back(TAParam("B","benchmark",true,pBenchmark,"render|seek","run performance test")); + params.push_back(TAParam("B","benchmark",true,pBenchmark,"render|seek|walk","run performance test")); params.push_back(TAParam("V","version",false,pVersion,"","view information about Furnace.")); params.push_back(TAParam("W","warranty",false,pWarranty,"","view warranty disclaimer.")); @@ -1031,7 +1033,9 @@ int main(int argc, char** argv) { if (benchMode) { logI("starting benchmark!"); - if (benchMode==2) { + if (benchMode==3) { + e.benchmarkWalk(); + } else if (benchMode==2) { e.benchmarkSeek(); } else { e.benchmarkPlayback();