dev80 - increase song limits

up to 256 patterns
up to 256 orders
This commit is contained in:
tildearrow 2022-04-08 17:21:36 -05:00
parent ff0c1f427f
commit 9e0e8f3345
11 changed files with 54 additions and 22 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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;

View File

@ -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);
} }
}; };

View File

@ -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*));
} }

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);