diff --git a/papers/export-tech.md b/papers/export-tech.md index 506c97b00..c8882b601 100644 --- a/papers/export-tech.md +++ b/papers/export-tech.md @@ -109,7 +109,7 @@ hex | description f3 | loop (negative offset and count follow... both are 8-bit) f4 | UNUSED - call symbol (32-bit index follows; only used internally) f5 | call sub-block (32-bit address follows) - f6 | UNUSED + f6 | note off + wait one tick f7 | full command (command and data follows) f8 | call sub-block (16-bit address follows) f9 | return from sub-block diff --git a/src/engine/cmdStream.cpp b/src/engine/cmdStream.cpp index f790d6d1a..d9a056177 100644 --- a/src/engine/cmdStream.cpp +++ b/src/engine/cmdStream.cpp @@ -210,6 +210,11 @@ bool DivCSPlayer::tick() { } break; } + case 0xf6: // note off + wait 1 + e->dispatchCmd(DivCommand(DIV_CMD_NOTE_OFF,i)); + chan[i].waitTicks=1; + chan[i].lastWaitLen=chan[i].waitTicks; + break; case 0xf7: command=stream.readC(); break; diff --git a/src/engine/cmdStream.h b/src/engine/cmdStream.h index 047bf1c74..6bf7914a2 100644 --- a/src/engine/cmdStream.h +++ b/src/engine/cmdStream.h @@ -113,10 +113,13 @@ class DivCSPlayer { struct DivCSProgress { int stage, count, total; + int optCurrent, optTotal; DivCSProgress(): stage(0), count(0), - total(0) {} + total(0), + optCurrent(0), + optTotal(0) {} }; struct DivCSOptions { diff --git a/src/engine/cmdStreamOps.cpp b/src/engine/cmdStreamOps.cpp index 39c9acb9d..18e2cf157 100644 --- a/src/engine/cmdStreamOps.cpp +++ b/src/engine/cmdStreamOps.cpp @@ -836,8 +836,6 @@ struct MatchBenefit { #define MIN_MATCH_SIZE 32 -// TODO: -// - see if we can optimize even more SafeWriter* findSubBlocks(SafeWriter* stream, std::vector& subBlocks, unsigned char* speedDial, DivCSProgress* progress) { unsigned char* buf=stream->getFinalBuf(); size_t matchSize=MIN_MATCH_SIZE; @@ -869,6 +867,11 @@ SafeWriter* findSubBlocks(SafeWriter* stream, std::vector& subBlock logD("%d candidates",(int)matches.size()); logD("%d origs",(int)origs.size()); + if (progress!=NULL) { + if ((int)matches.size()>progress->optTotal) progress->optTotal=matches.size(); + progress->optCurrent=matches.size(); + } + // quit if there isn't anything if (matches.empty()) return stream; @@ -1446,7 +1449,6 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options sortPos++; } - // condense delays for (int h=0; hgetFinalBuf(); @@ -1500,13 +1502,34 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options } } - // PASS 3: remove nop's + // PASS 3: note off + one-tick wait + // optimize one-tick gaps sometimes used in songs + for (int h=0; hgetFinalBuf(); + if (chanStream[h]->size()<8) continue; + for (size_t i=0; isize()-8; i+=8) { + // find note off + if (buf[i]==0xb5) { + // check for contiguous wait 1 + if (buf[i+8]==0xfe) { + // turn it into 0xf6 (note off + wait 1) and change the next one to nop + buf[i]=0xf6; + buf[i+8]=0xf1; + + // skip the next instruction + i+=8; + } + } + } + } + + // PASS 4: remove nop's // this includes modifying call addresses to compensate for (int h=0; htell(); logI("- %d: off %x size %ld",i,chanStreamOff[i],chanStream[i]->size()); @@ -1516,7 +1539,7 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options delete chanStream[i]; } - // PASS 5: find sub-blocks and isolate them + // PASS 6: find sub-blocks and isolate them if (!options.noSubBlock) { std::vector subBlocks; size_t beforeSize=globalStream->size(); @@ -1579,13 +1602,13 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options assert(!(globalStream->size()&7)); } - // PASS 6: pack stream + // PASS 7: pack stream globalStream=packStream(globalStream,sortedCmd); - // PASS 7: remove nop's which may be produced by 32-bit call conversion + // PASS 8: remove nop's which may be produced by 32-bit call conversion globalStream=stripNopsPacked(globalStream,sortedCmd); - // PASS 8: find new offsets + // PASS 9: find new offsets { unsigned char* buf=globalStream->getFinalBuf(); for (size_t i=0; isize();) { diff --git a/src/gui/csPlayer.cpp b/src/gui/csPlayer.cpp index 18922b079..66a17702a 100644 --- a/src/gui/csPlayer.cpp +++ b/src/gui/csPlayer.cpp @@ -142,6 +142,9 @@ String disasmCmd(unsigned char* buf, size_t bufLen, unsigned int addr, unsigned if (addr+4>=bufLen) return "???"; return fmt::sprintf("call $%.8x",(unsigned int)(buf[addr+1]|(buf[addr+2]<<8)|(buf[addr+3]<<16)|(buf[addr+4]<<24))); break; + case 0xf6: + return "offwait"; + break; case 0xf7: { if (addr+1>=bufLen) return "???"; int cmdLen=DivCS::getCmdLength(buf[addr+1]); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index e070c3f33..76c044735 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -6064,7 +6064,8 @@ bool FurnaceGUI::loop() { } } else { WAKE_UP; - ImGui::Text("Exporting... %d",csProgress.count); + ImGui::Text("Exporting..."); + ImGui::Text("%d/%d",csProgress.optCurrent,csProgress.optTotal); // check whether we're done if (csExportDone) {