command stream preset instruments/volumes
This commit is contained in:
parent
d3ce1a0b84
commit
92ad27f87e
5 changed files with 200 additions and 38 deletions
|
|
@ -27,8 +27,12 @@ size | description
|
|||
1 | reserved
|
||||
1?? | preset delays
|
||||
| - 16 values
|
||||
1?? | preset instruments
|
||||
| - 6 values
|
||||
1?? | preset volumes
|
||||
| - 6 values
|
||||
1?? | speed dial commands
|
||||
| - 16 values
|
||||
| - 4 values
|
||||
??? | pointers to channel data
|
||||
| - pointers are short (2-byte) or long (4-byte), set in flags
|
||||
1?? | maximum stack size per channel
|
||||
|
|
@ -115,10 +119,22 @@ hex | description
|
|||
de | wait one tick
|
||||
df | stop
|
||||
----|------------------------------------
|
||||
e0 | speed dial command 0
|
||||
e1 | speed dial command 1
|
||||
.. | ...
|
||||
ef | speed dial command 15
|
||||
e0 | preset instrument 0
|
||||
e1 | preset instrument 1
|
||||
e2 | preset instrument 2
|
||||
e3 | preset instrument 3
|
||||
e4 | preset instrument 4
|
||||
e5 | preset instrument 5
|
||||
e6 | preset volume 0
|
||||
e7 | preset volume 1
|
||||
e8 | preset volume 2
|
||||
e9 | preset volume 3
|
||||
ea | preset volume 4
|
||||
eb | preset volume 5
|
||||
ec | speed dial command 0
|
||||
ed | speed dial command 1
|
||||
ee | speed dial command 2
|
||||
ef | speed dial command 3
|
||||
----|------------------------------------
|
||||
f0 | preset delay 0
|
||||
f1 | preset delay 1
|
||||
|
|
|
|||
|
|
@ -59,6 +59,14 @@ unsigned char* DivCSPlayer::getFastDelays() {
|
|||
return fastDelays;
|
||||
}
|
||||
|
||||
unsigned char* DivCSPlayer::getFastIns() {
|
||||
return fastIns;
|
||||
}
|
||||
|
||||
unsigned char* DivCSPlayer::getFastVols() {
|
||||
return fastVols;
|
||||
}
|
||||
|
||||
unsigned char* DivCSPlayer::getFastCmds() {
|
||||
return fastCmds;
|
||||
}
|
||||
|
|
@ -110,9 +118,6 @@ bool DivCSPlayer::tick() {
|
|||
e->dispatchCmd(DivCommand(DIV_CMD_NOTE_ON,i,(int)next-60));
|
||||
chan[i].note=(int)next-60;
|
||||
chan[i].vibratoPos=0;
|
||||
} else if (next>=0xe0 && next<=0xef) {
|
||||
command=fastCmds[next&15];
|
||||
bAccessTS[fastCmdsOff+(next&15)]=curTick;
|
||||
} else if (next>=0xf0) { // preset delay
|
||||
chan[i].waitTicks=fastDelays[next&15];
|
||||
chan[i].lastWaitLen=chan[i].waitTicks;
|
||||
|
|
@ -205,13 +210,18 @@ bool DivCSPlayer::tick() {
|
|||
e->dispatchCmd(DivCommand(DIV_CMD_PANNING,i,panL,panR));
|
||||
break;
|
||||
}
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
|
||||
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
||||
case 0xe8: case 0xe9: case 0xea: case 0xeb:
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5:
|
||||
e->dispatchCmd(DivCommand(DIV_CMD_INSTRUMENT,i,fastIns[next-0xe0]));
|
||||
bAccessTS[fastInsOff+(next-0xe0)]=curTick;
|
||||
break;
|
||||
case 0xe6: case 0xe7: case 0xe8: case 0xe9: case 0xea: case 0xeb:
|
||||
chan[i].volume=fastVols[next-0xe6]<<8;
|
||||
bAccessTS[fastVolsOff+(next-0xe6)]=curTick;
|
||||
sendVolume=true;
|
||||
break;
|
||||
case 0xec: case 0xed: case 0xee: case 0xef:
|
||||
// TODO: remove as it has no effect
|
||||
command=fastCmds[next&15];
|
||||
|
||||
command=fastCmds[next&3];
|
||||
bAccessTS[fastCmdsOff+(next&3)]=curTick;
|
||||
break;
|
||||
case 0xd0: // placeholder
|
||||
stream.readC();
|
||||
|
|
@ -644,8 +654,12 @@ bool DivCSPlayer::init() {
|
|||
|
||||
fastDelaysOff=stream.tell();
|
||||
stream.read(fastDelays,16);
|
||||
fastInsOff=stream.tell();
|
||||
stream.read(fastIns,6);
|
||||
fastVolsOff=stream.tell();
|
||||
stream.read(fastVols,6);
|
||||
fastCmdsOff=stream.tell();
|
||||
stream.read(fastCmds,16);
|
||||
stream.read(fastCmds,4);
|
||||
|
||||
if (longPointers) {
|
||||
for (unsigned int i=0; i<fileChans; i++) {
|
||||
|
|
|
|||
|
|
@ -83,10 +83,12 @@ class DivCSPlayer {
|
|||
SafeReader stream;
|
||||
DivCSChannelState chan[DIV_MAX_CHANS];
|
||||
unsigned char fastDelays[16];
|
||||
unsigned char fastCmds[16];
|
||||
unsigned char fastIns[6];
|
||||
unsigned char fastVols[6];
|
||||
unsigned char fastCmds[4];
|
||||
unsigned char arpSpeed;
|
||||
unsigned int fileChans;
|
||||
unsigned int curTick, fastDelaysOff, fastCmdsOff, deltaCyclePos;
|
||||
unsigned int curTick, fastDelaysOff, fastInsOff, fastVolsOff, fastCmdsOff, deltaCyclePos;
|
||||
bool longPointers;
|
||||
bool bigEndian;
|
||||
|
||||
|
|
@ -98,6 +100,8 @@ class DivCSPlayer {
|
|||
DivCSChannelState* getChanState(int ch);
|
||||
unsigned int getFileChans();
|
||||
unsigned char* getFastDelays();
|
||||
unsigned char* getFastIns();
|
||||
unsigned char* getFastVols();
|
||||
unsigned char* getFastCmds();
|
||||
unsigned int getCurTick();
|
||||
void cleanup();
|
||||
|
|
|
|||
|
|
@ -256,13 +256,14 @@ int DivCS::getInsLength(unsigned char ins, unsigned char ext, unsigned char* spe
|
|||
case 0xc8: // vol slide
|
||||
case 0xc9: // porta
|
||||
return 3;
|
||||
// speed dial commands
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
|
||||
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
||||
case 0xe8: case 0xe9: case 0xea: case 0xeb:
|
||||
return 1;
|
||||
// speed dial commands
|
||||
case 0xec: case 0xed: case 0xee: case 0xef:
|
||||
if (speedDial==NULL) return 0;
|
||||
return 1+getCmdLength(speedDial[ins&15]);
|
||||
return 1+getCmdLength(speedDial[ins&3]);
|
||||
case 0xd0: // opt
|
||||
return 4;
|
||||
case 0xd7: // cmd
|
||||
|
|
@ -1257,12 +1258,18 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
|
|||
int loopRow=curSubSong->ts.loopStart.row;
|
||||
logI("loop point: %d %d",loopOrder,loopRow);
|
||||
|
||||
int insPopularity[256];
|
||||
int volPopularity[256];
|
||||
int cmdPopularity[256];
|
||||
int delayPopularity[256];
|
||||
|
||||
int sortedCmdPopularity[16];
|
||||
int sortedInsPopularity[6];
|
||||
int sortedVolPopularity[6];
|
||||
int sortedCmdPopularity[4];
|
||||
int sortedDelayPopularity[16];
|
||||
unsigned char sortedCmd[16];
|
||||
unsigned char sortedIns[6];
|
||||
unsigned char sortedVol[6];
|
||||
unsigned char sortedCmd[4];
|
||||
unsigned char sortedDelay[16];
|
||||
|
||||
SafeWriter* globalStream;
|
||||
|
|
@ -1272,14 +1279,20 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
|
|||
std::vector<size_t> tickPos[DIV_MAX_CHANS];
|
||||
int loopTick=-1;
|
||||
|
||||
memset(insPopularity,0,256*sizeof(int));
|
||||
memset(volPopularity,0,256*sizeof(int));
|
||||
memset(cmdPopularity,0,256*sizeof(int));
|
||||
memset(delayPopularity,0,256*sizeof(int));
|
||||
memset(chanStream,0,DIV_MAX_CHANS*sizeof(void*));
|
||||
memset(chanStreamOff,0,DIV_MAX_CHANS*sizeof(unsigned int));
|
||||
memset(chanStackSize,0,DIV_MAX_CHANS*sizeof(unsigned int));
|
||||
memset(sortedCmdPopularity,0,16*sizeof(int));
|
||||
memset(sortedInsPopularity,0,6*sizeof(int));
|
||||
memset(sortedVolPopularity,0,6*sizeof(int));
|
||||
memset(sortedCmdPopularity,0,4*sizeof(int));
|
||||
memset(sortedDelayPopularity,0,16*sizeof(int));
|
||||
memset(sortedCmd,0,16);
|
||||
memset(sortedIns,0,6);
|
||||
memset(sortedVol,0,6);
|
||||
memset(sortedCmd,0,4);
|
||||
memset(sortedDelay,0,16);
|
||||
|
||||
SafeWriter* w=new SafeWriter;
|
||||
|
|
@ -1386,6 +1399,11 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
|
|||
case DIV_CMD_PRE_NOTE:
|
||||
break;
|
||||
default:
|
||||
if (i.cmd==DIV_CMD_HINT_VOLUME) {
|
||||
volPopularity[i.value&0xff]++;
|
||||
} else if (i.cmd==DIV_CMD_INSTRUMENT) {
|
||||
insPopularity[i.value&0xff]++;
|
||||
}
|
||||
cmdPopularity[i.cmd]++;
|
||||
writeCommandValues(chanStream[i.chan],i,options.bigEndian);
|
||||
break;
|
||||
|
|
@ -1450,12 +1468,97 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
|
|||
extValuePresent=false;
|
||||
BUSY_END;
|
||||
|
||||
// PASS 1: optimize command calls
|
||||
// PASS 1: optimize command calls and volume/instrument changes
|
||||
if (!options.noCmdCallOpt) {
|
||||
// calculate command usage
|
||||
/// 1. instruments
|
||||
// calculate instrument usage
|
||||
int sortCand=-1;
|
||||
int sortPos=0;
|
||||
while (sortPos<16) {
|
||||
while (sortPos<6) {
|
||||
sortCand=-1;
|
||||
for (int i=0; i<256; i++) {
|
||||
if (insPopularity[i]) {
|
||||
if (sortCand==-1) {
|
||||
sortCand=i;
|
||||
} else if (insPopularity[sortCand]<insPopularity[i]) {
|
||||
sortCand=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sortCand==-1) break;
|
||||
|
||||
sortedInsPopularity[sortPos]=insPopularity[sortCand];
|
||||
sortedIns[sortPos]=sortCand;
|
||||
insPopularity[sortCand]=0;
|
||||
sortPos++;
|
||||
}
|
||||
|
||||
// set preset instruments
|
||||
for (int h=0; h<chans; h++) {
|
||||
unsigned char* buf=chanStream[h]->getFinalBuf();
|
||||
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
|
||||
if (buf[i]==0xb8) {
|
||||
// find whether this instrument is preset
|
||||
for (int j=0; j<6; j++) {
|
||||
if (buf[i+1]==sortedIns[j]) {
|
||||
buf[i]=0xe0+j;
|
||||
for (int k=i+1; k<(int)i+8; k++) {
|
||||
buf[k]=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 2. volumes
|
||||
// calculate volume usage
|
||||
sortCand=-1;
|
||||
sortPos=0;
|
||||
while (sortPos<6) {
|
||||
sortCand=-1;
|
||||
for (int i=0; i<256; i++) {
|
||||
if (volPopularity[i]) {
|
||||
if (sortCand==-1) {
|
||||
sortCand=i;
|
||||
} else if (volPopularity[sortCand]<volPopularity[i]) {
|
||||
sortCand=i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sortCand==-1) break;
|
||||
|
||||
sortedVolPopularity[sortPos]=volPopularity[sortCand];
|
||||
sortedVol[sortPos]=sortCand;
|
||||
volPopularity[sortCand]=0;
|
||||
sortPos++;
|
||||
}
|
||||
|
||||
// set preset volumes
|
||||
for (int h=0; h<chans; h++) {
|
||||
unsigned char* buf=chanStream[h]->getFinalBuf();
|
||||
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
|
||||
if (buf[i]==0xc7) {
|
||||
// find whether this volume is preset
|
||||
for (int j=0; j<6; j++) {
|
||||
if (buf[i+1]==sortedVol[j]) {
|
||||
buf[i]=0xe6+j;
|
||||
for (int k=i+1; k<(int)i+8; k++) {
|
||||
buf[k]=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 3. commands
|
||||
// calculate command usage
|
||||
sortCand=-1;
|
||||
sortPos=0;
|
||||
while (sortPos<4) {
|
||||
sortCand=-1;
|
||||
for (int i=DIV_CMD_SAMPLE_MODE; i<256; i++) {
|
||||
if (cmdPopularity[i]) {
|
||||
|
|
@ -1480,9 +1583,9 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
|
|||
for (size_t i=0; i<chanStream[h]->size(); i+=8) {
|
||||
if (buf[i]==0xd7) {
|
||||
// find whether this command is in speed dial
|
||||
for (int j=0; j<16; j++) {
|
||||
for (int j=0; j<4; j++) {
|
||||
if (buf[i+1]==sortedCmd[j]) {
|
||||
buf[i]=0xe0+j;
|
||||
buf[i]=0xec+j;
|
||||
// move everything to the left
|
||||
for (int k=i+2; k<(int)i+8; k++) {
|
||||
buf[k-1]=buf[k];
|
||||
|
|
@ -1795,8 +1898,20 @@ SafeWriter* DivEngine::saveCommand(DivCSProgress* progress, DivCSOptions options
|
|||
if (sortedDelayPopularity[i]) logD("- %d: %d",sortedDelay[i],sortedDelayPopularity[i]);
|
||||
}
|
||||
|
||||
logD("instrument popularity:");
|
||||
for (int i=0; i<6; i++) {
|
||||
w->writeC(sortedIns[i]);
|
||||
logD("- $%.2x: %d",sortedIns[i],sortedInsPopularity[i]);
|
||||
}
|
||||
|
||||
logD("volume popularity:");
|
||||
for (int i=0; i<6; i++) {
|
||||
w->writeC(sortedVol[i]);
|
||||
logD("- $%.2x: %d",sortedVol[i],sortedVolPopularity[i]);
|
||||
}
|
||||
|
||||
logD("command popularity:");
|
||||
for (int i=0; i<16; i++) {
|
||||
for (int i=0; i<4; i++) {
|
||||
w->writeC(sortedCmd[i]);
|
||||
if (sortedCmdPopularity[i]) logD("- %s ($%.2x): %d",cmdName[sortedCmd[i]],sortedCmd[i],sortedCmdPopularity[i]);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include "imgui.h"
|
||||
#include "guiConst.h"
|
||||
|
||||
String disasmCmd(unsigned char* buf, size_t bufLen, unsigned int addr, unsigned char* speedDial) {
|
||||
String disasmCmd(unsigned char* buf, size_t bufLen, unsigned int addr, unsigned char* fastIns, unsigned char* fastVols, unsigned char* fastCmds) {
|
||||
if (addr>=bufLen) return "???";
|
||||
|
||||
if (buf[addr]<0xb4) {
|
||||
|
|
@ -104,14 +104,17 @@ String disasmCmd(unsigned char* buf, size_t bufLen, unsigned int addr, unsigned
|
|||
if (addr+2>=bufLen) return "???";
|
||||
return fmt::sprintf("pan $%x, $%x",(int)buf[addr+1],(int)buf[addr+2]);
|
||||
break;
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3:
|
||||
case 0xe4: case 0xe5: case 0xe6: case 0xe7:
|
||||
case 0xe8: case 0xe9: case 0xea: case 0xeb:
|
||||
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5:
|
||||
return fmt::sprintf("qins%d $%.2x",buf[addr]-0xe0,fastIns[buf[addr]-0xe0]);
|
||||
break;
|
||||
case 0xe6: case 0xe7: case 0xe8: case 0xe9: case 0xea: case 0xeb:
|
||||
return fmt::sprintf("qvol%d $%.2x",buf[addr]-0xe6,fastVols[buf[addr]-0xe6]);
|
||||
break;
|
||||
case 0xec: case 0xed: case 0xee: case 0xef: {
|
||||
unsigned char cmd=speedDial[buf[addr]&15];
|
||||
unsigned char cmd=fastCmds[buf[addr]&3];
|
||||
int cmdLen=DivCS::getCmdLength(cmd);
|
||||
if ((addr+cmdLen)>=bufLen) return "???";
|
||||
String ret=fmt::sprintf("qcmd%d %s",buf[addr]-0xd0,(cmd<DIV_CMD_MAX)?cmdName[cmd]:"INVALID");
|
||||
String ret=fmt::sprintf("qcmd%d %s",buf[addr]-0xec,(cmd<DIV_CMD_MAX)?cmdName[cmd]:"INVALID");
|
||||
for (int i=0; i<cmdLen; i++) {
|
||||
ret+=fmt::sprintf(", %.2x",buf[addr+1+i]);
|
||||
}
|
||||
|
|
@ -325,7 +328,7 @@ void FurnaceGUI::drawCSPlayer() {
|
|||
if (state->trace[j]==0) {
|
||||
ImGui::TextUnformatted("...");
|
||||
} else {
|
||||
String dis=disasmCmd(buf,bufSize,state->trace[j],cs->getFastCmds());
|
||||
String dis=disasmCmd(buf,bufSize,state->trace[j],cs->getFastIns(),cs->getFastVols(),cs->getFastCmds());
|
||||
ImGui::Text("%.4x: %s",state->trace[j],dis.c_str());
|
||||
}
|
||||
}
|
||||
|
|
@ -400,7 +403,7 @@ void FurnaceGUI::drawCSPlayer() {
|
|||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
String dis=disasmCmd(i.data,8,0,cs->getFastCmds());
|
||||
String dis=disasmCmd(i.data,8,0,cs->getFastIns(),cs->getFastVols(),cs->getFastCmds());
|
||||
ImGui::Text("%s",dis.c_str());
|
||||
|
||||
// jmp/ret separator
|
||||
|
|
@ -599,8 +602,18 @@ void FurnaceGUI::drawCSPlayer() {
|
|||
ImGui::SameLine();
|
||||
ImGui::Text("%d",cs->getFastDelays()[i]);
|
||||
}
|
||||
ImGui::Text("preset instruments:");
|
||||
for (int i=0; i<6; i++) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%d",cs->getFastIns()[i]);
|
||||
}
|
||||
ImGui::Text("preset volumes:");
|
||||
for (int i=0; i<6; i++) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%d",cs->getFastVols()[i]);
|
||||
}
|
||||
ImGui::Text("speed dial commands:");
|
||||
for (int i=0; i<16; i++) {
|
||||
for (int i=0; i<4; i++) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("%d",cs->getFastCmds()[i]);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue