diff --git a/papers/export-tech.md b/papers/export-tech.md index 6e074b286..7c12dee22 100644 --- a/papers/export-tech.md +++ b/papers/export-tech.md @@ -28,8 +28,9 @@ size | description ??? | channel data ``` -read command and values (if any). -the list of commands follows. +program follows. + +### commands/instructions ``` hex | description @@ -47,7 +48,6 @@ hex | description b6 | note off env b7 | env release b8 | instrument // (ins, force) - be | panning // (left, right) c0 | pre porta // (inporta, isportaorslide) c2 | vibrato // (speed, depth) c3 | vibrato range // (range) @@ -55,9 +55,14 @@ hex | description c5 | pitch // (pitch) c6 | arpeggio // (note1, note2) c7 | volume // (vol) - c8 | vol slide // (amount, onetick) + c8 | vol slide // (amount) c9 | porta // (target, speed) ca | legato // (note) + cb | volume slide with target // (amount, target) + cc | tremolo // (speed/depth) + cd | panbrello // (speed/depth) + ce | pan slide // (speed) + cf | panning // (left, right) ----|------------------------------------ d0 | speed dial command 0 d1 | speed dial command 1 @@ -71,13 +76,13 @@ hex | description ----|------------------------------------ f0 | UNUSED - placeholder used during optimization passes (3-byte nonce follows) f1 | no operation - f2 | UNUSED - unoptimized extended command + f2 | UNUSED f3 | loop (negative offset and count follow... both are 8-bit) - f4 | call symbol (32-bit index follows; only used internally) - f5 | jump to sub-block (address follows) - f6 | go to sub-block (32-bit offset follows) + f4 | UNUSED - call symbol (32-bit index follows; only used internally) + f5 | call sub-block (32-bit address follows) + f6 | UNUSED f7 | full command (command and data follows) - f8 | go to sub-block (16-bit offset follows) + f8 | call sub-block (16-bit address follows) f9 | return from sub-block fa | jump (address follows) fb | set tick rate (4 bytes) @@ -87,3 +92,8 @@ hex | description ff | stop ``` +## full commands + +``` + +``` \ No newline at end of file diff --git a/src/engine/cmdStream.cpp b/src/engine/cmdStream.cpp index 7e24c7d42..f948a1ae7 100644 --- a/src/engine/cmdStream.cpp +++ b/src/engine/cmdStream.cpp @@ -117,6 +117,8 @@ bool DivCSPlayer::tick() { case 0xb8: case 0xbe: case 0xc0: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: case 0xc8: case 0xc9: case 0xca: + case 0xcb: case 0xcc: case 0xcd: case 0xce: + case 0xcf: command=next-0xb4; break; case 0xf0: // placeholder @@ -147,19 +149,11 @@ bool DivCSPlayer::tick() { command=stream.readC(); break; case 0xf8: { - unsigned int callAddr=chan[i].readPos+2+stream.readS(); + unsigned int callAddr=(unsigned short)stream.readS(); chan[i].readPos=stream.tell(); if (!chan[i].doCall(callAddr)) { - logE("%d: (callb16) stack error!",i); - } - mustTell=false; - break; - } - case 0xf6: { - unsigned int callAddr=chan[i].readPos+4+stream.readI(); - chan[i].readPos=stream.tell(); - if (!chan[i].doCall(callAddr)) { - logE("%d: (callb32) stack error!",i); + logE("%d: (call) stack error!",i); + chan[i].readPos=0; } mustTell=false; break; @@ -168,7 +162,8 @@ bool DivCSPlayer::tick() { unsigned int callAddr=stream.readI(); chan[i].readPos=stream.tell(); if (!chan[i].doCall(callAddr)) { - logE("%d: (call) stack error!",i); + logE("%d: (calli) stack error!",i); + chan[i].readPos=0; } mustTell=false; break; @@ -208,9 +203,9 @@ bool DivCSPlayer::tick() { chan[i].lastWaitLen=chan[i].waitTicks; break; case 0xff: - chan[i].readPos=chan[i].startPos; + chan[i].readPos=0; mustTell=false; - logI("%d: stop go back to %x",i,chan[i].readPos); + logI("%d: stop",i,chan[i].readPos); break; default: logE("%d: illegal instruction $%.2x! $%.x",i,next,chan[i].readPos); @@ -240,7 +235,7 @@ bool DivCSPlayer::tick() { arg0=(signed char)stream.readC(); arg1=(unsigned char)stream.readC(); break; - case DIV_CMD_PANNING: + case DIV_CMD_HINT_PANNING: // TODO: panbrello arg0=(unsigned char)stream.readC(); arg1=(unsigned char)stream.readC(); break; @@ -391,6 +386,9 @@ bool DivCSPlayer::tick() { case DIV_CMD_HINT_ARP_TIME: arpSpeed=arg0; break; + case DIV_CMD_HINT_PANNING: + e->dispatchCmd(DivCommand(DIV_CMD_PANNING,i,arg0,arg1)); + break; default: // dispatch it e->dispatchCmd(DivCommand((DivDispatchCmds)command,i,arg0,arg1)); break; diff --git a/src/engine/cmdStreamOps.cpp b/src/engine/cmdStreamOps.cpp index 04c5c1858..fed85115a 100644 --- a/src/engine/cmdStreamOps.cpp +++ b/src/engine/cmdStreamOps.cpp @@ -34,7 +34,7 @@ int DivCS::getInsLength(unsigned char ins, unsigned char ext) { case 0xca: // legato case 0xfd: // waitc return 2; - case 0xbe: // pan + case 0xcf: // pan case 0xc2: // vibrato case 0xc6: // arpeggio case 0xc8: // vol slide @@ -48,20 +48,19 @@ int DivCS::getInsLength(unsigned char ins, unsigned char ext) { return 0; case 0xf0: // opt return 4; - case 0xf2: // opt command case 0xf7: { // cmd // determine length from secondary if (ext==0) return 0; return 0; } - case 0xf8: // callb16 + case 0xf8: // call case 0xfc: // waits return 3; case 0xf4: // callsym - case 0xf5: // call - case 0xf6: // callb32 + case 0xf5: // calli case 0xfa: // jmp case 0xfb: // rate + case 0xcb: // volporta return 5; } return 1; @@ -80,7 +79,6 @@ void writePackedCommandValues(SafeWriter* w, const DivCommand& c) { case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_ENV_RELEASE: case DIV_CMD_INSTRUMENT: - case DIV_CMD_PANNING: case DIV_CMD_PRE_PORTA: case DIV_CMD_HINT_VIBRATO: case DIV_CMD_HINT_VIBRATO_RANGE: @@ -92,11 +90,15 @@ void writePackedCommandValues(SafeWriter* w, const DivCommand& c) { case DIV_CMD_HINT_VOL_SLIDE: case DIV_CMD_HINT_VOL_SLIDE_TARGET: case DIV_CMD_HINT_LEGATO: + case DIV_CMD_HINT_TREMOLO: + case DIV_CMD_HINT_PANBRELLO: + case DIV_CMD_HINT_PAN_SLIDE: + case DIV_CMD_HINT_PANNING: w->writeC((unsigned char)c.cmd+0xb4); break; default: - return; // quit for now... we'll implement this later - w->writeC(0xf2); // unoptimized extended command + return; + w->writeC(0xf7); w->writeC(c.cmd); break; } @@ -118,9 +120,12 @@ void writePackedCommandValues(SafeWriter* w, const DivCommand& c) { case DIV_CMD_HINT_VIBRATO_SHAPE: case DIV_CMD_HINT_PITCH: case DIV_CMD_HINT_VOLUME: + case DIV_CMD_HINT_TREMOLO: + case DIV_CMD_HINT_PANBRELLO: + case DIV_CMD_HINT_PAN_SLIDE: w->writeC(c.value); break; - case DIV_CMD_PANNING: + case DIV_CMD_HINT_PANNING: case DIV_CMD_HINT_VIBRATO: case DIV_CMD_HINT_ARPEGGIO: case DIV_CMD_HINT_PORTA: @@ -536,15 +541,11 @@ SafeWriter* DivEngine::saveCommand() { switch (i.cmd) { // strip away hinted/useless commands case DIV_CMD_GET_VOLUME: - break; case DIV_CMD_VOLUME: - break; + case DIV_CMD_PANNING: case DIV_CMD_NOTE_PORTA: - break; case DIV_CMD_LEGATO: - break; case DIV_CMD_PITCH: - break; case DIV_CMD_PRE_NOTE: break; default: @@ -808,119 +809,6 @@ SafeWriter* DivEngine::saveCommand() { sortPos++; }*/ - /* - for (int i=0; itoReader(); - chanStream[i]=new SafeWriter; - chanStream[i]->init(); - - while (1) { - try { - unsigned char next=reader->readC(); - switch (next) { - case 0xb8: // instrument - case 0xc0: // pre porta - case 0xc3: // vibrato range - case 0xc4: // vibrato shape - case 0xc5: // pitch - case 0xc7: // volume - case 0xca: // legato - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - break; - case 0xbe: // panning - case 0xc2: // vibrato - case 0xc6: // arpeggio - case 0xc8: // vol slide - case 0xc9: // porta - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - break; - case 0xf2: { // full command (pre) - unsigned char cmd=reader->readC(); - bool foundShort=false; - for (int j=0; j<16; j++) { - if (sortedCmd[j]==cmd) { - chanStream[i]->writeC(0xd0+j); - foundShort=true; - break; - } - } - if (!foundShort) { - chanStream[i]->writeC(0xf7); // full command - chanStream[i]->writeC(cmd); - } - - unsigned char cmdLen=reader->readC(); - logD("cmdLen: %d",cmdLen); - for (unsigned char j=0; jreadC(); - chanStream[i]->writeC(next); - } - break; - } - case 0xfb: // tick rate - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - next=reader->readC(); - chanStream[i]->writeC(next); - break; - case 0xfc: { // 16-bit wait - unsigned short delay=reader->readS(); - bool foundShort=false; - for (int j=0; j<16; j++) { - if (sortedDelay[j]==delay) { - chanStream[i]->writeC(0xe0+j); - foundShort=true; - break; - } - } - if (!foundShort) { - chanStream[i]->writeC(next); - chanStream[i]->writeS(delay); - } - break; - } - case 0xfd: { // 8-bit wait - unsigned char delay=reader->readC(); - bool foundShort=false; - for (int j=0; j<16; j++) { - if (sortedDelay[j]==delay) { - chanStream[i]->writeC(0xe0+j); - foundShort=true; - break; - } - } - if (!foundShort) { - chanStream[i]->writeC(next); - chanStream[i]->writeC(delay); - } - break; - } - default: - chanStream[i]->writeC(next); - break; - } - } catch (EndOfFileException& e) { - break; - } - } - - oldStream->finish(); - delete oldStream; - }*/ - // write results for (int i=0; itell(); diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index aa4c1cff8..7289767eb 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -71,6 +71,10 @@ enum DivDispatchCmds { DIV_CMD_HINT_PORTA, // (target, speed) DIV_CMD_HINT_LEGATO, // (note) DIV_CMD_HINT_VOL_SLIDE_TARGET, // (amount, target) + DIV_CMD_HINT_TREMOLO, // (speed/depth as a byte) + DIV_CMD_HINT_PANBRELLO, // (speed/depth as a byte) + DIV_CMD_HINT_PAN_SLIDE, // (speed) + DIV_CMD_HINT_PANNING, // (left, right) DIV_CMD_SAMPLE_MODE, // (enabled) DIV_CMD_SAMPLE_FREQ, // (frequency) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 8023851b1..cebd9846b 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -68,6 +68,10 @@ const char* cmdName[]={ "HINT_PORTA", "HINT_LEGATO", "HINT_VOL_SLIDE_TARGET", + "HINT_TREMOLO", + "HINT_PANBRELLO", + "HINT_PAN_SLIDE", + "HINT_PANNING", "SAMPLE_MODE", "SAMPLE_FREQ", @@ -764,6 +768,7 @@ void DivEngine::processRow(int i, bool afterDelay) { } else { chan[i].panSpeed=0; } + dispatchCmd(DivCommand(DIV_CMD_HINT_PAN_SLIDE,i,chan[i].panSpeed&0xff)); break; case 0x84: // panbrello if (chan[i].panDepth==0) { @@ -774,6 +779,7 @@ void DivEngine::processRow(int i, bool afterDelay) { if (chan[i].panDepth!=0) { chan[i].panSpeed=0; } + dispatchCmd(DivCommand(DIV_CMD_HINT_PANBRELLO,i,effectVal)); break; case 0x88: // panning rear (split 4-bit) chan[i].panRL=(effectVal>>4)|(effectVal&0xf0); @@ -941,6 +947,7 @@ void DivEngine::processRow(int i, bool afterDelay) { } chan[i].tremoloDepth=effectVal&15; chan[i].tremoloRate=effectVal>>4; + dispatchCmd(DivCommand(DIV_CMD_HINT_TREMOLO,i,effectVal)); if (chan[i].tremoloDepth!=0) { chan[i].volSpeed=0; chan[i].volSpeedTarget=-1; @@ -1229,6 +1236,7 @@ void DivEngine::processRow(int i, bool afterDelay) { if (panChanged) { dispatchCmd(DivCommand(DIV_CMD_PANNING,i,chan[i].panL,chan[i].panR)); + dispatchCmd(DivCommand(DIV_CMD_HINT_PANNING,i,chan[i].panL,chan[i].panR)); } if (surroundPanChanged) { dispatchCmd(DivCommand(DIV_CMD_SURROUND_PANNING,i,2,chan[i].panRL)); diff --git a/src/gui/csPlayer.cpp b/src/gui/csPlayer.cpp index d0a46533b..842fc1ac0 100644 --- a/src/gui/csPlayer.cpp +++ b/src/gui/csPlayer.cpp @@ -44,10 +44,6 @@ String disasmCmd(unsigned char* buf, size_t bufLen, unsigned int addr) { if (addr+1>=bufLen) return "???"; return fmt::sprintf("ins $%.2x",(int)buf[addr+1]); break; - case 0xbe: - if (addr+2>=bufLen) return "???"; - return fmt::sprintf("pan $%x, $%x",(int)buf[addr+1],(int)buf[addr+2]); - break; case 0xc0: if (addr+1>=bufLen) return "???"; return fmt::sprintf("preporta $%.2x",(int)buf[addr+1]); @@ -88,6 +84,26 @@ String disasmCmd(unsigned char* buf, size_t bufLen, unsigned int addr) { if (addr+1>=bufLen) return "???"; return fmt::sprintf("legato %d",(int)buf[addr+1]); break; + case 0xcb: + if (addr+4>=bufLen) return "???"; + return fmt::sprintf("volporta %d, %d",(int)((short)(buf[addr+1]|(buf[addr+2]<<8))),(int)((short)(buf[addr+3]|(buf[addr+4]<<8)))); + break; + case 0xcc: + if (addr+1>=bufLen) return "???"; + return fmt::sprintf("tremolo $%.2x",(int)buf[addr+1]); + break; + case 0xcd: + if (addr+1>=bufLen) return "???"; + return fmt::sprintf("panbrello $%.2x",(int)buf[addr+1]); + break; + case 0xce: + if (addr+1>=bufLen) return "???"; + return fmt::sprintf("panslide %d",(signed char)buf[addr+1]); + break; + case 0xcf: + 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: @@ -112,16 +128,12 @@ String disasmCmd(unsigned char* buf, size_t bufLen, unsigned int addr) { 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: - if (addr+4>=bufLen) return "???"; - return fmt::sprintf("callb32 %.8x",(unsigned int)(buf[addr+1]|(buf[addr+2]<<8)|(buf[addr+3]<<16)|(buf[addr+4]<<24))); - break; case 0xf7: return "CMD"; break; case 0xf8: if (addr+2>=bufLen) return "???"; - return fmt::sprintf("callb16 %.4x",(int)(buf[addr+1]|(buf[addr+2]<<8))); + return fmt::sprintf("call %.4x",(unsigned int)(buf[addr+1]|(buf[addr+2]<<8))); break; case 0xf9: return "ret";