ZSM export: support for looped samples, fix error dispatching ZSM sync events

This commit is contained in:
MooingLemur 2023-07-07 11:38:44 -07:00 committed by tildearrow
parent dfa663a500
commit d722cc33d4
4 changed files with 39 additions and 20 deletions

View File

@ -19,7 +19,6 @@
#include "vera.h"
#include "../engine.h"
#include "../../ta-log.h"
#include <string.h>
#include <math.h>
@ -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;
}

View File

@ -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);

View File

@ -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 <l m h>
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

View File

@ -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<DivRegWrite> ymwrites;
std::vector<DivRegWrite> pcmMeta;
std::vector<unsigned char> pcmData;