Merge branch 'master' of https://github.com/tildearrow/furnace into es5506_alt
* 'master' of https://github.com/tildearrow/furnace: (70 commits) whoops GUI: AY8930 credits GUI: fix inability to close subsongs BANK OPN: wire up ExtCh system fix build failure dev95 - multiple songs in a single file (READ) DO NOT USE - THIS FAILS - WORK IN PROGRESS enforce asset limits old .dmf loading improvements add AICA and YMZ ADPCM formats allocate ID for YMZ280B harden .fur file saver Fix AY VGM output, Fix presets preparations for UI improvements GUI: add more presets prepare for ExtCh OPN/OPNA GUI: clarify that lock layout doesn't work yet GUI: remember last state of order edit mode GUI: store edit/followOrders/followPattern state ... # Conflicts: # src/engine/fileOps.cpp # src/engine/platform/ym2610.cpp # src/engine/platform/ym2610b.cpp # src/engine/sample.cpp # src/engine/sample.h # src/engine/sysDef.cpp # src/gui/doAction.cpp # src/gui/sysConf.cpp
This commit is contained in:
commit
028adf2c8e
84 changed files with 7825 additions and 1146 deletions
|
|
@ -139,18 +139,18 @@ void DivEngine::walkSong(int& loopOrder, int& loopRow, int& loopEnd) {
|
|||
int nextRow=0;
|
||||
int effectVal=0;
|
||||
DivPattern* pat[DIV_MAX_CHANS];
|
||||
for (int i=0; i<song.ordersLen; i++) {
|
||||
for (int i=0; i<curSubSong->ordersLen; i++) {
|
||||
for (int j=0; j<chans; j++) {
|
||||
pat[j]=song.pat[j].getPattern(song.orders.ord[j][i],false);
|
||||
pat[j]=curPat[j].getPattern(curOrders->ord[j][i],false);
|
||||
}
|
||||
for (int j=nextRow; j<song.patLen; j++) {
|
||||
for (int j=nextRow; j<curSubSong->patLen; j++) {
|
||||
nextRow=0;
|
||||
for (int k=0; k<chans; k++) {
|
||||
for (int l=0; l<song.pat[k].effectCols; l++) {
|
||||
for (int l=0; l<curPat[k].effectCols; l++) {
|
||||
effectVal=pat[k]->data[j][5+(l<<1)];
|
||||
if (effectVal<0) effectVal=0;
|
||||
if (pat[k]->data[j][4+(l<<1)]==0x0d) {
|
||||
if (nextOrder==-1 && (i<song.ordersLen-1 || !song.ignoreJumpAtEnd)) {
|
||||
if (nextOrder==-1 && (i<curSubSong->ordersLen-1 || !song.ignoreJumpAtEnd)) {
|
||||
nextOrder=i+1;
|
||||
nextRow=effectVal;
|
||||
}
|
||||
|
|
@ -491,6 +491,86 @@ void DivEngine::notifyWaveChange(int wave) {
|
|||
BUSY_END;
|
||||
}
|
||||
|
||||
int DivEngine::loadSampleROM(String path, ssize_t expectedSize, unsigned char*& ret) {
|
||||
ret = NULL;
|
||||
if (path.empty()) {
|
||||
return 0;
|
||||
}
|
||||
logI("loading ROM %s...",path);
|
||||
FILE* f=ps_fopen(path.c_str(),"rb");
|
||||
if (f==NULL) {
|
||||
logE("error: %s",strerror(errno));
|
||||
lastError=strerror(errno);
|
||||
return -1;
|
||||
}
|
||||
if (fseek(f,0,SEEK_END)<0) {
|
||||
logE("size error: %s",strerror(errno));
|
||||
lastError=fmt::sprintf("on seek: %s",strerror(errno));
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
ssize_t len=ftell(f);
|
||||
if (len==(SIZE_MAX>>1)) {
|
||||
logE("could not get file length: %s",strerror(errno));
|
||||
lastError=fmt::sprintf("on pre tell: %s",strerror(errno));
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
if (len<1) {
|
||||
if (len==0) {
|
||||
logE("that file is empty!");
|
||||
lastError="file is empty";
|
||||
} else {
|
||||
logE("tell error: %s",strerror(errno));
|
||||
lastError=fmt::sprintf("on tell: %s",strerror(errno));
|
||||
}
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
if (len!=expectedSize) {
|
||||
logE("ROM size mismatch, expected: %d bytes, was: %d bytes", expectedSize, len);
|
||||
lastError=fmt::sprintf("ROM size mismatch, expected: %d bytes, was: %d", expectedSize, len);
|
||||
return -1;
|
||||
}
|
||||
if (fseek(f,0,SEEK_SET)<0) {
|
||||
logE("size error: %s",strerror(errno));
|
||||
lastError=fmt::sprintf("on get size: %s",strerror(errno));
|
||||
fclose(f);
|
||||
return -1;
|
||||
}
|
||||
unsigned char* file=new unsigned char[len];
|
||||
if (fread(file,1,(size_t)len,f)!=(size_t)len) {
|
||||
logE("read error: %s",strerror(errno));
|
||||
lastError=fmt::sprintf("on read: %s",strerror(errno));
|
||||
fclose(f);
|
||||
delete[] file;
|
||||
return -1;
|
||||
}
|
||||
fclose(f);
|
||||
ret = file;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DivEngine::loadSampleROMs() {
|
||||
if (yrw801ROM!=NULL) {
|
||||
delete[] yrw801ROM;
|
||||
yrw801ROM=NULL;
|
||||
}
|
||||
if (tg100ROM!=NULL) {
|
||||
delete[] tg100ROM;
|
||||
tg100ROM=NULL;
|
||||
}
|
||||
if (mu5ROM!=NULL) {
|
||||
delete[] mu5ROM;
|
||||
mu5ROM=NULL;
|
||||
}
|
||||
int error = 0;
|
||||
error += loadSampleROM(getConfString("yrw801Path",""), 0x200000, yrw801ROM);
|
||||
error += loadSampleROM(getConfString("tg100Path",""), 0x200000, tg100ROM);
|
||||
error += loadSampleROM(getConfString("mu5Path",""), 0x200000, mu5ROM);
|
||||
return error;
|
||||
}
|
||||
|
||||
void DivEngine::renderSamplesP() {
|
||||
BUSY_BEGIN;
|
||||
renderSamples();
|
||||
|
|
@ -616,6 +696,7 @@ void DivEngine::createNew(const int* description) {
|
|||
saveLock.lock();
|
||||
song.unload();
|
||||
song=DivSong();
|
||||
changeSong(0);
|
||||
if (description!=NULL) {
|
||||
initSongWithDesc(description);
|
||||
}
|
||||
|
|
@ -637,45 +718,55 @@ void DivEngine::swapChannels(int src, int dest) {
|
|||
}
|
||||
|
||||
for (int i=0; i<256; i++) {
|
||||
song.orders.ord[dest][i]^=song.orders.ord[src][i];
|
||||
song.orders.ord[src][i]^=song.orders.ord[dest][i];
|
||||
song.orders.ord[dest][i]^=song.orders.ord[src][i];
|
||||
curOrders->ord[dest][i]^=curOrders->ord[src][i];
|
||||
curOrders->ord[src][i]^=curOrders->ord[dest][i];
|
||||
curOrders->ord[dest][i]^=curOrders->ord[src][i];
|
||||
|
||||
DivPattern* prev=song.pat[src].data[i];
|
||||
song.pat[src].data[i]=song.pat[dest].data[i];
|
||||
song.pat[dest].data[i]=prev;
|
||||
DivPattern* prev=curPat[src].data[i];
|
||||
curPat[src].data[i]=curPat[dest].data[i];
|
||||
curPat[dest].data[i]=prev;
|
||||
}
|
||||
|
||||
song.pat[src].effectCols^=song.pat[dest].effectCols;
|
||||
song.pat[dest].effectCols^=song.pat[src].effectCols;
|
||||
song.pat[src].effectCols^=song.pat[dest].effectCols;
|
||||
curPat[src].effectCols^=curPat[dest].effectCols;
|
||||
curPat[dest].effectCols^=curPat[src].effectCols;
|
||||
curPat[src].effectCols^=curPat[dest].effectCols;
|
||||
|
||||
String prevChanName=song.chanName[src];
|
||||
String prevChanShortName=song.chanShortName[src];
|
||||
bool prevChanShow=song.chanShow[src];
|
||||
bool prevChanCollapse=song.chanCollapse[src];
|
||||
String prevChanName=curSubSong->chanName[src];
|
||||
String prevChanShortName=curSubSong->chanShortName[src];
|
||||
bool prevChanShow=curSubSong->chanShow[src];
|
||||
bool prevChanCollapse=curSubSong->chanCollapse[src];
|
||||
|
||||
song.chanName[src]=song.chanName[dest];
|
||||
song.chanShortName[src]=song.chanShortName[dest];
|
||||
song.chanShow[src]=song.chanShow[dest];
|
||||
song.chanCollapse[src]=song.chanCollapse[dest];
|
||||
song.chanName[dest]=prevChanName;
|
||||
song.chanShortName[dest]=prevChanShortName;
|
||||
song.chanShow[dest]=prevChanShow;
|
||||
song.chanCollapse[dest]=prevChanCollapse;
|
||||
curSubSong->chanName[src]=curSubSong->chanName[dest];
|
||||
curSubSong->chanShortName[src]=curSubSong->chanShortName[dest];
|
||||
curSubSong->chanShow[src]=curSubSong->chanShow[dest];
|
||||
curSubSong->chanCollapse[src]=curSubSong->chanCollapse[dest];
|
||||
curSubSong->chanName[dest]=prevChanName;
|
||||
curSubSong->chanShortName[dest]=prevChanShortName;
|
||||
curSubSong->chanShow[dest]=prevChanShow;
|
||||
curSubSong->chanCollapse[dest]=prevChanCollapse;
|
||||
}
|
||||
|
||||
void DivEngine::stompChannel(int ch) {
|
||||
logV("stomping channel %d",ch);
|
||||
for (int i=0; i<256; i++) {
|
||||
song.orders.ord[ch][i]=0;
|
||||
curOrders->ord[ch][i]=0;
|
||||
}
|
||||
song.pat[ch].wipePatterns();
|
||||
song.pat[ch].effectCols=1;
|
||||
song.chanName[ch]="";
|
||||
song.chanShortName[ch]="";
|
||||
song.chanShow[ch]=true;
|
||||
song.chanCollapse[ch]=false;
|
||||
curPat[ch].wipePatterns();
|
||||
curPat[ch].effectCols=1;
|
||||
curSubSong->chanName[ch]="";
|
||||
curSubSong->chanShortName[ch]="";
|
||||
curSubSong->chanShow[ch]=true;
|
||||
curSubSong->chanCollapse[ch]=false;
|
||||
}
|
||||
|
||||
void DivEngine::changeSong(size_t songIndex) {
|
||||
if (songIndex>=song.subsong.size()) return;
|
||||
curSubSong=song.subsong[songIndex];
|
||||
curPat=song.subsong[songIndex]->pat;
|
||||
curOrders=&song.subsong[songIndex]->orders;
|
||||
curSubSongIndex=songIndex;
|
||||
curOrder=0;
|
||||
curRow=0;
|
||||
}
|
||||
|
||||
void DivEngine::swapChannelsP(int src, int dest) {
|
||||
|
|
@ -688,6 +779,41 @@ void DivEngine::swapChannelsP(int src, int dest) {
|
|||
BUSY_END;
|
||||
}
|
||||
|
||||
void DivEngine::changeSongP(size_t index) {
|
||||
if (index>=song.subsong.size()) return;
|
||||
if (index==curSubSongIndex) return;
|
||||
stop();
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
changeSong(index);
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
}
|
||||
|
||||
int DivEngine::addSubSong() {
|
||||
if (song.subsong.size()>=127) return -1;
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
song.subsong.push_back(new DivSubSong);
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
return song.subsong.size()-1;
|
||||
}
|
||||
|
||||
bool DivEngine::removeSubSong(int index) {
|
||||
if (song.subsong.size()<=1) return false;
|
||||
stop();
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
song.subsong[index]->clearData();
|
||||
delete song.subsong[index];
|
||||
song.subsong.erase(song.subsong.begin()+index);
|
||||
changeSong(0);
|
||||
saveLock.unlock();
|
||||
BUSY_END;
|
||||
return true;
|
||||
}
|
||||
|
||||
void DivEngine::changeSystem(int index, DivSystem which, bool preserveOrder) {
|
||||
int chanCount=chans;
|
||||
quitDispatch();
|
||||
|
|
@ -760,6 +886,7 @@ bool DivEngine::addSystem(DivSystem which) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// TODO: maybe issue with subsongs?
|
||||
bool DivEngine::removeSystem(int index, bool preserveOrder) {
|
||||
if (song.systemLen<=1) {
|
||||
lastError="cannot remove the last one";
|
||||
|
|
@ -1245,15 +1372,15 @@ void DivEngine::reset() {
|
|||
}
|
||||
extValue=0;
|
||||
extValuePresent=0;
|
||||
speed1=song.speed1;
|
||||
speed2=song.speed2;
|
||||
speed1=curSubSong->speed1;
|
||||
speed2=curSubSong->speed2;
|
||||
firstTick=false;
|
||||
nextSpeed=speed1;
|
||||
divider=60;
|
||||
if (song.customTempo) {
|
||||
divider=song.hz;
|
||||
if (curSubSong->customTempo) {
|
||||
divider=curSubSong->hz;
|
||||
} else {
|
||||
if (song.pal) {
|
||||
if (curSubSong->pal) {
|
||||
divider=60;
|
||||
} else {
|
||||
divider=50;
|
||||
|
|
@ -1408,6 +1535,10 @@ int DivEngine::getRow() {
|
|||
return curRow;
|
||||
}
|
||||
|
||||
size_t DivEngine::getCurrentSubSong() {
|
||||
return curSubSongIndex;
|
||||
}
|
||||
|
||||
unsigned char DivEngine::getSpeed1() {
|
||||
return speed1;
|
||||
}
|
||||
|
|
@ -1417,9 +1548,9 @@ unsigned char DivEngine::getSpeed2() {
|
|||
}
|
||||
|
||||
float DivEngine::getHz() {
|
||||
if (song.customTempo) {
|
||||
return song.hz;
|
||||
} else if (song.pal) {
|
||||
if (curSubSong->customTempo) {
|
||||
return curSubSong->hz;
|
||||
} else if (curSubSong->pal) {
|
||||
return 60.0;
|
||||
} else {
|
||||
return 50.0;
|
||||
|
|
@ -1526,6 +1657,7 @@ void DivEngine::unmuteAll() {
|
|||
}
|
||||
|
||||
int DivEngine::addInstrument(int refChan) {
|
||||
if (song.ins.size()>=256) return -1;
|
||||
BUSY_BEGIN;
|
||||
DivInstrument* ins=new DivInstrument;
|
||||
int insCount=(int)song.ins.size();
|
||||
|
|
@ -1544,7 +1676,9 @@ int DivEngine::addInstrument(int refChan) {
|
|||
*ins=song.nullInsQSound;
|
||||
}
|
||||
ins->name=fmt::sprintf("Instrument %d",insCount);
|
||||
ins->type=prefType;
|
||||
if (prefType!=DIV_INS_NULL) {
|
||||
ins->type=prefType;
|
||||
}
|
||||
saveLock.lock();
|
||||
song.ins.push_back(ins);
|
||||
song.insLen=insCount+1;
|
||||
|
|
@ -1554,6 +1688,10 @@ int DivEngine::addInstrument(int refChan) {
|
|||
}
|
||||
|
||||
int DivEngine::addInstrumentPtr(DivInstrument* which) {
|
||||
if (song.ins.size()>=256) {
|
||||
delete which;
|
||||
return -1;
|
||||
}
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
song.ins.push_back(which);
|
||||
|
|
@ -1584,10 +1722,10 @@ void DivEngine::delInstrument(int index) {
|
|||
song.insLen=song.ins.size();
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (int j=0; j<256; j++) {
|
||||
if (song.pat[i].data[j]==NULL) continue;
|
||||
for (int k=0; k<song.patLen; k++) {
|
||||
if (song.pat[i].data[j]->data[k][2]>index) {
|
||||
song.pat[i].data[j]->data[k][2]--;
|
||||
if (curPat[i].data[j]==NULL) continue;
|
||||
for (int k=0; k<curSubSong->patLen; k++) {
|
||||
if (curPat[i].data[j]->data[k][2]>index) {
|
||||
curPat[i].data[j]->data[k][2]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1598,6 +1736,7 @@ void DivEngine::delInstrument(int index) {
|
|||
}
|
||||
|
||||
int DivEngine::addWave() {
|
||||
if (song.wave.size()>=256) return -1;
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
DivWavetable* wave=new DivWavetable;
|
||||
|
|
@ -1610,37 +1749,48 @@ int DivEngine::addWave() {
|
|||
}
|
||||
|
||||
bool DivEngine::addWaveFromFile(const char* path) {
|
||||
if (song.wave.size()>=256) {
|
||||
lastError="too many wavetables!";
|
||||
return false;
|
||||
}
|
||||
FILE* f=ps_fopen(path,"rb");
|
||||
if (f==NULL) {
|
||||
lastError=fmt::sprintf("%s",strerror(errno));
|
||||
return false;
|
||||
}
|
||||
unsigned char* buf;
|
||||
ssize_t len;
|
||||
if (fseek(f,0,SEEK_END)!=0) {
|
||||
fclose(f);
|
||||
lastError=fmt::sprintf("could not seek to end: %s",strerror(errno));
|
||||
return false;
|
||||
}
|
||||
len=ftell(f);
|
||||
if (len<0) {
|
||||
fclose(f);
|
||||
lastError=fmt::sprintf("could not determine file size: %s",strerror(errno));
|
||||
return false;
|
||||
}
|
||||
if (len==(SIZE_MAX>>1)) {
|
||||
fclose(f);
|
||||
lastError="file size is invalid!";
|
||||
return false;
|
||||
}
|
||||
if (len==0) {
|
||||
fclose(f);
|
||||
lastError="file is empty";
|
||||
return false;
|
||||
}
|
||||
if (fseek(f,0,SEEK_SET)!=0) {
|
||||
fclose(f);
|
||||
lastError=fmt::sprintf("could not seek to beginning: %s",strerror(errno));
|
||||
return false;
|
||||
}
|
||||
buf=new unsigned char[len];
|
||||
if (fread(buf,1,len,f)!=(size_t)len) {
|
||||
logW("did not read entire wavetable file buffer!");
|
||||
delete[] buf;
|
||||
lastError=fmt::sprintf("could not read entire file: %s",strerror(errno));
|
||||
return false;
|
||||
}
|
||||
fclose(f);
|
||||
|
|
@ -1720,6 +1870,7 @@ bool DivEngine::addWaveFromFile(const char* path) {
|
|||
} catch (EndOfFileException& e) {
|
||||
delete wave;
|
||||
delete[] buf;
|
||||
lastError="premature end of file";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1746,6 +1897,7 @@ void DivEngine::delWave(int index) {
|
|||
}
|
||||
|
||||
int DivEngine::addSample() {
|
||||
if (song.sample.size()>=256) return -1;
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
DivSample* sample=new DivSample;
|
||||
|
|
@ -1760,6 +1912,10 @@ int DivEngine::addSample() {
|
|||
}
|
||||
|
||||
int DivEngine::addSampleFromFile(const char* path) {
|
||||
if (song.sample.size()>=256) {
|
||||
lastError="too many samples!";
|
||||
return -1;
|
||||
}
|
||||
BUSY_BEGIN;
|
||||
warnings="";
|
||||
|
||||
|
|
@ -1957,18 +2113,18 @@ void DivEngine::delSample(int index) {
|
|||
|
||||
void DivEngine::addOrder(bool duplicate, bool where) {
|
||||
unsigned char order[DIV_MAX_CHANS];
|
||||
if (song.ordersLen>=0xff) return;
|
||||
if (curSubSong->ordersLen>=0xff) return;
|
||||
BUSY_BEGIN_SOFT;
|
||||
if (duplicate) {
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
order[i]=song.orders.ord[i][curOrder];
|
||||
order[i]=curOrders->ord[i][curOrder];
|
||||
}
|
||||
} else {
|
||||
bool used[256];
|
||||
for (int i=0; i<chans; i++) {
|
||||
memset(used,0,sizeof(bool)*256);
|
||||
for (int j=0; j<song.ordersLen; j++) {
|
||||
used[song.orders.ord[i][j]]=true;
|
||||
for (int j=0; j<curSubSong->ordersLen; j++) {
|
||||
used[curOrders->ord[i][j]]=true;
|
||||
}
|
||||
order[i]=0xff;
|
||||
for (int j=0; j<256; j++) {
|
||||
|
|
@ -1982,19 +2138,19 @@ void DivEngine::addOrder(bool duplicate, bool where) {
|
|||
if (where) { // at the end
|
||||
saveLock.lock();
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
song.orders.ord[i][song.ordersLen]=order[i];
|
||||
curOrders->ord[i][curSubSong->ordersLen]=order[i];
|
||||
}
|
||||
song.ordersLen++;
|
||||
curSubSong->ordersLen++;
|
||||
saveLock.unlock();
|
||||
} else { // after current order
|
||||
saveLock.lock();
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
for (int j=song.ordersLen; j>curOrder; j--) {
|
||||
song.orders.ord[i][j]=song.orders.ord[i][j-1];
|
||||
for (int j=curSubSong->ordersLen; j>curOrder; j--) {
|
||||
curOrders->ord[i][j]=curOrders->ord[i][j-1];
|
||||
}
|
||||
song.orders.ord[i][curOrder+1]=order[i];
|
||||
curOrders->ord[i][curOrder+1]=order[i];
|
||||
}
|
||||
song.ordersLen++;
|
||||
curSubSong->ordersLen++;
|
||||
saveLock.unlock();
|
||||
curOrder++;
|
||||
if (playing && !freelance) {
|
||||
|
|
@ -2006,21 +2162,21 @@ void DivEngine::addOrder(bool duplicate, bool where) {
|
|||
|
||||
void DivEngine::deepCloneOrder(bool where) {
|
||||
unsigned char order[DIV_MAX_CHANS];
|
||||
if (song.ordersLen>=0xff) return;
|
||||
if (curSubSong->ordersLen>=0xff) return;
|
||||
warnings="";
|
||||
BUSY_BEGIN_SOFT;
|
||||
for (int i=0; i<chans; i++) {
|
||||
bool didNotFind=true;
|
||||
logD("channel %d",i);
|
||||
order[i]=song.orders.ord[i][curOrder];
|
||||
order[i]=curOrders->ord[i][curOrder];
|
||||
// find free slot
|
||||
for (int j=0; j<256; j++) {
|
||||
logD("finding free slot in %d...",j);
|
||||
if (song.pat[i].data[j]==NULL) {
|
||||
if (curPat[i].data[j]==NULL) {
|
||||
int origOrd=order[i];
|
||||
order[i]=j;
|
||||
DivPattern* oldPat=song.pat[i].getPattern(origOrd,false);
|
||||
DivPattern* pat=song.pat[i].getPattern(j,true);
|
||||
DivPattern* oldPat=curPat[i].getPattern(origOrd,false);
|
||||
DivPattern* pat=curPat[i].getPattern(j,true);
|
||||
memcpy(pat->data,oldPat->data,256*32*sizeof(short));
|
||||
logD("found at %d",j);
|
||||
didNotFind=false;
|
||||
|
|
@ -2034,19 +2190,19 @@ void DivEngine::deepCloneOrder(bool where) {
|
|||
if (where) { // at the end
|
||||
saveLock.lock();
|
||||
for (int i=0; i<chans; i++) {
|
||||
song.orders.ord[i][song.ordersLen]=order[i];
|
||||
curOrders->ord[i][curSubSong->ordersLen]=order[i];
|
||||
}
|
||||
song.ordersLen++;
|
||||
curSubSong->ordersLen++;
|
||||
saveLock.unlock();
|
||||
} else { // after current order
|
||||
saveLock.lock();
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (int j=song.ordersLen; j>curOrder; j--) {
|
||||
song.orders.ord[i][j]=song.orders.ord[i][j-1];
|
||||
for (int j=curSubSong->ordersLen; j>curOrder; j--) {
|
||||
curOrders->ord[i][j]=curOrders->ord[i][j-1];
|
||||
}
|
||||
song.orders.ord[i][curOrder+1]=order[i];
|
||||
curOrders->ord[i][curOrder+1]=order[i];
|
||||
}
|
||||
song.ordersLen++;
|
||||
curSubSong->ordersLen++;
|
||||
saveLock.unlock();
|
||||
curOrder++;
|
||||
if (playing && !freelance) {
|
||||
|
|
@ -2057,17 +2213,17 @@ void DivEngine::deepCloneOrder(bool where) {
|
|||
}
|
||||
|
||||
void DivEngine::deleteOrder() {
|
||||
if (song.ordersLen<=1) return;
|
||||
if (curSubSong->ordersLen<=1) return;
|
||||
BUSY_BEGIN_SOFT;
|
||||
saveLock.lock();
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
for (int j=curOrder; j<song.ordersLen; j++) {
|
||||
song.orders.ord[i][j]=song.orders.ord[i][j+1];
|
||||
for (int j=curOrder; j<curSubSong->ordersLen; j++) {
|
||||
curOrders->ord[i][j]=curOrders->ord[i][j+1];
|
||||
}
|
||||
}
|
||||
song.ordersLen--;
|
||||
curSubSong->ordersLen--;
|
||||
saveLock.unlock();
|
||||
if (curOrder>=song.ordersLen) curOrder=song.ordersLen-1;
|
||||
if (curOrder>=curSubSong->ordersLen) curOrder=curSubSong->ordersLen-1;
|
||||
if (playing && !freelance) {
|
||||
playSub(false);
|
||||
}
|
||||
|
|
@ -2082,9 +2238,9 @@ void DivEngine::moveOrderUp() {
|
|||
}
|
||||
saveLock.lock();
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
song.orders.ord[i][curOrder]^=song.orders.ord[i][curOrder-1];
|
||||
song.orders.ord[i][curOrder-1]^=song.orders.ord[i][curOrder];
|
||||
song.orders.ord[i][curOrder]^=song.orders.ord[i][curOrder-1];
|
||||
curOrders->ord[i][curOrder]^=curOrders->ord[i][curOrder-1];
|
||||
curOrders->ord[i][curOrder-1]^=curOrders->ord[i][curOrder];
|
||||
curOrders->ord[i][curOrder]^=curOrders->ord[i][curOrder-1];
|
||||
}
|
||||
saveLock.unlock();
|
||||
curOrder--;
|
||||
|
|
@ -2096,15 +2252,15 @@ void DivEngine::moveOrderUp() {
|
|||
|
||||
void DivEngine::moveOrderDown() {
|
||||
BUSY_BEGIN_SOFT;
|
||||
if (curOrder>=song.ordersLen-1) {
|
||||
if (curOrder>=curSubSong->ordersLen-1) {
|
||||
BUSY_END;
|
||||
return;
|
||||
}
|
||||
saveLock.lock();
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
song.orders.ord[i][curOrder]^=song.orders.ord[i][curOrder+1];
|
||||
song.orders.ord[i][curOrder+1]^=song.orders.ord[i][curOrder];
|
||||
song.orders.ord[i][curOrder]^=song.orders.ord[i][curOrder+1];
|
||||
curOrders->ord[i][curOrder]^=curOrders->ord[i][curOrder+1];
|
||||
curOrders->ord[i][curOrder+1]^=curOrders->ord[i][curOrder];
|
||||
curOrders->ord[i][curOrder]^=curOrders->ord[i][curOrder+1];
|
||||
}
|
||||
saveLock.unlock();
|
||||
curOrder++;
|
||||
|
|
@ -2117,12 +2273,12 @@ void DivEngine::moveOrderDown() {
|
|||
void DivEngine::exchangeIns(int one, int two) {
|
||||
for (int i=0; i<chans; i++) {
|
||||
for (int j=0; j<256; j++) {
|
||||
if (song.pat[i].data[j]==NULL) continue;
|
||||
for (int k=0; k<song.patLen; k++) {
|
||||
if (song.pat[i].data[j]->data[k][2]==one) {
|
||||
song.pat[i].data[j]->data[k][2]=two;
|
||||
} else if (song.pat[i].data[j]->data[k][2]==two) {
|
||||
song.pat[i].data[j]->data[k][2]=one;
|
||||
if (curPat[i].data[j]==NULL) continue;
|
||||
for (int k=0; k<curSubSong->patLen; k++) {
|
||||
if (curPat[i].data[j]->data[k][2]==one) {
|
||||
curPat[i].data[j]->data[k][2]=two;
|
||||
} else if (curPat[i].data[j]->data[k][2]==two) {
|
||||
curPat[i].data[j]->data[k][2]=one;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2244,9 +2400,9 @@ void DivEngine::autoNoteOn(int ch, int ins, int note, int vol) {
|
|||
|
||||
// 1. check which channels are viable for this instrument
|
||||
DivInstrument* insInst=getIns(ins);
|
||||
if (getPreferInsType(finalChan)!=insInst->type && getPreferInsSecondType(finalChan)!=insInst->type) notInViableChannel=true;
|
||||
if (getPreferInsType(finalChan)!=insInst->type && getPreferInsSecondType(finalChan)!=insInst->type && getPreferInsType(finalChan)!=DIV_INS_NULL) notInViableChannel=true;
|
||||
for (int i=0; i<chans; i++) {
|
||||
if (ins==-1 || ins>=song.insLen || getPreferInsType(i)==insInst->type || getPreferInsSecondType(i)==insInst->type) {
|
||||
if (ins==-1 || ins>=song.insLen || getPreferInsType(i)==insInst->type || (getPreferInsType(i)==DIV_INS_NULL && finalChanType==DIV_CH_NOISE) || getPreferInsSecondType(i)==insInst->type) {
|
||||
if (insInst->type==DIV_INS_OPL) {
|
||||
if (insInst->fm.ops==2 || getChannelType(i)==DIV_CH_OP) {
|
||||
isViable[i]=true;
|
||||
|
|
@ -2326,7 +2482,7 @@ void DivEngine::autoNoteOffAll() {
|
|||
void DivEngine::setOrder(unsigned char order) {
|
||||
BUSY_BEGIN_SOFT;
|
||||
curOrder=order;
|
||||
if (order>=song.ordersLen) curOrder=0;
|
||||
if (order>=curSubSong->ordersLen) curOrder=0;
|
||||
if (playing && !freelance) {
|
||||
playSub(false);
|
||||
}
|
||||
|
|
@ -2349,15 +2505,15 @@ void DivEngine::setSysFlags(int system, unsigned int flags, bool restart) {
|
|||
void DivEngine::setSongRate(float hz, bool pal) {
|
||||
BUSY_BEGIN;
|
||||
saveLock.lock();
|
||||
song.pal=!pal;
|
||||
song.hz=hz;
|
||||
curSubSong->pal=!pal;
|
||||
curSubSong->hz=hz;
|
||||
// what?
|
||||
song.customTempo=true;
|
||||
curSubSong->customTempo=true;
|
||||
divider=60;
|
||||
if (song.customTempo) {
|
||||
divider=song.hz;
|
||||
if (curSubSong->customTempo) {
|
||||
divider=curSubSong->hz;
|
||||
} else {
|
||||
if (song.pal) {
|
||||
if (curSubSong->pal) {
|
||||
divider=60;
|
||||
} else {
|
||||
divider=50;
|
||||
|
|
@ -2722,6 +2878,8 @@ bool DivEngine::init() {
|
|||
|
||||
loadConf();
|
||||
|
||||
loadSampleROMs();
|
||||
|
||||
// set default system preset
|
||||
if (!hasLoadedSomething) {
|
||||
logD("setting default preset");
|
||||
|
|
@ -2795,5 +2953,9 @@ bool DivEngine::quit() {
|
|||
active=false;
|
||||
delete[] oscBuf[0];
|
||||
delete[] oscBuf[1];
|
||||
if (yrw801ROM!=NULL) delete[] yrw801ROM;
|
||||
if (tg100ROM!=NULL) delete[] tg100ROM;
|
||||
if (mu5ROM!=NULL) delete[] mu5ROM;
|
||||
song.unload();
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue