dev80 - increase song limits
up to 256 patterns up to 256 orders
This commit is contained in:
parent
ff0c1f427f
commit
9e0e8f3345
|
@ -29,6 +29,7 @@ furthermore, an `or reserved` indicates this field is always present, but is res
|
||||||
|
|
||||||
the format versions are:
|
the format versions are:
|
||||||
|
|
||||||
|
- 80: Furnace dev80
|
||||||
- 79: Furnace dev79
|
- 79: Furnace dev79
|
||||||
- 78: Furnace dev78
|
- 78: Furnace dev78
|
||||||
- 77: Furnace dev77
|
- 77: Furnace dev77
|
||||||
|
@ -119,12 +120,17 @@ size | description
|
||||||
| - 60 is NTSC
|
| - 60 is NTSC
|
||||||
| - 50 is PAL
|
| - 50 is PAL
|
||||||
2 | pattern length
|
2 | pattern length
|
||||||
|
| - the limit is 256.
|
||||||
2 | orders length
|
2 | orders length
|
||||||
|
| - the limit is 256 (>=80) or 127 (<80).
|
||||||
1 | highlight A
|
1 | highlight A
|
||||||
1 | highlight B
|
1 | highlight B
|
||||||
2 | instrument count
|
2 | instrument count
|
||||||
|
| - the limit is 256.
|
||||||
2 | wavetable count
|
2 | wavetable count
|
||||||
|
| - the limit is 256.
|
||||||
2 | sample count
|
2 | sample count
|
||||||
|
| - the limit is 256.
|
||||||
4 | pattern count
|
4 | pattern count
|
||||||
32 | list of sound chips
|
32 | list of sound chips
|
||||||
| - possible soundchips:
|
| - possible soundchips:
|
||||||
|
@ -230,6 +236,7 @@ size | description
|
||||||
| - a table of bytes
|
| - a table of bytes
|
||||||
| - size=channels*ordLen
|
| - size=channels*ordLen
|
||||||
| - read orders then channels
|
| - read orders then channels
|
||||||
|
| - the maximum value of a cell is FF (>=80) or 7F (<80).
|
||||||
??? | effect columns
|
??? | effect columns
|
||||||
| - size=channels
|
| - size=channels
|
||||||
1?? | channel hide status
|
1?? | channel hide status
|
||||||
|
|
|
@ -1281,7 +1281,7 @@ void DivEngine::delInstrument(int index) {
|
||||||
song.ins.erase(song.ins.begin()+index);
|
song.ins.erase(song.ins.begin()+index);
|
||||||
song.insLen=song.ins.size();
|
song.insLen=song.ins.size();
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
for (int j=0; j<128; j++) {
|
for (int j=0; j<256; j++) {
|
||||||
if (song.pat[i].data[j]==NULL) continue;
|
if (song.pat[i].data[j]==NULL) continue;
|
||||||
for (int k=0; k<song.patLen; k++) {
|
for (int k=0; k<song.patLen; k++) {
|
||||||
if (song.pat[i].data[j]->data[k][2]>index) {
|
if (song.pat[i].data[j]->data[k][2]>index) {
|
||||||
|
@ -1556,7 +1556,7 @@ void DivEngine::delSample(int index) {
|
||||||
|
|
||||||
void DivEngine::addOrder(bool duplicate, bool where) {
|
void DivEngine::addOrder(bool duplicate, bool where) {
|
||||||
unsigned char order[DIV_MAX_CHANS];
|
unsigned char order[DIV_MAX_CHANS];
|
||||||
if (song.ordersLen>=0x7e) return;
|
if (song.ordersLen>=0xff) return;
|
||||||
BUSY_BEGIN_SOFT;
|
BUSY_BEGIN_SOFT;
|
||||||
if (duplicate) {
|
if (duplicate) {
|
||||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||||
|
@ -1569,7 +1569,7 @@ void DivEngine::addOrder(bool duplicate, bool where) {
|
||||||
for (int j=0; j<song.ordersLen; j++) {
|
for (int j=0; j<song.ordersLen; j++) {
|
||||||
used[song.orders.ord[i][j]]=true;
|
used[song.orders.ord[i][j]]=true;
|
||||||
}
|
}
|
||||||
order[i]=0x7e;
|
order[i]=0xff;
|
||||||
for (int j=0; j<256; j++) {
|
for (int j=0; j<256; j++) {
|
||||||
if (!used[j]) {
|
if (!used[j]) {
|
||||||
order[i]=j;
|
order[i]=j;
|
||||||
|
@ -1605,7 +1605,7 @@ void DivEngine::addOrder(bool duplicate, bool where) {
|
||||||
|
|
||||||
void DivEngine::deepCloneOrder(bool where) {
|
void DivEngine::deepCloneOrder(bool where) {
|
||||||
unsigned char order[DIV_MAX_CHANS];
|
unsigned char order[DIV_MAX_CHANS];
|
||||||
if (song.ordersLen>=0x7e) return;
|
if (song.ordersLen>=0xff) return;
|
||||||
warnings="";
|
warnings="";
|
||||||
BUSY_BEGIN_SOFT;
|
BUSY_BEGIN_SOFT;
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
|
@ -1613,7 +1613,7 @@ void DivEngine::deepCloneOrder(bool where) {
|
||||||
logD("channel %d\n",i);
|
logD("channel %d\n",i);
|
||||||
order[i]=song.orders.ord[i][curOrder];
|
order[i]=song.orders.ord[i][curOrder];
|
||||||
// find free slot
|
// find free slot
|
||||||
for (int j=0; j<128; j++) {
|
for (int j=0; j<256; j++) {
|
||||||
logD("finding free slot in %d...\n",j);
|
logD("finding free slot in %d...\n",j);
|
||||||
if (song.pat[i].data[j]==NULL) {
|
if (song.pat[i].data[j]==NULL) {
|
||||||
int origOrd=order[i];
|
int origOrd=order[i];
|
||||||
|
@ -1715,7 +1715,7 @@ void DivEngine::moveOrderDown() {
|
||||||
|
|
||||||
void DivEngine::exchangeIns(int one, int two) {
|
void DivEngine::exchangeIns(int one, int two) {
|
||||||
for (int i=0; i<chans; i++) {
|
for (int i=0; i<chans; i++) {
|
||||||
for (int j=0; j<128; j++) {
|
for (int j=0; j<256; j++) {
|
||||||
if (song.pat[i].data[j]==NULL) continue;
|
if (song.pat[i].data[j]==NULL) continue;
|
||||||
for (int k=0; k<song.patLen; k++) {
|
for (int k=0; k<song.patLen; k++) {
|
||||||
if (song.pat[i].data[j]->data[k][2]==one) {
|
if (song.pat[i].data[j]->data[k][2]==one) {
|
||||||
|
|
|
@ -42,8 +42,8 @@
|
||||||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||||
|
|
||||||
#define DIV_VERSION "dev79"
|
#define DIV_VERSION "dev80"
|
||||||
#define DIV_ENGINE_VERSION 79
|
#define DIV_ENGINE_VERSION 80
|
||||||
|
|
||||||
// for imports
|
// for imports
|
||||||
#define DIV_VERSION_MOD 0xff01
|
#define DIV_VERSION_MOD 0xff01
|
||||||
|
|
|
@ -959,7 +959,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
delete[] file;
|
delete[] file;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (ds.ordersLen>127) {
|
if (ds.ordersLen>256) {
|
||||||
logE("song is too long!\n");
|
logE("song is too long!\n");
|
||||||
lastError="song is too long!";
|
lastError="song is too long!";
|
||||||
delete[] file;
|
delete[] file;
|
||||||
|
@ -1407,6 +1407,8 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
int index=reader.readS();
|
int index=reader.readS();
|
||||||
reader.readI();
|
reader.readI();
|
||||||
|
|
||||||
|
logD("- %d, %d\n",chan,index);
|
||||||
|
|
||||||
if (chan<0 || chan>=tchans) {
|
if (chan<0 || chan>=tchans) {
|
||||||
logE("pattern channel out of range!\n",i);
|
logE("pattern channel out of range!\n",i);
|
||||||
lastError="pattern channel out of range!";
|
lastError="pattern channel out of range!";
|
||||||
|
@ -1414,7 +1416,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
delete[] file;
|
delete[] file;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (index<0 || index>127) {
|
if (index<0 || index>255) {
|
||||||
logE("pattern index out of range!\n",i);
|
logE("pattern index out of range!\n",i);
|
||||||
lastError="pattern index out of range!";
|
lastError="pattern index out of range!";
|
||||||
ds.unload();
|
ds.unload();
|
||||||
|
@ -1422,8 +1424,6 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
logD("- %d, %d\n",chan,index);
|
|
||||||
|
|
||||||
DivPattern* pat=ds.pat[chan].getPattern(index,true);
|
DivPattern* pat=ds.pat[chan].getPattern(index,true);
|
||||||
for (int j=0; j<ds.patLen; j++) {
|
for (int j=0; j<ds.patLen; j++) {
|
||||||
pat->data[j][0]=reader.readS();
|
pat->data[j][0]=reader.readS();
|
||||||
|
@ -2292,6 +2292,31 @@ SafeWriter* DivEngine::saveDMF(unsigned char version) {
|
||||||
lastError="this system is not possible on .dmf";
|
lastError="this system is not possible on .dmf";
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
// fail if values are out of range
|
||||||
|
if (song.ordersLen>127) {
|
||||||
|
logE("maximum .dmf song length is 127!\n");
|
||||||
|
lastError="maximum .dmf song length is 127";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (song.ins.size()>128) {
|
||||||
|
logE("maximum number of instruments in .dmf is 128!\n");
|
||||||
|
lastError="maximum number of instruments in .dmf is 128";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (song.wave.size()>64) {
|
||||||
|
logE("maximum number of wavetables in .dmf is 64!\n");
|
||||||
|
lastError="maximum number of wavetables in .dmf is 64";
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
for (int i=0; i<chans; i++) {
|
||||||
|
for (int j=0; j<song.ordersLen; j++) {
|
||||||
|
if (song.orders.ord[i][j]>0x7f) {
|
||||||
|
logE("order %d, %d is out of range (0-127)!\n",song.orders.ord[i][j]);
|
||||||
|
lastError=fmt::sprintf("order %d, %d is out of range (0-127)",song.orders.ord[i][j]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
saveLock.lock();
|
saveLock.lock();
|
||||||
warnings="";
|
warnings="";
|
||||||
song.version=version;
|
song.version=version;
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
#define _ORDERS_H
|
#define _ORDERS_H
|
||||||
|
|
||||||
struct DivOrders {
|
struct DivOrders {
|
||||||
unsigned char ord[DIV_MAX_CHANS][128];
|
unsigned char ord[DIV_MAX_CHANS][256];
|
||||||
|
|
||||||
DivOrders() {
|
DivOrders() {
|
||||||
memset(ord,0,DIV_MAX_CHANS*128);
|
memset(ord,0,DIV_MAX_CHANS*256);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ DivPattern* DivChannelData::getPattern(int index, bool create) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivChannelData::wipePatterns() {
|
void DivChannelData::wipePatterns() {
|
||||||
for (int i=0; i<128; i++) {
|
for (int i=0; i<256; i++) {
|
||||||
if (data[i]!=NULL) {
|
if (data[i]!=NULL) {
|
||||||
delete data[i];
|
delete data[i];
|
||||||
data[i]=NULL;
|
data[i]=NULL;
|
||||||
|
@ -131,5 +131,5 @@ SafeReader* DivPattern::compile(int len, int fxRows) {
|
||||||
|
|
||||||
DivChannelData::DivChannelData():
|
DivChannelData::DivChannelData():
|
||||||
effectRows(1) {
|
effectRows(1) {
|
||||||
memset(data,0,128*sizeof(void*));
|
memset(data,0,256*sizeof(void*));
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ struct DivChannelData {
|
||||||
// 3: volume
|
// 3: volume
|
||||||
// 4-5+: effect/effect value
|
// 4-5+: effect/effect value
|
||||||
// do NOT access directly unless you know what you're doing!
|
// do NOT access directly unless you know what you're doing!
|
||||||
DivPattern* data[128];
|
DivPattern* data[256];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get a pattern from this channel, or the empty pattern if not initialized.
|
* get a pattern from this channel, or the empty pattern if not initialized.
|
||||||
|
|
|
@ -1131,7 +1131,7 @@ void FurnaceGUI::keyDown(SDL_Event& ev) {
|
||||||
if (orderCursor>=0 && orderCursor<e->getTotalChannelCount()) {
|
if (orderCursor>=0 && orderCursor<e->getTotalChannelCount()) {
|
||||||
int curOrder=e->getOrder();
|
int curOrder=e->getOrder();
|
||||||
e->lockSave([this,curOrder,num]() {
|
e->lockSave([this,curOrder,num]() {
|
||||||
e->song.orders.ord[orderCursor][curOrder]=((e->song.orders.ord[orderCursor][curOrder]<<4)|num)&0x7f;
|
e->song.orders.ord[orderCursor][curOrder]=((e->song.orders.ord[orderCursor][curOrder]<<4)|num);
|
||||||
});
|
});
|
||||||
if (orderEditMode==2 || orderEditMode==3) {
|
if (orderEditMode==2 || orderEditMode==3) {
|
||||||
curNibble=!curNibble;
|
curNibble=!curNibble;
|
||||||
|
|
|
@ -952,7 +952,7 @@ class FurnaceGUI {
|
||||||
|
|
||||||
int oldOrdersLen;
|
int oldOrdersLen;
|
||||||
DivOrders oldOrders;
|
DivOrders oldOrders;
|
||||||
DivPattern* oldPat[128];
|
DivPattern* oldPat[DIV_MAX_CHANS];
|
||||||
std::deque<UndoStep> undoHist;
|
std::deque<UndoStep> undoHist;
|
||||||
std::deque<UndoStep> redoHist;
|
std::deque<UndoStep> redoHist;
|
||||||
|
|
||||||
|
|
|
@ -102,10 +102,10 @@ void FurnaceGUI::drawOrders() {
|
||||||
e->lockSave([this,i,j]() {
|
e->lockSave([this,i,j]() {
|
||||||
if (changeAllOrders) {
|
if (changeAllOrders) {
|
||||||
for (int k=0; k<e->getTotalChannelCount(); k++) {
|
for (int k=0; k<e->getTotalChannelCount(); k++) {
|
||||||
if (e->song.orders.ord[k][i]<0x7f) e->song.orders.ord[k][i]++;
|
if (e->song.orders.ord[k][i]<0xff) e->song.orders.ord[k][i]++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (e->song.orders.ord[j][i]<0x7f) e->song.orders.ord[j][i]++;
|
if (e->song.orders.ord[j][i]<0xff) e->song.orders.ord[j][i]++;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
e->walkSong(loopOrder,loopRow,loopEnd);
|
e->walkSong(loopOrder,loopRow,loopEnd);
|
||||||
|
|
|
@ -122,7 +122,7 @@ void FurnaceGUI::drawSongInfo() {
|
||||||
int ordLen=e->song.ordersLen;
|
int ordLen=e->song.ordersLen;
|
||||||
if (ImGui::InputInt("##OrdLength",&ordLen,1,3)) { MARK_MODIFIED
|
if (ImGui::InputInt("##OrdLength",&ordLen,1,3)) { MARK_MODIFIED
|
||||||
if (ordLen<1) ordLen=1;
|
if (ordLen<1) ordLen=1;
|
||||||
if (ordLen>127) ordLen=127;
|
if (ordLen>256) ordLen=256;
|
||||||
e->song.ordersLen=ordLen;
|
e->song.ordersLen=ordLen;
|
||||||
if (e->getOrder()>=ordLen) {
|
if (e->getOrder()>=ordLen) {
|
||||||
e->setOrder(ordLen-1);
|
e->setOrder(ordLen-1);
|
||||||
|
|
Loading…
Reference in New Issue