implement command playback - UNTESTED!

This commit is contained in:
tildearrow 2025-04-05 19:27:44 -05:00
parent d7922baa07
commit 6fba60818d
3 changed files with 169 additions and 33 deletions

View file

@ -223,7 +223,6 @@ bool DivCSPlayer::tick() {
case DIV_CMD_HINT_VIBRATO_RANGE: case DIV_CMD_HINT_VIBRATO_RANGE:
case DIV_CMD_HINT_VIBRATO_SHAPE: case DIV_CMD_HINT_VIBRATO_SHAPE:
case DIV_CMD_HINT_VOLUME: case DIV_CMD_HINT_VOLUME:
case DIV_CMD_HINT_ARP_TIME:
arg0=(unsigned char)stream.readC(); arg0=(unsigned char)stream.readC();
break; break;
case DIV_CMD_HINT_PITCH: case DIV_CMD_HINT_PITCH:
@ -259,14 +258,16 @@ bool DivCSPlayer::tick() {
arg0-=60; arg0-=60;
} }
break; break;
// ONE BYTE COMMANDS
case DIV_CMD_SAMPLE_MODE: case DIV_CMD_SAMPLE_MODE:
case DIV_CMD_SAMPLE_FREQ: case DIV_CMD_SAMPLE_FREQ:
case DIV_CMD_SAMPLE_BANK: case DIV_CMD_SAMPLE_BANK:
case DIV_CMD_SAMPLE_POS:
case DIV_CMD_SAMPLE_DIR: case DIV_CMD_SAMPLE_DIR:
case DIV_CMD_FM_HARD_RESET: case DIV_CMD_FM_HARD_RESET:
case DIV_CMD_FM_LFO: case DIV_CMD_FM_LFO:
case DIV_CMD_FM_LFO_WAVE: case DIV_CMD_FM_LFO_WAVE:
case DIV_CMD_FM_LFO2:
case DIV_CMD_FM_LFO2_WAVE:
case DIV_CMD_FM_FB: case DIV_CMD_FM_FB:
case DIV_CMD_FM_EXTCH: case DIV_CMD_FM_EXTCH:
case DIV_CMD_FM_AM_DEPTH: case DIV_CMD_FM_AM_DEPTH:
@ -306,8 +307,101 @@ bool DivCSPlayer::tick() {
case DIV_CMD_MACRO_OFF: case DIV_CMD_MACRO_OFF:
case DIV_CMD_MACRO_ON: case DIV_CMD_MACRO_ON:
case DIV_CMD_MACRO_RESTART: case DIV_CMD_MACRO_RESTART:
case DIV_CMD_HINT_ARP_TIME:
case DIV_CMD_QSOUND_ECHO_FEEDBACK:
case DIV_CMD_QSOUND_ECHO_LEVEL:
case DIV_CMD_QSOUND_SURROUND:
case DIV_CMD_X1_010_ENVELOPE_SHAPE:
case DIV_CMD_X1_010_ENVELOPE_ENABLE:
case DIV_CMD_X1_010_ENVELOPE_MODE:
case DIV_CMD_X1_010_ENVELOPE_PERIOD:
case DIV_CMD_X1_010_ENVELOPE_SLIDE:
case DIV_CMD_X1_010_AUTO_ENVELOPE:
case DIV_CMD_X1_010_SAMPLE_BANK_SLOT:
case DIV_CMD_WS_SWEEP_TIME:
case DIV_CMD_WS_SWEEP_AMOUNT:
case DIV_CMD_N163_WAVE_POSITION:
case DIV_CMD_N163_WAVE_LENGTH:
case DIV_CMD_N163_WAVE_UNUSED1:
case DIV_CMD_N163_WAVE_UNUSED2:
case DIV_CMD_N163_WAVE_LOADPOS:
case DIV_CMD_N163_WAVE_LOADLEN:
case DIV_CMD_N163_WAVE_UNUSED3:
case DIV_CMD_N163_CHANNEL_LIMIT:
case DIV_CMD_N163_GLOBAL_WAVE_LOAD:
case DIV_CMD_N163_GLOBAL_WAVE_LOADPOS:
case DIV_CMD_N163_UNUSED4:
case DIV_CMD_N163_UNUSED5:
case DIV_CMD_SU_SYNC_PERIOD_LOW:
case DIV_CMD_SU_SYNC_PERIOD_HIGH:
case DIV_CMD_ADPCMA_GLOBAL_VOLUME:
case DIV_CMD_SNES_ECHO:
case DIV_CMD_SNES_PITCH_MOD:
case DIV_CMD_SNES_INVERT:
case DIV_CMD_SNES_GAIN_MODE:
case DIV_CMD_SNES_GAIN:
case DIV_CMD_SNES_ECHO_ENABLE:
case DIV_CMD_SNES_ECHO_DELAY:
case DIV_CMD_SNES_ECHO_VOL_LEFT:
case DIV_CMD_SNES_ECHO_VOL_RIGHT:
case DIV_CMD_SNES_ECHO_FEEDBACK:
case DIV_CMD_NES_ENV_MODE:
case DIV_CMD_NES_LENGTH:
case DIV_CMD_NES_COUNT_MODE:
case DIV_CMD_FM_AM2_DEPTH:
case DIV_CMD_FM_PM2_DEPTH:
case DIV_CMD_ES5506_ENVELOPE_LVRAMP:
case DIV_CMD_ES5506_ENVELOPE_RVRAMP:
case DIV_CMD_ES5506_PAUSE:
case DIV_CMD_ES5506_FILTER_MODE:
case DIV_CMD_SNES_GLOBAL_VOL_LEFT:
case DIV_CMD_SNES_GLOBAL_VOL_RIGHT:
case DIV_CMD_NES_LINEAR_LENGTH:
case DIV_CMD_EXTERNAL:
case DIV_CMD_C64_AD:
case DIV_CMD_C64_SR:
case DIV_CMD_DAVE_HIGH_PASS:
case DIV_CMD_DAVE_RING_MOD:
case DIV_CMD_DAVE_SWAP_COUNTERS:
case DIV_CMD_DAVE_LOW_PASS:
case DIV_CMD_DAVE_CLOCK_DIV:
case DIV_CMD_MINMOD_ECHO:
case DIV_CMD_FDS_MOD_AUTO:
case DIV_CMD_FM_OPMASK:
case DIV_CMD_MULTIPCM_MIX_FM:
case DIV_CMD_MULTIPCM_MIX_PCM:
case DIV_CMD_MULTIPCM_LFO:
case DIV_CMD_MULTIPCM_VIB:
case DIV_CMD_MULTIPCM_AM:
case DIV_CMD_MULTIPCM_AR:
case DIV_CMD_MULTIPCM_D1R:
case DIV_CMD_MULTIPCM_DL:
case DIV_CMD_MULTIPCM_D2R:
case DIV_CMD_MULTIPCM_RC:
case DIV_CMD_MULTIPCM_RR:
case DIV_CMD_MULTIPCM_DAMP:
case DIV_CMD_MULTIPCM_PSEUDO_REVERB:
case DIV_CMD_MULTIPCM_LFO_RESET:
case DIV_CMD_MULTIPCM_LEVEL_DIRECT:
case DIV_CMD_SID3_SPECIAL_WAVE:
case DIV_CMD_SID3_RING_MOD_SRC:
case DIV_CMD_SID3_HARD_SYNC_SRC:
case DIV_CMD_SID3_PHASE_MOD_SRC:
case DIV_CMD_SID3_WAVE_MIX:
case DIV_CMD_SID3_1_BIT_NOISE:
case DIV_CMD_SID3_CHANNEL_INVERSION:
case DIV_CMD_SID3_FILTER_CONNECTION:
case DIV_CMD_SID3_FILTER_MATRIX:
case DIV_CMD_SID3_FILTER_ENABLE:
case DIV_CMD_SID3_PHASE_RESET:
case DIV_CMD_SID3_NOISE_PHASE_RESET:
case DIV_CMD_SID3_ENVELOPE_RESET:
case DIV_CMD_SID3_CUTOFF_SCALING:
case DIV_CMD_SID3_RESONANCE_SCALING:
case DIV_CMD_WS_GLOBAL_SPEAKER_VOLUME:
arg0=(unsigned char)stream.readC(); arg0=(unsigned char)stream.readC();
break; break;
// TWO BYTE COMMANDS
case DIV_CMD_FM_TL: case DIV_CMD_FM_TL:
case DIV_CMD_FM_AM: case DIV_CMD_FM_AM:
case DIV_CMD_FM_AR: case DIV_CMD_FM_AR:
@ -330,14 +424,45 @@ bool DivCSPlayer::tick() {
case DIV_CMD_AY_IO_WRITE: case DIV_CMD_AY_IO_WRITE:
case DIV_CMD_AY_AUTO_PWM: case DIV_CMD_AY_AUTO_PWM:
case DIV_CMD_SURROUND_PANNING: case DIV_CMD_SURROUND_PANNING:
case DIV_CMD_SU_SWEEP_PERIOD_LOW:
case DIV_CMD_SU_SWEEP_PERIOD_HIGH:
case DIV_CMD_SU_SWEEP_BOUND:
case DIV_CMD_SU_SWEEP_ENABLE:
case DIV_CMD_SNES_ECHO_FIR:
case DIV_CMD_ES5506_FILTER_K1_SLIDE:
case DIV_CMD_ES5506_FILTER_K2_SLIDE:
case DIV_CMD_ES5506_ENVELOPE_K1RAMP:
case DIV_CMD_ES5506_ENVELOPE_K2RAMP:
case DIV_CMD_ESFM_OP_PANNING:
case DIV_CMD_ESFM_OUTLVL:
case DIV_CMD_ESFM_MODIN:
case DIV_CMD_ESFM_ENV_DELAY:
case DIV_CMD_POWERNOISE_COUNTER_LOAD:
case DIV_CMD_POWERNOISE_IO_WRITE:
case DIV_CMD_BIFURCATOR_STATE_LOAD:
case DIV_CMD_BIFURCATOR_PARAMETER:
case DIV_CMD_SID3_LFSR_FEEDBACK_BITS:
case DIV_CMD_SID3_FILTER_DISTORTION:
case DIV_CMD_SID3_FILTER_OUTPUT_VOLUME:
case DIV_CMD_C64_PW_SLIDE:
case DIV_CMD_C64_CUTOFF_SLIDE:
arg0=(unsigned char)stream.readC(); arg0=(unsigned char)stream.readC();
arg1=(unsigned char)stream.readC(); arg1=(unsigned char)stream.readC();
break; break;
// ONE SHORT COMMANDS
case DIV_CMD_C64_FINE_DUTY: case DIV_CMD_C64_FINE_DUTY:
case DIV_CMD_C64_FINE_CUTOFF: case DIV_CMD_C64_FINE_CUTOFF:
case DIV_CMD_LYNX_LFSR_LOAD: case DIV_CMD_LYNX_LFSR_LOAD:
case DIV_CMD_QSOUND_ECHO_DELAY:
case DIV_CMD_ES5506_ENVELOPE_COUNT:
arg0=(unsigned short)stream.readS(); arg0=(unsigned short)stream.readS();
break; break;
// TWO SHORT COMMANDS
case DIV_CMD_ES5506_FILTER_K1:
case DIV_CMD_ES5506_FILTER_K2:
arg0=(unsigned short)stream.readS();
arg1=(unsigned short)stream.readS();
break;
case DIV_CMD_FM_FIXFREQ: case DIV_CMD_FM_FIXFREQ:
arg0=(unsigned short)stream.readS(); arg0=(unsigned short)stream.readS();
arg1=arg0&0x7ff; arg1=arg0&0x7ff;
@ -348,6 +473,9 @@ bool DivCSPlayer::tick() {
arg1=arg0&0x77; arg1=arg0&0x77;
arg0=(arg0&8)?1:0; arg0=(arg0&8)?1:0;
break; break;
case DIV_CMD_SAMPLE_POS:
arg0=(unsigned int)stream.readI();
break;
} }
switch (command) { switch (command) {

View file

@ -913,7 +913,32 @@ SafeWriter* DivEngine::saveCommand() {
extValuePresent=false; extValuePresent=false;
BUSY_END; BUSY_END;
// PASS 1: condense delays // PASS 1: optimize command calls
// calculate command usage
int sortCand=-1;
int sortPos=0;
while (sortPos<16) {
sortCand=-1;
for (int i=DIV_CMD_SAMPLE_MODE; i<256; i++) {
if (cmdPopularity[i]) {
if (sortCand==-1) {
sortCand=i;
} else if (cmdPopularity[sortCand]<cmdPopularity[i]) {
sortCand=i;
}
}
}
if (sortCand==-1) break;
sortedCmdPopularity[sortPos]=cmdPopularity[sortCand];
sortedCmd[sortPos]=sortCand;
cmdPopularity[sortCand]=0;
sortPos++;
}
// set speed dial commands (TODO)
// PASS 2: condense delays
// calculate delay usage // calculate delay usage
for (int h=0; h<chans; h++) { for (int h=0; h<chans; h++) {
unsigned char* buf=chanStream[h]->getFinalBuf(); unsigned char* buf=chanStream[h]->getFinalBuf();
@ -937,8 +962,8 @@ SafeWriter* DivEngine::saveCommand() {
} }
// preset delays // preset delays
int sortCand=-1; sortCand=-1;
int sortPos=0; sortPos=0;
while (sortPos<16) { while (sortPos<16) {
sortCand=-1; sortCand=-1;
for (int i=0; i<256; i++) { for (int i=0; i<256; i++) {
@ -1015,14 +1040,14 @@ SafeWriter* DivEngine::saveCommand() {
} }
} }
// PASS 2: remove nop's // PASS 3: remove nop's
// this includes modifying call addresses to compensate // this includes modifying call addresses to compensate
for (int h=0; h<chans; h++) { for (int h=0; h<chans; h++) {
chanStream[h]=stripNops(chanStream[h],sortedCmd); chanStream[h]=stripNops(chanStream[h],sortedCmd);
} }
#ifndef DISABLE_BLOCK_SEARCH #ifndef DISABLE_BLOCK_SEARCH
// PASS 3: find sub-blocks and isolate them // PASS 4: find sub-blocks and isolate them
for (int h=0; h<chans; h++) { for (int h=0; h<chans; h++) {
std::vector<SafeWriter*> subBlocks; std::vector<SafeWriter*> subBlocks;
size_t beforeSize=chanStream[h]->size(); size_t beforeSize=chanStream[h]->size();
@ -1109,34 +1134,11 @@ SafeWriter* DivEngine::saveCommand() {
} }
#endif #endif
// PASS 4: remove nop's (again) // PASS 5: remove nop's (again)
for (int h=0; h<chans; h++) { for (int h=0; h<chans; h++) {
chanStream[h]=stripNops(chanStream[h],sortedCmd); chanStream[h]=stripNops(chanStream[h],sortedCmd);
} }
// PASS 5: optimize command calls
/*
int sortCand=-1;
int sortPos=0;
while (sortPos<16) {
sortCand=-1;
for (int i=DIV_CMD_SAMPLE_MODE; i<256; i++) {
if (cmdPopularity[i]) {
if (sortCand==-1) {
sortCand=i;
} else if (cmdPopularity[sortCand]<cmdPopularity[i]) {
sortCand=i;
}
}
}
if (sortCand==-1) break;
sortedCmdPopularity[sortPos]=cmdPopularity[sortCand];
sortedCmd[sortPos]=sortCand;
cmdPopularity[sortCand]=0;
sortPos++;
}*/
// write results // write results
for (int i=0; i<chans; i++) { for (int i=0; i<chans; i++) {
chanStreamOff[i]=w->tell(); chanStreamOff[i]=w->tell();

View file

@ -104,6 +104,12 @@ String disasmCmd(unsigned char* buf, size_t bufLen, unsigned int addr) {
if (addr+2>=bufLen) return "???"; if (addr+2>=bufLen) return "???";
return fmt::sprintf("pan $%x, $%x",(int)buf[addr+1],(int)buf[addr+2]); return fmt::sprintf("pan $%x, $%x",(int)buf[addr+1],(int)buf[addr+2]);
break; break;
case 0xd0: case 0xd1: case 0xd2: case 0xd3:
case 0xd4: case 0xd5: case 0xd6: case 0xd7:
case 0xd8: case 0xd9: case 0xda: case 0xdb:
case 0xdc: case 0xdd: case 0xde: case 0xdf:
return "qcmd";
break;
case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe0: case 0xe1: case 0xe2: case 0xe3:
case 0xe4: case 0xe5: case 0xe6: case 0xe7: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xe8: case 0xe9: case 0xea: case 0xeb:
@ -129,7 +135,7 @@ String disasmCmd(unsigned char* buf, size_t bufLen, unsigned int addr) {
return fmt::sprintf("call %.8x",(unsigned int)(buf[addr+1]|(buf[addr+2]<<8)|(buf[addr+3]<<16)|(buf[addr+4]<<24))); return fmt::sprintf("call %.8x",(unsigned int)(buf[addr+1]|(buf[addr+2]<<8)|(buf[addr+3]<<16)|(buf[addr+4]<<24)));
break; break;
case 0xf7: case 0xf7:
return "CMD"; return "cmd";
break; break;
case 0xf8: case 0xf8:
if (addr+2>=bufLen) return "???"; if (addr+2>=bufLen) return "???";
@ -329,7 +335,7 @@ void FurnaceGUI::drawCSPlayer() {
csDisAsm.clear(); csDisAsm.clear();
unsigned char* buf=cs->getData(); unsigned char* buf=cs->getData();
for (size_t i=csDisAsmAddr; i<cs->getDataLen();) { for (size_t i=csDisAsmAddr; i<cs->getDataLen();) {
int insLen=DivCS::getInsLength(buf[i]); int insLen=DivCS::getInsLength(buf[i],(((i+1)<cs->getDataLen())?buf[i+1]:0),cs->getFastCmds());
if (insLen<1) { if (insLen<1) {
logE("INS %x NOT IMPLEMENTED...",buf[i]); logE("INS %x NOT IMPLEMENTED...",buf[i]);
break; break;