diff --git a/src/engine/platform/vera.cpp b/src/engine/platform/vera.cpp index fe34b8bc..5b8c2d9e 100644 --- a/src/engine/platform/vera.cpp +++ b/src/engine/platform/vera.cpp @@ -19,7 +19,6 @@ #include "vera.h" #include "../engine.h" -#include "../../ta-log.h" #include #include @@ -40,14 +39,15 @@ extern "C" { #define rWriteZSMSync(d) {if (dumpWrites) addWrite(68,(d));} const char* regCheatSheetVERA[]={ - "CHxFreq", "00+x*4", - "CHxVol", "02+x*4", - "CHxWave", "03+x*4", + "CHxFreq", "00+x*4", + "CHxVol", "02+x*4", + "CHxWave", "03+x*4", - "AUDIO_CTRL", "40", - "AUDIO_RATE", "41", - "AUDIO_DATA", "42", - "ZSM_SYNC", "44", + "AUDIO_CTRL", "40", + "AUDIO_RATE", "41", + "AUDIO_DATA", "42", + "ZSM_PCM_LOOP_POINT", "43", + "ZSM_SYNC", "44", NULL }; @@ -230,9 +230,16 @@ void DivPlatformVERA::tick(bool sysTick) { chan[16].freqChanged=false; } + // For export, output the entire sample that starts on this tick if (dumpWrites) { DivSample* s=parent->getSample(chan[16].pcm.sample); if (s->samples>0) { + if (s->isLoopable()) { + // Inform the export process of the loop point for this sample + addWrite(67,s->loopStart&0xff); + addWrite(67,(s->loopStart>>8)&0xff); + addWrite(67,(s->loopStart>>16)&0xff); + } while (true) { short tmp_l=0; short tmp_r=0; @@ -258,8 +265,6 @@ void DivPlatformVERA::tick(bool sysTick) { } chan[16].pcm.pos++; if (s->isLoopable() && chan[16].pcm.pos>=(unsigned int)s->loopEnd) { - //chan[16].pcm.pos=s->loopStart; - logI("VERA PCM export: treating looped sample as non-looped"); chan[16].pcm.sample=-1; break; } diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 7825e188..9f8a2f10 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -915,7 +915,7 @@ void DivEngine::processRow(int i, bool afterDelay) { //printf("\x1b[1;36m%d: extern command %d\x1b[m\n",i,effectVal); extValue=effectVal; extValuePresent=true; - dispatchCmd(DivCommand(DIV_CMD_EXTERNAL,effectVal)); + dispatchCmd(DivCommand(DIV_CMD_EXTERNAL,i,effectVal)); break; case 0xef: // global pitch globalPitch+=(signed char)(effectVal-0x80); diff --git a/src/engine/zsm.cpp b/src/engine/zsm.cpp index b0f42111..7cedc6d8 100644 --- a/src/engine/zsm.cpp +++ b/src/engine/zsm.cpp @@ -61,6 +61,8 @@ void DivZSM::init(unsigned int rate) { pcmRateCache=-1; pcmCtrlRVCache=-1; pcmCtrlDCCache=-1; + pcmIsLooped=false; + pcmLoopPointCache=0; // Channel masks ymMask=0; psgMask=0; @@ -166,6 +168,9 @@ void DivZSM::writePCM(unsigned char a, unsigned char v) { } else if (a==2) { // PCM data pcmCache.push_back(v); numWrites++; + } else if (a==3) { // PCM loop point + pcmLoopPointCache=(pcmLoopPointCache>>8)|(v<<16); + pcmIsLooped=true; } } @@ -213,7 +218,7 @@ SafeWriter* DivZSM::finish() { pcmData.clear(); pcmInsts.clear(); } else if (pcmData.size()) { // if exists, write PCM instruments and blob to the end of file - int pcmOff=w->tell(); + unsigned int pcmOff=w->tell(); w->writeC('P'); w->writeC('C'); w->writeC('M'); @@ -236,10 +241,11 @@ SafeWriter* DivZSM::finish() { w->writeC((unsigned char)(inst.length>>16)&0xff); // Feature mask: Lxxxxxxx // L = Loop enabled - w->writeC(0); - // Loop point (not yet implemented) - w->writeC(0); - w->writeS(0); + w->writeC((unsigned char)inst.isLooped<<7); + // Sample loop point + w->writeC((unsigned char)inst.loopPoint&0xff); + w->writeC((unsigned char)(inst.loopPoint>>8)&0xff); + w->writeC((unsigned char)(inst.loopPoint>>16)&0xff); // Reserved for future use w->writeS(0); w->writeS(0); @@ -289,8 +295,8 @@ void DivZSM::flushWrites() { } ymwrites.clear(); unsigned int pcmInst=0; - int pcmOff=0; - int pcmLen=0; + unsigned int pcmOff=0; + unsigned int pcmLen=0; int extCmd0Len=pcmMeta.size()*2; if (pcmCache.size()) { // collapse stereo data to mono if both channels are fully identical @@ -347,7 +353,7 @@ void DivZSM::flushWrites() { extCmd0Len+=2; // search for a matching PCM instrument definition for (S_pcmInst& inst: pcmInsts) { - if (inst.offset==pcmOff && inst.length==pcmLen && inst.geometry==pcmCtrlDCCache) + if (inst.offset==pcmOff && inst.length==pcmLen && inst.geometry==pcmCtrlDCCache && inst.isLooped==pcmIsLooped && inst.loopPoint==pcmLoopPointCache) break; pcmInst++; } @@ -356,7 +362,11 @@ void DivZSM::flushWrites() { inst.geometry=pcmCtrlDCCache; inst.offset=pcmOff; inst.length=pcmLen; + inst.loopPoint=pcmLoopPointCache; + inst.isLooped=pcmIsLooped; pcmInsts.push_back(inst); + pcmIsLooped=false; + pcmLoopPointCache=0; } } if (extCmd0Len>63) { // this would be bad, but will almost certainly never happen diff --git a/src/engine/zsm.h b/src/engine/zsm.h index 42300cf7..ff497693 100644 --- a/src/engine/zsm.h +++ b/src/engine/zsm.h @@ -46,7 +46,9 @@ enum PSG_STATE { psg_PREV, psg_NEW, psg_STATES }; class DivZSM { private: struct S_pcmInst { - int geometry, offset, length; + int geometry; + unsigned int offset, length, loopPoint; + bool isLooped; }; SafeWriter* w; int ymState[ym_STATES][256]; @@ -54,6 +56,8 @@ class DivZSM { int pcmRateCache; int pcmCtrlRVCache; int pcmCtrlDCCache; + unsigned int pcmLoopPointCache; + bool pcmIsLooped; std::vector ymwrites; std::vector pcmMeta; std::vector pcmData;