From 5ff81aef3324d0720bba1486c177ba9ff01a4f56 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 30 Oct 2025 20:35:14 -0500 Subject: [PATCH] some time refactors no more weird totalTicks name code looks better --- src/engine/engine.cpp | 41 +++++---------- src/engine/engine.h | 18 +++---- src/engine/filePlayer.cpp | 24 ++++----- src/engine/filePlayer.h | 5 +- src/engine/playback.cpp | 32 ++++++------ src/engine/song.cpp | 18 +++---- src/engine/song.h | 3 +- src/gui/clock.cpp | 5 +- src/gui/debugWindow.cpp | 6 ++- src/gui/gui.cpp | 46 +++-------------- src/gui/orders.cpp | 25 ++------- src/gui/pattern.cpp | 3 +- src/gui/refPlayer.cpp | 68 ++++++------------------- src/gui/tutorial.cpp | 2 +- src/timeutils.cpp | 103 +++++++++++++++++++++++++++++++++++--- src/timeutils.h | 68 ++++++++++++++++++++++++- 16 files changed, 256 insertions(+), 211 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index d2b9d9f61..b2b87277e 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -1511,8 +1511,7 @@ String DivEngine::getPlaybackDebugInfo() { "midiTimeDrift: %f\n" "changeOrd: %d\n" "changePos: %d\n" - "totalSeconds: %d\n" - "totalTicks: %d\n" + "totalTime: %s\n" "totalTicksR: %d\n" "curMidiClock: %d\n" "curMidiTime: %d\n" @@ -1524,7 +1523,7 @@ String DivEngine::getPlaybackDebugInfo() { "totalProcessed: %d\n" "bufferPos: %d\n", curOrder,prevOrder,curRow,prevRow,ticks,subticks,totalLoops,lastLoopPos,nextSpeed,divider,cycles,clockDrift, - midiClockCycles,midiClockDrift,midiTimeCycles,midiTimeDrift,changeOrd,changePos,totalSeconds,totalTicks, + midiClockCycles,midiClockDrift,midiTimeCycles,midiTimeDrift,changeOrd,changePos,totalTime.toString(), totalTicksR,curMidiClock,curMidiTime,totalCmds,lastCmds,cmdsPerSecond, (int)extValue,(int)tempoAccum,(int)totalProcessed,(int)bufferPos ); @@ -1662,27 +1661,17 @@ void DivEngine::setFilePlayerSync(bool doSync) { filePlayerSync=doSync; } -void DivEngine::getFilePlayerCue(int& seconds, int& micros) { - seconds=filePlayerCueSeconds; - micros=filePlayerCueMicros; +TimeMicros DivEngine::getFilePlayerCue() { + return filePlayerCue; } -void DivEngine::setFilePlayerCue(int seconds, int micros) { - filePlayerCueSeconds=seconds; - filePlayerCueMicros=micros; +void DivEngine::setFilePlayerCue(TimeMicros cue) { + filePlayerCue=cue; } void DivEngine::syncFilePlayer() { if (curFilePlayer==NULL) return; - int finalSeconds=totalSeconds+filePlayerCueSeconds; - int finalMicros=totalTicks+filePlayerCueMicros; - - while (finalMicros>=1000000) { - finalMicros-=1000000; - finalSeconds++; - } - - curFilePlayer->setPosSeconds(finalSeconds,finalMicros); + curFilePlayer->setPosSeconds(totalTime+filePlayerCue); } void DivEngine::playSub(bool preserveDrift, int goalRow) { @@ -1717,9 +1706,8 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) { ticks=1; subticks=0; tempoAccum=0; - totalTicks=0; + totalTime=TimeMicros(0,0); totalTicksOff=0; - totalSeconds=0; totalTicksR=0; curMidiClock=0; curMidiTime=0; @@ -1809,7 +1797,7 @@ void DivEngine::playSub(bool preserveDrift, int goalRow) { cmdStream.clear(); std::chrono::high_resolution_clock::time_point timeEnd=std::chrono::high_resolution_clock::now(); logV("playSub() took %dµs",std::chrono::duration_cast(timeEnd-timeStart).count()); - logV("and landed us at %d.%06d (%d ticks, %d:%d.%d)",totalSeconds,totalTicks,totalTicksR,curOrder,curRow,ticks); + logV("and landed us at %s (%d ticks, %d:%d.%d)",totalTime.toString(),totalTicksR,curOrder,curRow,ticks); } /* @@ -2569,12 +2557,8 @@ void DivEngine::virtualTempoChanged() { BUSY_END; } -int DivEngine::getTotalSeconds() { - return totalSeconds; -} - -int DivEngine::getTotalTicks() { - return totalTicks; +TimeMicros DivEngine::getCurTime() { + return totalTime; } bool DivEngine::getRepeatPattern() { @@ -3995,9 +3979,8 @@ void DivEngine::quitDispatch() { nextSpeed=3; changeOrd=-1; changePos=0; - totalTicks=0; + totalTime=TimeMicros(0,0); totalTicksOff=0; - totalSeconds=0; totalTicksR=0; curMidiClock=0; curMidiTime=0; diff --git a/src/engine/engine.h b/src/engine/engine.h index 9cda7433e..804fdc3b4 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -510,7 +510,8 @@ class DivEngine { int midiTimeCycles; double midiTimeDrift; int stepPlay; - int changeOrd, changePos, totalSeconds, totalTicks, totalTicksR, curMidiClock, curMidiTime, totalCmds, lastCmds, cmdsPerSecond; + int changeOrd, changePos, totalTicksR, curMidiClock, curMidiTime, totalCmds, lastCmds, cmdsPerSecond; + TimeMicros totalTime; double totalTicksOff; int curMidiTimePiece, curMidiTimeCode; unsigned char extValue, pendingMetroTick; @@ -602,8 +603,7 @@ class DivEngine { size_t filePlayerBufLen; DivFilePlayer* curFilePlayer; bool filePlayerSync; - ssize_t filePlayerCueSeconds; - unsigned int filePlayerCueMicros; + TimeMicros filePlayerCue; int filePlayerLoopTrail; int curFilePlayerTrail; @@ -763,8 +763,8 @@ class DivEngine { bool getFilePlayerSync(); void setFilePlayerSync(bool doSync); // get/set file player cue position. - void getFilePlayerCue(int& seconds, int& micros); - void setFilePlayerCue(int seconds, int micros); + TimeMicros getFilePlayerCue(); + void setFilePlayerCue(TimeMicros cue); // UNSAFE - sync file player to current playback position. void syncFilePlayer(); @@ -1049,8 +1049,7 @@ class DivEngine { void virtualTempoChanged(); // get time - int getTotalTicks(); // 1/1000000th of a second - int getTotalSeconds(); + TimeMicros getCurTime(); // get repeat pattern bool getRepeatPattern(); @@ -1525,8 +1524,6 @@ class DivEngine { stepPlay(0), changeOrd(-1), changePos(0), - totalSeconds(0), - totalTicks(0), totalTicksR(0), curMidiClock(0), curMidiTime(0), @@ -1576,8 +1573,7 @@ class DivEngine { filePlayerBufLen(0), curFilePlayer(NULL), filePlayerSync(false), - filePlayerCueSeconds(0), - filePlayerCueMicros(0), + filePlayerCue(0,0), filePlayerLoopTrail(0), curFilePlayerTrail(0), totalProcessed(0), diff --git a/src/engine/filePlayer.cpp b/src/engine/filePlayer.cpp index 9c627ce84..62dac52de 100644 --- a/src/engine/filePlayer.cpp +++ b/src/engine/filePlayer.cpp @@ -298,15 +298,15 @@ ssize_t DivFilePlayer::getPos() { return playPos; } -void DivFilePlayer::getPosSeconds(ssize_t& seconds, unsigned int& micros) { +TimeMicros DivFilePlayer::getPosSeconds() { if (sf==NULL) { - seconds=0; - micros=0; - return; + return TimeMicros(0,0); } double microsD=playPos%si.samplerate; - seconds=playPos/si.samplerate; - micros=(int)((1000000.0*microsD)/(double)si.samplerate); + return TimeMicros( + playPos/si.samplerate, // seconds + (int)((1000000.0*microsD)/(double)si.samplerate) // microseconds + ); } ssize_t DivFilePlayer::setPos(ssize_t newPos, unsigned int offset) { @@ -325,20 +325,20 @@ ssize_t DivFilePlayer::setPos(ssize_t newPos, unsigned int offset) { } } -ssize_t DivFilePlayer::setPosSeconds(ssize_t seconds, unsigned int micros, unsigned int offset) { +ssize_t DivFilePlayer::setPosSeconds(TimeMicros newTime, unsigned int offset) { if (sf==NULL) return 0; - double microsD=(double)si.samplerate*((double)micros/1000000.0); + double microsD=(double)si.samplerate*((double)newTime.micros/1000000.0); if (offset==UINT_MAX) { - playPos=seconds*si.samplerate+(int)microsD; + playPos=(ssize_t)newTime.seconds*(ssize_t)si.samplerate+(int)microsD; rateAccum=0; wantBlock=playPos; - logD("DivFilePlayer: setPosSeconds(%" PRIi64 ".%06d)",seconds,micros); + logD("DivFilePlayer: setPosSeconds(%s)",newTime.toString()); return playPos; } else { pendingPosOffset=offset; - pendingPos=seconds*si.samplerate+(int)microsD; + pendingPos=(ssize_t)newTime.seconds*(ssize_t)si.samplerate+(int)microsD; wantBlock=pendingPos; - logD("DivFilePlayer: offset %u setPosSeconds(%" PRIi64 ".%06d)",offset,seconds,micros); + logD("DivFilePlayer: offset %u setPosSeconds(%s)",offset,newTime.toString()); return pendingPos; } } diff --git a/src/engine/filePlayer.h b/src/engine/filePlayer.h index 0ab310179..50fac93ad 100644 --- a/src/engine/filePlayer.h +++ b/src/engine/filePlayer.h @@ -21,6 +21,7 @@ #define _FILEPLAYER_H #include "../ta-utils.h" +#include "../timeutils.h" #include #include #include @@ -78,9 +79,9 @@ class DivFilePlayer { void mix(float** buf, int chans, unsigned int size); ssize_t getPos(); - void getPosSeconds(ssize_t& seconds, unsigned int& micros); + TimeMicros getPosSeconds(); ssize_t setPos(ssize_t newPos, unsigned int offset=UINT_MAX); - ssize_t setPosSeconds(ssize_t seconds, unsigned int micros, unsigned int offset=UINT_MAX); + ssize_t setPosSeconds(TimeMicros newTime, unsigned int offset=UINT_MAX); bool isBlockPresent(ssize_t pos); bool setBlockPriority(ssize_t pos, bool priority); diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 1c94ad275..d52ed1144 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -2172,8 +2172,9 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { // also set the playback position and sync file player if necessary TimeMicros rowTS=curSubSong->ts.getTimes(curOrder,curRow); - totalSeconds=rowTS.seconds; - totalTicks=rowTS.micros; + if (rowTS.seconds!=-1) { + totalTime=rowTS; + } if (curFilePlayer && filePlayerSync) { syncFilePlayer(); } @@ -2581,25 +2582,27 @@ bool DivEngine::nextTick(bool noAccum, bool inhibitLowLat) { if (!noAccum) { double dt=divider*tickMult; totalTicksR++; - // despite the name, totalTicks is in microseconds... - totalTicks+=1000000/dt; + totalTime.micros+=1000000/dt; totalTicksOff+=fmod(1000000.0,dt); while (totalTicksOff>=dt) { totalTicksOff-=dt; - totalTicks++; + totalTime.micros++; } } - if (totalTicks>=1000000) { - totalTicks-=1000000; + if (totalTime.micros>=1000000) { + totalTime.micros-=1000000; // who's gonna play a song for 68 years? - if (totalSeconds<0x7fffffff) totalSeconds++; + if (totalTime.seconds<0x7fffffff) totalTime.seconds++; cmdsPerSecond=totalCmds-lastCmds; lastCmds=totalCmds; } } // print status in console mode - if (consoleMode && !disableStatusOut && subticks<=1 && !skipping) fprintf(stderr,"\x1b[2K> %d:%.2d:%.2d.%.2d %.2x/%.2x:%.3d/%.3d %4dcmd/s\x1b[G",totalSeconds/3600,(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000,curOrder,curSubSong->ordersLen,curRow,curSubSong->patLen,cmdsPerSecond); + if (consoleMode && !disableStatusOut && subticks<=1 && !skipping) { + String timeFormatted=totalTime.toString(2,TA_TIME_FORMAT_HMS); + fprintf(stderr,"\x1b[2K> %s %.2x/%.2x:%.3d/%.3d %4dcmd/s\x1b[G",timeFormatted.c_str(),curOrder,curSubSong->ordersLen,curRow,curSubSong->patLen,cmdsPerSecond); + } } @@ -3110,15 +3113,12 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi if (curFilePlayer && filePlayerSync) { if (curFilePlayer->isPlaying()) { TimeMicros rowTS=curSubSong->ts.loopStartTime; - int finalSeconds=rowTS.seconds+filePlayerCueSeconds; - int finalMicros=rowTS.micros+filePlayerCueMicros; - while (finalMicros>=1000000) { - finalMicros-=1000000; - finalSeconds++; + if (rowTS.seconds==-1) { + logW("that row isn't supposed to play. report this now!"); } - curFilePlayer->setPosSeconds(finalSeconds,finalMicros,lastLoopPos); + curFilePlayer->setPosSeconds(rowTS+filePlayerCue,lastLoopPos); } } // increase total loop count @@ -3232,7 +3232,7 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi // complain and stop playback if we believe the engine has stalled //logD("attempts: %d",attempts); if (attempts>=(int)(size+10)) { - logE("hang detected! stopping! at %d seconds %d micro (%d>=%d)",totalSeconds,totalTicks,attempts,(int)size); + logE("hang detected! stopping! at %s (%d>=%d)",totalTime.toString(),attempts,(int)size); freelance=false; playing=false; extValuePresent=false; diff --git a/src/engine/song.cpp b/src/engine/song.cpp index 9d70c5283..116815da7 100644 --- a/src/engine/song.cpp +++ b/src/engine/song.cpp @@ -30,8 +30,7 @@ TimeMicros DivSongTimestamps::getTimes(int order, int row) { } DivSongTimestamps::DivSongTimestamps(): - totalSeconds(0), - totalMicros(0), + totalTime(0,0), totalTicks(0), totalRows(0), isLoopDefined(false), @@ -54,8 +53,7 @@ void DivSubSong::calcTimestamps(int chans, std::vector& groove std::chrono::high_resolution_clock::time_point timeStart=std::chrono::high_resolution_clock::now(); // reset state - ts.totalSeconds=0; - ts.totalMicros=0; + ts.totalTime=TimeMicros(0,0); ts.totalTicks=0; ts.totalRows=0; ts.isLoopDefined=true; @@ -396,7 +394,7 @@ void DivSubSong::calcTimestamps(int chans, std::vector& groove ts.orders[prevOrder][i].seconds=-1; } } - ts.orders[prevOrder][prevRow]=TimeMicros(ts.totalSeconds,ts.totalMicros); + ts.orders[prevOrder][prevRow]=ts.totalTime; rowChanged=false; } @@ -405,16 +403,16 @@ void DivSubSong::calcTimestamps(int chans, std::vector& groove double dt=divider;//*((double)virtualTempoN/(double)MAX(1,virtualTempoD)); ts.totalTicks++; - ts.totalMicros+=1000000/dt; + ts.totalTime.micros+=1000000/dt; totalMicrosOff+=fmod(1000000.0,dt); while (totalMicrosOff>=dt) { totalMicrosOff-=dt; - ts.totalMicros++; + ts.totalTime.micros++; } - if (ts.totalMicros>=1000000) { - ts.totalMicros-=1000000; + if (ts.totalTime.micros>=1000000) { + ts.totalTime.micros-=1000000; // who's gonna play a song for 68 years? - if (ts.totalSeconds<0x7fffffff) ts.totalSeconds++; + if (ts.totalTime.seconds<0x7fffffff) ts.totalTime.seconds++; } } if (ts.maxRow[curOrder]getTotalTicks(); - int totalSeconds=e->getTotalSeconds(); + String timeFormatted=e->getCurTime().toString(2,TA_TIME_FORMAT_MS_ZERO); ImGui::PushFont(bigFont); - ImGui::Text("%.2d:%.2d.%.2d",(totalSeconds/60),totalSeconds%60,totalTicks/10000); + ImGui::TextUnformatted(timeFormatted.c_str()); ImGui::PopFont(); } } diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 5d29a0a6a..63fc23973 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -206,7 +206,8 @@ void FurnaceGUI::drawDebug() { DivSongTimestamps& ts=e->curSubSong->ts; - ImGui::Text("song duration: %d.%06d (%d ticks; %d rows)",ts.totalSeconds,ts.totalMicros,ts.totalTicks,ts.totalRows); + 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); if (ts.isLoopDefined) { ImGui::Text("loop region is defined"); } else { @@ -219,7 +220,8 @@ void FurnaceGUI::drawDebug() { } ImGui::Text("loop region: %d:%d - %d:%d",ts.loopStart.order,ts.loopStart.row,ts.loopEnd.order,ts.loopEnd.row); - ImGui::Text("loop start time: %d.%06d",ts.loopStartTime.seconds,ts.loopStartTime.micros); + timeFormatted=ts.loopStartTime.toString(-1,TA_TIME_FORMAT_AUTO); + ImGui::Text("loop start time: %s",timeFormatted.c_str()); if (ImGui::TreeNode("Maximum rows")) { for (int i=0; icurSubSong->ordersLen; i++) { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 35ee384b0..a4081350f 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2719,7 +2719,7 @@ void FurnaceGUI::exportAudio(String path, DivAudioExportModes mode) { e->calcSongTimestamps(); DivSongTimestamps& ts=e->curSubSong->ts; - songLength=ts.totalSeconds+(double)ts.totalMicros/1000000.0; + songLength=ts.totalTime.toDouble(); double loopLength=songLength-(ts.loopStartTime.seconds+(double)ts.loopStartTime.micros/1000000.0); e->saveAudio(path.c_str(),audioExportOptions); @@ -4843,8 +4843,7 @@ bool FurnaceGUI::loop() { } ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_PLAYBACK_STAT]); if (e->isPlaying() && settings.playbackTime) { - int totalTicks=e->getTotalTicks(); - int totalSeconds=e->getTotalSeconds(); + TimeMicros totalTime=e->getCurTime(); String info; @@ -4873,32 +4872,10 @@ bool FurnaceGUI::loop() { info+=_("| "); - if (totalSeconds==0x7fffffff) { + if (totalTime.seconds==0x7fffffff) { info+=_("Don't you have anything better to do?"); } else { - if (totalSeconds>=86400) { - int totalDays=totalSeconds/86400; - int totalYears=totalDays/365; - totalDays%=365; - int totalMonths=totalDays/30; - totalDays%=30; - -#ifdef HAVE_LOCALE - info+=fmt::sprintf(ngettext("%d year ","%d years ",totalYears),totalYears); - info+=fmt::sprintf(ngettext("%d month ","%d months ",totalMonths),totalMonths); - info+=fmt::sprintf(ngettext("%d day ","%d days ",totalDays),totalDays); -#else - info+=fmt::sprintf(_GN("%d year ","%d years ",totalYears),totalYears); - info+=fmt::sprintf(_GN("%d month ","%d months ",totalMonths),totalMonths); - info+=fmt::sprintf(_GN("%d day ","%d days ",totalDays),totalDays); -#endif - } - - if (totalSeconds>=3600) { - info+=fmt::sprintf("%.2d:",(totalSeconds/3600)%24); - } - - info+=fmt::sprintf("%.2d:%.2d.%.2d",(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000); + info+=totalTime.toString(2,TA_TIME_FORMAT_AUTO_MS_ZERO); } ImGui::TextUnformatted(info.c_str()); @@ -6039,7 +6016,7 @@ bool FurnaceGUI::loop() { [this, curFileLambda] () { *curFileLambda=0; e->getCurFileIndex(*curFileLambda); - curProgress=(((double)e->getTotalSeconds()+(double)e->getTotalTicks()/1000000.0)+(songLength*(*curFileLambda)))/totalLength; + curProgress=(e->getCurTime().toDouble()+(songLength*(*curFileLambda)))/totalLength; } ); } @@ -7390,17 +7367,8 @@ bool FurnaceGUI::loop() { if (!fp->isPlaying()) { TimeMicros rowTS=e->curSubSong->ts.getTimes(cursor.order,cursor.y); if (rowTS.seconds!=-1) { - int cueSeconds=0; - int cueMicros=0; - e->getFilePlayerCue(cueSeconds,cueMicros); - rowTS.seconds+=cueSeconds; - rowTS.micros+=cueMicros; - while (rowTS.micros>=1000000) { - rowTS.micros-=1000000; - rowTS.seconds++; - } - - fp->setPosSeconds(rowTS.seconds,rowTS.micros); + TimeMicros cueTime=e->getFilePlayerCue(); + fp->setPosSeconds(cueTime+rowTS); } } } diff --git a/src/gui/orders.cpp b/src/gui/orders.cpp index 406d0237c..2f85a69b0 100644 --- a/src/gui/orders.cpp +++ b/src/gui/orders.cpp @@ -90,30 +90,11 @@ void FurnaceGUI::drawMobileOrderSel() { // time if (e->isPlaying() && settings.playbackTime) { - int totalTicks=e->getTotalTicks(); - int totalSeconds=e->getTotalSeconds(); - String info=""; + TimeMicros totalTime=e->getCurTime(); + String info=totalTime.toString(2,TA_TIME_FORMAT_AUTO_MS_ZERO); - if (totalSeconds==0x7fffffff) { + if (totalTime.seconds==0x7fffffff) { info="∞"; - } else { - if (totalSeconds>=86400) { - int totalDays=totalSeconds/86400; - int totalYears=totalDays/365; - totalDays%=365; - int totalMonths=totalDays/30; - totalDays%=30; - - info+=fmt::sprintf("%dy",totalYears); - info+=fmt::sprintf("%dm",totalMonths); - info+=fmt::sprintf("%dd",totalDays); - } - - if (totalSeconds>=3600) { - info+=fmt::sprintf("%.2d:",(totalSeconds/3600)%24); - } - - info+=fmt::sprintf("%.2d:%.2d.%.2d",(totalSeconds/60)%60,totalSeconds%60,totalTicks/10000); } ImVec2 textSize=ImGui::CalcTextSize(info.c_str()); diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index aeea36b63..46f799c27 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -412,7 +412,8 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int if (rowTS.seconds==-1) { ImGui::Text("---"); } else { - ImGui::Text("%d.%06d",rowTS.seconds,rowTS.micros); + String timeFormatted=rowTS.toString(2,TA_TIME_FORMAT_AUTO_MS_ZERO); + ImGui::TextUnformatted(timeFormatted.c_str()); } } } diff --git a/src/gui/refPlayer.cpp b/src/gui/refPlayer.cpp index de0884078..be2f12067 100644 --- a/src/gui/refPlayer.cpp +++ b/src/gui/refPlayer.cpp @@ -79,21 +79,15 @@ void FurnaceGUI::drawRefPlayer() { } if (fp->isPlaying()) { if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { - int cueSeconds=0; - int cueMicros=0; fp->stop(); - e->getFilePlayerCue(cueSeconds,cueMicros); - fp->setPosSeconds(cueSeconds,cueMicros); + fp->setPosSeconds(e->getFilePlayerCue()); } if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) { fp->stop(); fp->setPos(0); } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { - int cueSeconds=0; - int cueMicros=0; - e->getFilePlayerCue(cueSeconds,cueMicros); - fp->setPosSeconds(cueSeconds,cueMicros); + fp->setPosSeconds(e->getFilePlayerCue()); } ImGui::SetItemTooltip( _("left click: go to cue position\n" @@ -103,21 +97,12 @@ void FurnaceGUI::drawRefPlayer() { } else { if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { // try setting cue pos - ssize_t curSeconds=0; - unsigned int curMicros=0; - fp->getPosSeconds(curSeconds,curMicros); + TimeMicros curPos=fp->getPosSeconds(); TimeMicros rowTS=e->curSubSong->ts.getTimes(curOrder,0); if (rowTS.seconds==-1) { showError(_("the first row of this order isn't going to play.")); } else { - // calculate difference and set cue pos - curSeconds-=rowTS.seconds; - int curMicrosI=curMicros-rowTS.micros; - while (curMicrosI<0) { - curMicrosI+=1000000; - curSeconds--; - } - e->setFilePlayerCue(curSeconds,curMicrosI); + e->setFilePlayerCue(curPos-rowTS); } } if (ImGui::IsItemClicked(ImGuiMouseButton_Middle)) { @@ -125,25 +110,23 @@ void FurnaceGUI::drawRefPlayer() { } if (ImGui::BeginPopupContextItem("Edit Cue Position",ImGuiPopupFlags_MouseButtonRight)) { ImGui::TextUnformatted(_("Set cue position at first order:")); - int cueSeconds=0; - int cueMicros=0; + TimeMicros cueTime=e->getFilePlayerCue(); bool altered=false; - e->getFilePlayerCue(cueSeconds,cueMicros); // TODO: improve this... ImGui::SetNextItemWidth(240.0f*dpiScale); - if (ImGui::InputInt(_("Seconds##CuePosS"),&cueSeconds)) { - if (cueSeconds<-3600) cueSeconds=-3600; - if (cueSeconds>3600) cueSeconds=3600; + if (ImGui::InputInt(_("Seconds##CuePosS"),&cueTime.seconds)) { + if (cueTime.seconds<-3600) cueTime.seconds=-3600; + if (cueTime.seconds>3600) cueTime.seconds=3600; altered=true; } ImGui::SetNextItemWidth(240.0f*dpiScale); - if (ImGui::InputInt(_("Microseconds##CuePosM"),&cueMicros,1000,10000)) { - if (cueMicros<0) cueMicros=0; - if (cueMicros>999999) cueMicros=999999; + if (ImGui::InputInt(_("Microseconds##CuePosM"),&cueTime.micros,1000,10000)) { + if (cueTime.micros<0) cueTime.micros=0; + if (cueTime.micros>999999) cueTime.micros=999999; altered=true; } if (altered) { - e->setFilePlayerCue(cueSeconds,cueMicros); + e->setFilePlayerCue(cueTime); } if (ImGui::Button(_("OK"))) { ImGui::CloseCurrentPopup(); @@ -165,21 +148,12 @@ void FurnaceGUI::drawRefPlayer() { } if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { // try setting cue pos - ssize_t curSeconds=0; - unsigned int curMicros=0; - fp->getPosSeconds(curSeconds,curMicros); + TimeMicros curPos=fp->getPosSeconds(); TimeMicros rowTS=e->curSubSong->ts.getTimes(curOrder,0); if (rowTS.seconds==-1) { showError(_("the first row of this order isn't going to play.")); } else { - // calculate difference and set cue pos - curSeconds-=rowTS.seconds; - int curMicrosI=curMicros-rowTS.micros; - while (curMicrosI<0) { - curMicrosI+=1000000; - curSeconds--; - } - e->setFilePlayerCue(curSeconds,curMicrosI); + e->setFilePlayerCue(curPos-rowTS); fp->stop(); } } @@ -203,9 +177,7 @@ void FurnaceGUI::drawRefPlayer() { } else { rowTS=e->curSubSong->ts.getTimes(curOrder,0); } - int cueSeconds=0; - int cueMicros=0; - e->getFilePlayerCue(cueSeconds,cueMicros); + TimeMicros cueTime=e->getFilePlayerCue(); if (rowTS.seconds==-1) { if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { showError(_("the row that the pattern cursor is at isn't going to play. try moving the cursor.")); @@ -213,15 +185,7 @@ void FurnaceGUI::drawRefPlayer() { showError(_("the first row of this order isn't going to play. try another order.")); } } else { - int finalSeconds=rowTS.seconds+cueSeconds; - int finalMicros=rowTS.micros+cueMicros; - - while (finalMicros>=1000000) { - finalMicros-=1000000; - finalSeconds++; - } - - fp->setPosSeconds(finalSeconds,finalMicros); + fp->setPosSeconds(rowTS+cueTime); fp->play(); } } diff --git a/src/gui/tutorial.cpp b/src/gui/tutorial.cpp index 2b6d0eb2c..50812fbd2 100644 --- a/src/gui/tutorial.cpp +++ b/src/gui/tutorial.cpp @@ -1082,7 +1082,7 @@ void FurnaceGUI::drawTutorial() { oneQuarter=(oneQuarter*e->curSubSong->virtualTempoN)/e->curSubSong->virtualTempoD; oneQuarter/=e->curSubSong->hz; oneQuarter/=4; - if (cv->playSongs && e->getTotalSeconds()>=oneQuarter) { + if (cv->playSongs && e->getCurTime().seconds>=oneQuarter) { if (loadRandomDemoSong()) { cv->loadInstruments(); e->changeSongP(0); diff --git a/src/timeutils.cpp b/src/timeutils.cpp index 0c9c058d8..158fdd42c 100644 --- a/src/timeutils.cpp +++ b/src/timeutils.cpp @@ -20,7 +20,7 @@ #include "timeutils.h" #include -String TimeMicros::toString(signed char prec, unsigned char hms) { +String TimeMicros::toString(signed char prec, TATimeFormats hms) { String ret; int actualSeconds=seconds; int actualMicros=micros; @@ -31,8 +31,55 @@ String TimeMicros::toString(signed char prec, unsigned char hms) { } if (negative) actualSeconds=-actualSeconds; + // handle auto formats switch (hms) { - case 2: { // h:mm:ss + case TA_TIME_FORMAT_AUTO: + hms=TA_TIME_FORMAT_SECONDS; + if (actualSeconds>60) hms=TA_TIME_FORMAT_MS; + if (actualSeconds>3600) hms=TA_TIME_FORMAT_HMS; + if (actualSeconds>86400) hms=TA_TIME_FORMAT_DAYS_HMS; + break; + case TA_TIME_FORMAT_AUTO_ZERO: + hms=TA_TIME_FORMAT_SECONDS; + if (actualSeconds>60) hms=TA_TIME_FORMAT_MS_ZERO; + if (actualSeconds>3600) hms=TA_TIME_FORMAT_HMS_ZERO; + if (actualSeconds>86400) hms=TA_TIME_FORMAT_DAYS_HMS_ZERO; + break; + case TA_TIME_FORMAT_AUTO_MS: + hms=TA_TIME_FORMAT_MS; + if (actualSeconds>3600) hms=TA_TIME_FORMAT_HMS; + if (actualSeconds>86400) hms=TA_TIME_FORMAT_DAYS_HMS; + break; + case TA_TIME_FORMAT_AUTO_MS_ZERO: + hms=TA_TIME_FORMAT_MS_ZERO; + if (actualSeconds>3600) hms=TA_TIME_FORMAT_HMS_ZERO; + if (actualSeconds>86400) hms=TA_TIME_FORMAT_DAYS_HMS_ZERO; + break; + default: + break; + } + + switch (hms) { + case TA_TIME_FORMAT_SECONDS: { // seconds + if (negative) { + ret=fmt::sprintf("-%d",actualSeconds); + } else { + ret=fmt::sprintf("%d",actualSeconds); + } + break; + } + case TA_TIME_FORMAT_MS: { // m:ss + int m=actualSeconds/60; + int s=actualSeconds%60; + + if (negative) { + ret=fmt::sprintf("-%d:%02d",m,s); + } else { + ret=fmt::sprintf("%d:%02d",m,s); + } + break; + } + case TA_TIME_FORMAT_HMS: { // h:mm:ss int h=actualSeconds/3600; int m=(actualSeconds/60)%60; int s=actualSeconds%60; @@ -44,25 +91,65 @@ String TimeMicros::toString(signed char prec, unsigned char hms) { } break; } - case 1: { // m:ss + case TA_TIME_FORMAT_MS_ZERO: { // mm:ss int m=actualSeconds/60; int s=actualSeconds%60; if (negative) { - ret=fmt::sprintf("-%d:%02d",m,s); + ret=fmt::sprintf("-%02d:%02d",m,s); } else { - ret=fmt::sprintf("%d:%02d",m,s); + ret=fmt::sprintf("%02d:%02d",m,s); } break; } - default: { // seconds + case TA_TIME_FORMAT_HMS_ZERO: { // hh:mm:ss + int h=actualSeconds/3600; + int m=(actualSeconds/60)%60; + int s=actualSeconds%60; + if (negative) { - ret=fmt::sprintf("-%d",actualSeconds); + ret=fmt::sprintf("-%02d:%02d:%02d",h,m,s); } else { - ret=fmt::sprintf("%d",actualSeconds); + ret=fmt::sprintf("%02d:%02d:%02d",h,m,s); } break; } + case TA_TIME_FORMAT_DAYS_HMS: { // ?y?m?d h:mm:ss + int days=actualSeconds/86400; + int years=days/365; + days%=365; + int months=days/30; + days%=30; + int h=(actualSeconds/3600)%24; + int m=(actualSeconds/60)%60; + int s=actualSeconds%60; + + if (negative) { + ret=fmt::sprintf("-%dy%dm%dd %d:%02d:%02d",years,months,days,h,m,s); + } else { + ret=fmt::sprintf("%dy%dm%dd %d:%02d:%02d",years,months,days,h,m,s); + } + break; + } + case TA_TIME_FORMAT_DAYS_HMS_ZERO: { // ?y?m?d hh:mm:ss + int days=actualSeconds/86400; + int years=days/365; + days%=365; + int months=days/30; + days%=30; + int h=(actualSeconds/3600)%24; + int m=(actualSeconds/60)%60; + int s=actualSeconds%60; + + if (negative) { + ret=fmt::sprintf("-%dy%dm%dd %02d:%02d:%02d",years,months,days,h,m,s); + } else { + ret=fmt::sprintf("%dy%dm%dd %02d:%02d:%02d",years,months,days,h,m,s); + } + break; + } + default: + return "ERROR!"; } if (prec<0) { diff --git a/src/timeutils.h b/src/timeutils.h index 0bf07ccf5..7da4f92d8 100644 --- a/src/timeutils.h +++ b/src/timeutils.h @@ -27,6 +27,23 @@ #include "ta-utils.h" +enum TATimeFormats: unsigned char { + TA_TIME_FORMAT_SECONDS=0, // seconds only + TA_TIME_FORMAT_MS, // m:ss + TA_TIME_FORMAT_HMS, // h:mm:ss + + TA_TIME_FORMAT_MS_ZERO, // mm:ss + TA_TIME_FORMAT_HMS_ZERO, // hh:mm:ss + + TA_TIME_FORMAT_DAYS_HMS, // years, months, days, h:mm:ss + TA_TIME_FORMAT_DAYS_HMS_ZERO, // years, months, days, hh:mm:ss + + TA_TIME_FORMAT_AUTO, // automatic + TA_TIME_FORMAT_AUTO_ZERO, // automatic (zero) + TA_TIME_FORMAT_AUTO_MS, // automatic (from minutes) + TA_TIME_FORMAT_AUTO_MS_ZERO, // automatic (from minutes; zero) +}; + struct TimeMicros { int seconds, micros; @@ -37,13 +54,62 @@ struct TimeMicros { return seconds+(double)micros/1000000.0; } + // operators + inline TimeMicros& operator+(TimeMicros& other) { + seconds+=other.seconds; + micros+=other.micros; + while (micros>=1000000) { + micros-=1000000; + seconds++; + } + return *this; + } + inline TimeMicros& operator+(int other) { + seconds+=other; + return *this; + } + inline TimeMicros& operator-(TimeMicros& other) { + seconds-=other.seconds; + micros-=other.micros; + while (micros<0) { + micros+=1000000; + seconds--; + } + return *this; + } + inline TimeMicros& operator-(int other) { + seconds-=other; + return *this; + } + + // comparison operators + inline bool operator==(TimeMicros& other) { + return (seconds==other.seconds && micros==other.micros); + } + inline bool operator>(TimeMicros& other) { + return (seconds>other.seconds || (seconds==other.seconds && micros>other.micros)); + } + inline bool operator>=(TimeMicros& other) { + return (seconds>other.seconds || (seconds==other.seconds && micros>=other.micros)); + } + + inline bool operator!=(TimeMicros& other) { + return !(*this==other); + } + inline bool operator<(TimeMicros& other) { + return !(*this>=other); + } + inline bool operator<=(TimeMicros& other) { + return !(*this>other); + } + /** * convert this TimeMicros to a String. * @param prec maximum digit precision (0-6). use -1 for automatic precision. * @param hms how many denominations to include (0: seconds, 1: minutes, 2: hours). * @return formatted TimeMicros. */ - String toString(signed char prec=-1, unsigned char hms=0); + String toString(signed char prec=6, TATimeFormats hms=TA_TIME_FORMAT_SECONDS); static TimeMicros fromString(String s); TimeMicros(int s, int u):