some time refactors

no more weird totalTicks name
code looks better
This commit is contained in:
tildearrow 2025-10-30 20:35:14 -05:00
parent a2b56b5b64
commit 5ff81aef33
16 changed files with 256 additions and 211 deletions

View file

@ -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<std::chrono::microseconds>(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;

View file

@ -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),

View file

@ -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;
}
}

View file

@ -21,6 +21,7 @@
#define _FILEPLAYER_H
#include "../ta-utils.h"
#include "../timeutils.h"
#include <thread>
#include <mutex>
#include <condition_variable>
@ -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);

View file

@ -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;

View file

@ -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<DivGroovePattern>& 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<DivGroovePattern>& 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<DivGroovePattern>& 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]<curRow) ts.maxRow[curOrder]=curRow;

View file

@ -170,8 +170,7 @@ struct DivGroovePattern {
struct DivSongTimestamps {
// song duration (in seconds and microseconds)
int totalSeconds;
int totalMicros;
TimeMicros totalTime;
int totalTicks;
int totalRows;

View file

@ -104,10 +104,9 @@ void FurnaceGUI::drawClock() {
}
}
if (clockShowTime) {
int totalTicks=e->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();
}
}

View file

@ -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; i<e->curSubSong->ordersLen; i++) {

View file

@ -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);
}
}
}

View file

@ -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());

View file

@ -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());
}
}
}

View file

@ -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();
}
}

View file

@ -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);

View file

@ -20,7 +20,7 @@
#include "timeutils.h"
#include <fmt/printf.h>
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) {

View file

@ -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):