mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-26 14:33:01 +00:00
account for fadeout length, optimize some progress bar calc
This commit is contained in:
parent
17f6ea5c6a
commit
a4dae5302b
7 changed files with 180 additions and 28 deletions
|
@ -199,9 +199,11 @@ void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) {
|
|||
}
|
||||
}
|
||||
|
||||
void DivEngine::findSongLength(bool& hasFFxx, std::vector<int>& 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<int>& orders, int& length)
|
||||
{
|
||||
if (curSubSong!=NULL)
|
||||
{
|
||||
curSubSong->findLength(loopOrder, loopRow, fadeoutLen, rowsForFadeout, hasFFxx, orders, song.grooves, length, chans, song.jumpTreatment, song.ignoreJumpAtEnd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<int>& orders, int& length, int loopOrder, int loopRow, int loopEnd);
|
||||
void findSongLength(int loopOrder, int loopRow, double fadeoutLen, int& rowsForFadeout, bool& hasFFxx, std::vector<int>& 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),
|
||||
|
|
|
@ -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<int>& 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<MIN(16,speeds.len); i++) {
|
||||
speedSum+=speeds.val[i];
|
||||
}
|
||||
speedSum/=MAX(1,speeds.len);
|
||||
if (timeBase<1.0) timeBase=1.0;
|
||||
if (speedSum<1.0) speedSum=1.0;
|
||||
if (vD<1) vD=1;
|
||||
//return (60.0 * hz / (timeBase * hl * speedSum)) * (double)vN / (double)vD;
|
||||
return 1.0 / ((60.0*hz/(timeBase*hl*speedSum))*(double)vN/(double)vD / 60.0);
|
||||
}
|
||||
|
||||
void DivSubSong::findLength(int loopOrder, int loopRow, double fadeoutLen, int& rowsForFadeout, bool& hasFFxx, std::vector<int>& orders_vec, std::vector<DivGroovePattern>& 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<int>& 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<chans; k++)
|
||||
|
@ -162,6 +184,51 @@ void DivSubSong::findLength(bool& hasFFxx, std::vector<int>& 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<int>& 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)
|
||||
|
|
|
@ -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<int>& 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<int>& orders, std::vector<DivGroovePattern>& grooves, int& length, int chans, int jumpTreatment, int ignoreJumpAtEnd, int firstPat=0);
|
||||
|
||||
void clearData();
|
||||
void optimizePatterns();
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -1726,7 +1726,11 @@ class FurnaceGUI {
|
|||
std::vector<int> 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;
|
||||
|
|
Loading…
Reference in a new issue