From a4dae5302ba4fe68331f3a5f00ef3491d1133d15 Mon Sep 17 00:00:00 2001 From: LTVA1 <87536432+LTVA1@users.noreply.github.com> Date: Wed, 21 Aug 2024 15:11:11 +0300 Subject: [PATCH] account for fadeout length, optimize some progress bar calc --- src/engine/engine.cpp | 8 ++-- src/engine/engine.h | 7 +++- src/engine/song.cpp | 91 +++++++++++++++++++++++++++++++++++++++---- src/engine/song.h | 2 +- src/engine/wavOps.cpp | 7 +++- src/gui/gui.cpp | 89 +++++++++++++++++++++++++++++++++++------- src/gui/gui.h | 4 ++ 7 files changed, 180 insertions(+), 28 deletions(-) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index b8defa1f7..fbbf0edc8 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -199,9 +199,11 @@ void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) { } } -void DivEngine::findSongLength(bool& hasFFxx, std::vector& orders, int& length, int loopOrder, int loopRow, int loopEnd) { - if (curSubSong!=NULL) { - curSubSong->findLength(hasFFxx, orders, length, loopOrder, loopRow, loopEnd, chans, song.jumpTreatment, song.ignoreJumpAtEnd); +void DivEngine::findSongLength(int loopOrder, int loopRow, double fadeoutLen, int& rowsForFadeout, bool& hasFFxx, std::vector& orders, int& length) +{ + if (curSubSong!=NULL) + { + curSubSong->findLength(loopOrder, loopRow, fadeoutLen, rowsForFadeout, hasFFxx, orders, song.grooves, length, chans, song.jumpTreatment, song.ignoreJumpAtEnd); } } diff --git a/src/engine/engine.h b/src/engine/engine.h index 5541b4fe6..64d406964 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -498,6 +498,7 @@ class DivEngine { DivAudioExportModes exportMode; DivAudioExportFormats exportFormat; double exportFadeOut; + bool isFadingOut; int exportOutputs; bool exportChannelMask[DIV_MAX_CHANS]; DivConfig conf; @@ -817,7 +818,7 @@ class DivEngine { void walkSong(int& loopOrder, int& loopRow, int& loopEnd); // find song length in rows (up to specified loop point), and find length of every order - void findSongLength(bool& hasFFxx, std::vector& orders, int& length, int loopOrder, int loopRow, int loopEnd); + void findSongLength(int loopOrder, int loopRow, double fadeoutLen, int& rowsForFadeout, bool& hasFFxx, std::vector& orders, int& length); // play (returns whether successful) bool play(); @@ -1025,6 +1026,9 @@ class DivEngine { //get which file is processed right now (progress for e.g. per-channel export) void getCurFileIndex(int& file); + //get fadeout state + bool getIsFadingOut(); + // add instrument int addInstrument(int refChan=0, DivInstrumentType fallbackType=DIV_INS_STD); @@ -1457,6 +1461,7 @@ class DivEngine { exportMode(DIV_EXPORT_MODE_ONE), exportFormat(DIV_EXPORT_FORMAT_S16), exportFadeOut(0.0), + isFadingOut(false), exportOutputs(2), cmdStreamInt(NULL), midiBaseChan(0), diff --git a/src/engine/song.cpp b/src/engine/song.cpp index e4a398c2c..e4c516b6e 100644 --- a/src/engine/song.cpp +++ b/src/engine/song.cpp @@ -102,14 +102,39 @@ bool DivSubSong::walk(int& loopOrder, int& loopRow, int& loopEnd, int chans, int return false; } -void DivSubSong::findLength(bool& hasFFxx, std::vector& orders_vec, int& length, int& loopOrder, int& loopRow, int& loopEnd, int chans, int jumpTreatment, int ignoreJumpAtEnd, int firstPat) +double calcRowLenInSeconds(const DivGroovePattern& speeds, float hz, int vN, int vD, int timeBaseFromSong) +{ + double hl=1; //count for 1 row + if (hl<=0.0) hl=4.0; + double timeBase=timeBaseFromSong+1; + double speedSum=0; + for (int i=0; i& orders_vec, std::vector& grooves, int& length, int chans, int jumpTreatment, int ignoreJumpAtEnd, int firstPat) { length = 0; hasFFxx = false; + rowsForFadeout = 0; + + float secondsPerThisRow = 0.0f; + + DivGroovePattern curSpeeds = speeds; //simulate that we are playing the song, track all speed/BPM/tempo/engine rate changes + short curVirtualTempoN = virtualTempoN; + short curVirtualTempoD = virtualTempoD; + float curHz = hz; + double curDivider = (double)timeBase; + + double curLen = 0.0; //how many seconds passed since the start of song - loopOrder=0; - loopRow=0; - loopEnd=-1; int nextOrder=-1; int nextRow=0; int effectVal=0; @@ -139,9 +164,6 @@ void DivSubSong::findLength(bool& hasFFxx, std::vector& orders_vec, int& le bool jumpingOrder=false; if (wsWalked[((i<<5)+(j>>3))&8191]&(1<<(j&7))) { - loopOrder=i; - loopRow=j; - loopEnd=lastSuspectedLoopEnd; return; } for (int k=0; k& orders_vec, int& le return; } + switch(subPat[k]->data[j][4+(l<<1)]) //track speed/BMP/Hz/tempo changes + { + case 0x09: // select groove pattern/speed 1 + { + if (grooves.empty()) { + if (effectVal>0) curSpeeds.val[0]=effectVal; + } else { + if (effectVal<(short)grooves.size()) { + curSpeeds=grooves[effectVal]; + //curSpeed=0; + } + } + break; + } + case 0x0f: // speed 1/speed 2 + { + if (curSpeeds.len==2 && grooves.empty()) { + if (effectVal>0) curSpeeds.val[1]=effectVal; + } else { + if (effectVal>0) curSpeeds.val[0]=effectVal; + } + break; + } + case 0xfd: // virtual tempo num + { + if (effectVal>0) curVirtualTempoN=effectVal; + break; + } + case 0xfe: // virtual tempo den + { + if (effectVal>0) curVirtualTempoD=effectVal; + break; + } + case 0xf0: // set Hz by tempo (set bpm) + { + curDivider=(double)effectVal*2.0/5.0; + if (curDivider<1) curDivider=1; + //cycles=got.rate*pow(2,MASTER_CLOCK_PREC)/divider; + //clockDrift=0; + //subticks=0; + break; + } + default: break; + } + if (subPat[k]->data[j][4+(l<<1)]==0x0d) { if (jumpTreatment==2) @@ -210,6 +277,16 @@ void DivSubSong::findLength(bool& hasFFxx, std::vector& orders_vec, int& le } } + if(i > loopOrder || (i == loopOrder && j > loopRow)) + { + if(curLen <= fadeoutLen && fadeoutLen > 0.0) //we count each row fadeout lasts. When our time is greater than fadeout length we successfully counted the number of fadeout rows + { + secondsPerThisRow = calcRowLenInSeconds(speeds, curHz, curVirtualTempoN, curVirtualTempoD, curDivider); + curLen += secondsPerThisRow; + rowsForFadeout++; + } + } + wsWalked[((i<<5)+(j>>3))&8191]|=1<<(j&7); if (nextOrder!=-1) diff --git a/src/engine/song.h b/src/engine/song.h index e247ca0ca..75b86ec71 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -188,7 +188,7 @@ struct DivSubSong { /** * find song length in rows (up to specified loop point). Also find length of every row */ - void findLength(bool& hasFFxx, std::vector& orders, int& length, int& loopOrder, int& loopRow, int& loopEnd, int chans, int jumpTreatment, int ignoreJumpAtEnd, int firstPat=0); + void findLength(int loopOrder, int loopRow, double fadeoutLen, int& rowsForFadeout, bool& hasFFxx, std::vector& orders, std::vector& grooves, int& length, int chans, int jumpTreatment, int ignoreJumpAtEnd, int firstPat=0); void clearData(); void optimizePatterns(); diff --git a/src/engine/wavOps.cpp b/src/engine/wavOps.cpp index c8e5a5b03..f1e8de315 100644 --- a/src/engine/wavOps.cpp +++ b/src/engine/wavOps.cpp @@ -104,11 +104,16 @@ void DivEngine::getCurFileIndex(int& file) } } +bool DivEngine::getIsFadingOut() +{ + return isFadingOut; +} + #ifdef HAVE_SNDFILE void DivEngine::runExportThread() { size_t fadeOutSamples=got.rate*exportFadeOut; size_t curFadeOutSample=0; - bool isFadingOut=false; + isFadingOut=false; switch (exportMode) { case DIV_EXPORT_MODE_ONE: { diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 4e314959d..5235faa21 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2588,7 +2588,8 @@ void FurnaceGUI::exportAudio(String path, DivAudioExportModes mode) { int loopRow=0; int loopEnd=0; e->walkSong(loopOrder,loopRow,loopEnd); - e->findSongLength(songHasSongEndCommand, songOrdersLengths, songLength, loopOrder, loopRow, loopEnd); //for progress estimation + + e->findSongLength(loopOrder, loopRow, audioExportOptions.fadeOut, songFadeoutSectionLength, songHasSongEndCommand, songOrdersLengths, songLength); //for progress estimation songLoopedSectionLength = songLength; for(int i = 0; i < loopOrder; i++) @@ -2598,9 +2599,74 @@ void FurnaceGUI::exportAudio(String path, DivAudioExportModes mode) { songLoopedSectionLength -= loopRow; e->saveAudio(path.c_str(),audioExportOptions); + + int totalFiles = 0; + e->getTotalAudioFiles(totalFiles); + int totalLoops = 0; + + lengthOfOneFile = songLength; + + if(!songHasSongEndCommand) + { + e->getTotalLoops(totalLoops); + + lengthOfOneFile += songLoopedSectionLength * totalLoops; + lengthOfOneFile += songFadeoutSectionLength; //account for fadeout + } + + totalLength = lengthOfOneFile * totalFiles; + + curProgress = 0.0f; + displayExporting=true; } + /*e->lockEngine([this, progressLambda]() + { + int totalFiles = 0; + e->getTotalAudioFiles(totalFiles); + int loopsLeft = 0; + int totalLoops = 0; + + int curRow = 0; + int curOrder = 0; + e->getCurSongPos(curRow, curOrder); + int curFile = 0; + e->getCurFileIndex(curFile); + + int lengthOfOneFile = songLength; + + int curPosInRows = curRow; + + for(int i = 0; i < curOrder; i++) + { + curPosInRows += songOrdersLengths[i]; + } + + if(!songHasSongEndCommand) + { + e->getLoopsLeft(loopsLeft); + e->getTotalLoops(totalLoops); + + lengthOfOneFile += songLoopedSectionLength * totalLoops; + lengthOfOneFile += songFadeoutSectionLength; //account for fadeout + + if(totalLoops != loopsLeft) //we are going 2nd, 3rd, etc. time through the song + { + curPosInRows -= (songLength - songLoopedSectionLength); //a hack so progress bar does not jump? + } + } + + //int lengthOfOneFile = songLength * (totalLoops + 1); + //songLoopedSectionLength + int totalLength = lengthOfOneFile * totalFiles; + + *progressLambda = (float)(curPosInRows + + (totalLoops - loopsLeft) * songLength + + lengthOfOneFile * curFile) + / (float)totalLength; + });*/ + void FurnaceGUI::editStr(String* which) { editString=which; displayEditString=true; @@ -5837,14 +5903,11 @@ bool FurnaceGUI::loop() { centerNextWindow(_("Rendering..."),canvasW,canvasH); if (ImGui::BeginPopupModal(_("Rendering..."),NULL,ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) { ImGui::Text(_("Please wait...")); - float progress = 0.0f; - float* progressLambda = &progress; + float* progressLambda = &curProgress; if(e->isExporting()) { e->lockEngine([this, progressLambda]() { - int totalFiles = 0; - e->getTotalAudioFiles(totalFiles); int loopsLeft = 0; int totalLoops = 0; @@ -5854,8 +5917,6 @@ bool FurnaceGUI::loop() { int curFile = 0; e->getCurFileIndex(curFile); - int lengthOfOneFile = songLength; - int curPosInRows = curRow; for(int i = 0; i < curOrder; i++) @@ -5868,26 +5929,24 @@ bool FurnaceGUI::loop() { e->getLoopsLeft(loopsLeft); e->getTotalLoops(totalLoops); - lengthOfOneFile += songLoopedSectionLength * totalLoops; - if(totalLoops != loopsLeft) //we are going 2nd, 3rd, etc. time through the song { curPosInRows -= (songLength - songLoopedSectionLength); //a hack so progress bar does not jump? } + if(e->getIsFadingOut()) //we are in fadeout??? why it works like that bruh + { + curPosInRows -= (songLength - songLoopedSectionLength); //a hack so progress bar does not jump? + } } - //int lengthOfOneFile = songLength * (totalLoops + 1); - //songLoopedSectionLength - int totalLength = lengthOfOneFile * totalFiles; - *progressLambda = (float)(curPosInRows + (totalLoops - loopsLeft) * songLength + lengthOfOneFile * curFile) / (float)totalLength; }); } - ImGui::Text(_("%f"), progress); - ImGui::ProgressBar(progress,ImVec2(-FLT_MIN,0)); + ImGui::Text(_("%f"), curProgress); + ImGui::ProgressBar(curProgress,ImVec2(-FLT_MIN,0)); if (ImGui::Button(_("Abort"))) { if (e->haltAudioFile()) { ImGui::CloseCurrentPopup(); diff --git a/src/gui/gui.h b/src/gui/gui.h index 46ec9f592..f95160de2 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1726,7 +1726,11 @@ class FurnaceGUI { std::vector songOrdersLengths; //lengths of all orders (for drawing song export progress) int songLength; //length of all the song in rows int songLoopedSectionLength; //length of looped part of the song + int songFadeoutSectionLength; //length of fading part of the song bool songHasSongEndCommand; //song has "Song end" command (FFxx) + int lengthOfOneFile; //length of one rendering pass. song length times num of loops + fadeout + int totalLength; //total length of render (lengthOfOneFile times num of files for per-channel export) + float curProgress; struct Settings { bool settingsChanged;