Merge branch 'tildearrow:master' into SID3
This commit is contained in:
commit
093b1fe4dc
8 changed files with 451 additions and 23 deletions
|
|
@ -199,6 +199,14 @@ void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) {
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
#define EXPORT_BUFSIZE 2048
|
||||
|
||||
double DivEngine::benchmarkPlayback() {
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ class DivEngine {
|
|||
int midiOutTimeRate;
|
||||
float midiVolExp;
|
||||
int softLockCount;
|
||||
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, nextSpeed, elapsedBars, elapsedBeats, curSpeed;
|
||||
int subticks, ticks, curRow, curOrder, prevRow, prevOrder, remainingLoops, totalLoops, lastLoopPos, exportLoopCount, curExportChan /*for per-channel export progress*/, nextSpeed, elapsedBars, elapsedBeats, curSpeed;
|
||||
size_t curSubSongIndex;
|
||||
size_t bufferPos;
|
||||
double divider;
|
||||
|
|
@ -498,6 +498,7 @@ class DivEngine {
|
|||
DivAudioExportModes exportMode;
|
||||
DivAudioExportFormats exportFormat;
|
||||
double exportFadeOut;
|
||||
bool isFadingOut;
|
||||
int exportOutputs;
|
||||
bool exportChannelMask[DIV_MAX_CHANS];
|
||||
DivConfig conf;
|
||||
|
|
@ -816,6 +817,9 @@ class DivEngine {
|
|||
// find song loop position
|
||||
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(int loopOrder, int loopRow, double fadeoutLen, int& rowsForFadeout, bool& hasFFxx, std::vector<int>& orders, int& length);
|
||||
|
||||
// play (returns whether successful)
|
||||
bool play();
|
||||
|
||||
|
|
@ -1007,6 +1011,24 @@ class DivEngine {
|
|||
// is exporting
|
||||
bool isExporting();
|
||||
|
||||
// get how many loops is left
|
||||
void getLoopsLeft(int& loops);
|
||||
|
||||
//get how many loops in total export needs to do
|
||||
void getTotalLoops(int& loops);
|
||||
|
||||
// get current position in song
|
||||
void getCurSongPos(int& row, int& order);
|
||||
|
||||
//get how many files export needs to create
|
||||
void getTotalAudioFiles(int& files);
|
||||
|
||||
//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);
|
||||
|
||||
|
|
@ -1400,6 +1422,7 @@ class DivEngine {
|
|||
totalLoops(0),
|
||||
lastLoopPos(0),
|
||||
exportLoopCount(0),
|
||||
curExportChan(0),
|
||||
nextSpeed(3),
|
||||
elapsedBars(0),
|
||||
elapsedBeats(0),
|
||||
|
|
@ -1438,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,6 +102,211 @@ bool DivSubSong::walk(int& loopOrder, int& loopRow, int& loopEnd, int chans, int
|
|||
return false;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
int nextOrder=-1;
|
||||
int nextRow=0;
|
||||
int effectVal=0;
|
||||
int lastSuspectedLoopEnd=-1;
|
||||
DivPattern* subPat[DIV_MAX_CHANS];
|
||||
unsigned char wsWalked[8192];
|
||||
memset(wsWalked,0,8192);
|
||||
if (firstPat>0) {
|
||||
memset(wsWalked,255,32*firstPat);
|
||||
}
|
||||
for (int i=firstPat; i<ordersLen; i++)
|
||||
{
|
||||
bool jumped = false;
|
||||
|
||||
for (int j=0; j<chans; j++)
|
||||
{
|
||||
subPat[j]=pat[j].getPattern(orders.ord[j][i],false);
|
||||
}
|
||||
if (i>lastSuspectedLoopEnd)
|
||||
{
|
||||
lastSuspectedLoopEnd=i;
|
||||
}
|
||||
for (int j=nextRow; j<patLen; j++)
|
||||
{
|
||||
nextRow=0;
|
||||
bool changingOrder=false;
|
||||
bool jumpingOrder=false;
|
||||
if (wsWalked[((i<<5)+(j>>3))&8191]&(1<<(j&7)))
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int k=0; k<chans; k++)
|
||||
{
|
||||
for (int l=0; l<pat[k].effectCols; l++)
|
||||
{
|
||||
effectVal=subPat[k]->data[j][5+(l<<1)];
|
||||
if (effectVal<0) effectVal=0;
|
||||
|
||||
if (subPat[k]->data[j][4+(l<<1)]==0xff)
|
||||
{
|
||||
hasFFxx = true;
|
||||
|
||||
//FFxx makes YOU SHALL NOT PASS!!! move
|
||||
orders_vec.push_back(j + 1); //order len
|
||||
length += j + 1; //add length of order to song length
|
||||
|
||||
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)
|
||||
{
|
||||
if ((i<ordersLen-1 || !ignoreJumpAtEnd))
|
||||
{
|
||||
nextOrder=i+1;
|
||||
nextRow=effectVal;
|
||||
jumpingOrder=true;
|
||||
}
|
||||
}
|
||||
else if (jumpTreatment==1)
|
||||
{
|
||||
if (nextOrder==-1 && (i<ordersLen-1 || !ignoreJumpAtEnd))
|
||||
{
|
||||
nextOrder=i+1;
|
||||
nextRow=effectVal;
|
||||
jumpingOrder=true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((i<ordersLen-1 || !ignoreJumpAtEnd))
|
||||
{
|
||||
if (!changingOrder)
|
||||
{
|
||||
nextOrder=i+1;
|
||||
}
|
||||
jumpingOrder=true;
|
||||
nextRow=effectVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (subPat[k]->data[j][4+(l<<1)]==0x0b)
|
||||
{
|
||||
if (nextOrder==-1 || jumpTreatment==0)
|
||||
{
|
||||
nextOrder=effectVal;
|
||||
if (jumpTreatment==1 || jumpTreatment==2 || !jumpingOrder)
|
||||
{
|
||||
nextRow=0;
|
||||
}
|
||||
changingOrder=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
i=nextOrder-1;
|
||||
orders_vec.push_back(j + 1); //order len
|
||||
length += j + 1; //add length of order to song length
|
||||
jumped = true;
|
||||
nextOrder=-1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!jumped) //if no jump occured we add full pattern length
|
||||
{
|
||||
orders_vec.push_back(patLen); //order len
|
||||
length += patLen; //add length of order to song length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DivSubSong::clearData() {
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
pat[i].wipePatterns();
|
||||
|
|
|
|||
|
|
@ -186,6 +186,11 @@ struct DivSubSong {
|
|||
*/
|
||||
bool walk(int& loopOrder, int& loopRow, int& loopEnd, int chans, int jumpTreatment, int ignoreJumpAtEnd, int firstPat=0);
|
||||
|
||||
/**
|
||||
* find song length in rows (up to specified loop point). Also find length of every row
|
||||
*/
|
||||
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();
|
||||
void rearrangePatterns();
|
||||
|
|
|
|||
|
|
@ -33,11 +33,87 @@ bool DivEngine::isExporting() {
|
|||
return exporting;
|
||||
}
|
||||
|
||||
void DivEngine::getLoopsLeft(int& loops) {
|
||||
if(totalLoops < 0 || exportLoopCount == 0)
|
||||
{
|
||||
loops = 0;
|
||||
return;
|
||||
}
|
||||
loops = exportLoopCount - 1 - totalLoops;
|
||||
}
|
||||
|
||||
void DivEngine::getTotalLoops(int& loops) {
|
||||
loops = exportLoopCount - 1;
|
||||
}
|
||||
|
||||
void DivEngine::getCurSongPos(int& row, int& order) {
|
||||
row = curRow;
|
||||
order = curOrder;
|
||||
}
|
||||
|
||||
void DivEngine::getTotalAudioFiles(int& files)
|
||||
{
|
||||
files = 0;
|
||||
|
||||
switch(exportMode)
|
||||
{
|
||||
case DIV_EXPORT_MODE_ONE:
|
||||
{
|
||||
files = 1;
|
||||
break;
|
||||
}
|
||||
case DIV_EXPORT_MODE_MANY_SYS:
|
||||
{
|
||||
files = 1; //there actually are several files but they are processed in the same loop, so to correctly draw progress we think of them as one file
|
||||
break;
|
||||
}
|
||||
case DIV_EXPORT_MODE_MANY_CHAN:
|
||||
{
|
||||
for(int i = 0; i < chans; i++)
|
||||
{
|
||||
if (exportChannelMask[i]) files++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void DivEngine::getCurFileIndex(int& file)
|
||||
{
|
||||
file = 0;
|
||||
|
||||
switch(exportMode)
|
||||
{
|
||||
case DIV_EXPORT_MODE_ONE:
|
||||
{
|
||||
file = 0;
|
||||
break;
|
||||
}
|
||||
case DIV_EXPORT_MODE_MANY_SYS:
|
||||
{
|
||||
file = 0; //there actually are several files but they are processed in the same loop, so to correctly draw progress we think of them as one file
|
||||
break;
|
||||
}
|
||||
case DIV_EXPORT_MODE_MANY_CHAN:
|
||||
{
|
||||
file = curExportChan;
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
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: {
|
||||
|
|
@ -140,7 +216,11 @@ void DivEngine::runExportThread() {
|
|||
sf[i]=NULL;
|
||||
si[i].samplerate=got.rate;
|
||||
si[i].channels=disCont[i].dispatch->getOutputCount();
|
||||
si[i].format=SF_FORMAT_WAV|SF_FORMAT_PCM_16;
|
||||
if (exportFormat==DIV_EXPORT_FORMAT_S16) {
|
||||
si[i].format=SF_FORMAT_WAV|SF_FORMAT_PCM_16;
|
||||
} else {
|
||||
si[i].format=SF_FORMAT_WAV|SF_FORMAT_FLOAT;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<song.systemLen; i++) {
|
||||
|
|
@ -247,6 +327,8 @@ void DivEngine::runExportThread() {
|
|||
// take control of audio output
|
||||
deinitAudioBackend();
|
||||
|
||||
curExportChan = 0;
|
||||
|
||||
float* outBuf[DIV_MAX_OUTPUTS];
|
||||
float* outBufFinal;
|
||||
for (int i=0; i<exportOutputs; i++) {
|
||||
|
|
@ -258,6 +340,7 @@ void DivEngine::runExportThread() {
|
|||
|
||||
for (int i=0; i<chans; i++) {
|
||||
if (!exportChannelMask[i]) continue;
|
||||
|
||||
SNDFILE* sf;
|
||||
SF_INFO si;
|
||||
SFWrapper sfWrap;
|
||||
|
|
@ -338,6 +421,8 @@ void DivEngine::runExportThread() {
|
|||
}
|
||||
}
|
||||
|
||||
curExportChan++;
|
||||
|
||||
if (sfWrap.doClose()!=0) {
|
||||
logE("could not close audio file!");
|
||||
}
|
||||
|
|
@ -378,6 +463,7 @@ void DivEngine::runExportThread() {
|
|||
}
|
||||
logI("done!");
|
||||
exporting=false;
|
||||
curExportChan = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue