VERA, ZSM Export: Add EFxx event as synchronization message, add sync message support in ZSM export

This commit is contained in:
MooingLemur 2023-07-05 15:07:44 -07:00
parent 23b65c61ce
commit fba48149a5
10 changed files with 67 additions and 24 deletions

View file

@ -118,9 +118,13 @@ void DivZSM::writePSG(unsigned char a, unsigned char v) {
// TODO: suppress writes to PSG voice that is not audible (volume=0)
// ^ Let's leave these alone, ZSMKit has a feature that can benefit
// from silent channels.
if (a>=67) {
logD ("ZSM: ignoring VERA PSG write a=%02x v=%02x",a,v);
if (a>=69) {
logD("ZSM: ignoring VERA PSG write a=%02x v=%02x",a,v);
return;
} else if (a==68) {
// Sync event
numWrites++;
return syncCache.push_back(v);
} else if (a>=64) {
return writePCM(a-64,v);
}
@ -259,7 +263,7 @@ SafeWriter* DivZSM::finish() {
}
void DivZSM::flushWrites() {
logD("ZSM: flushWrites.... numwrites=%d ticks=%d ymwrites=%d pcmMeta=%d pcmCache=%d pcmData=%d",numWrites,ticks,ymwrites.size(),pcmMeta.size(),pcmCache.size(),pcmData.size());
logD("ZSM: flushWrites.... numwrites=%d ticks=%d ymwrites=%d pcmMeta=%d pcmCache=%d pcmData=%d syncCache=%d",numWrites,ticks,ymwrites.size(),pcmMeta.size(),pcmCache.size(),pcmData.size(),syncCache.size());
if (numWrites==0) return;
flushTicks(); // only flush ticks if there are writes pending.
for (unsigned char i=0; i<64; i++) {
@ -287,43 +291,43 @@ void DivZSM::flushWrites() {
unsigned int pcmInst=0;
int pcmOff=0;
int pcmLen=0;
int extCmdLen=pcmMeta.size()*2;
int extCmd0Len=pcmMeta.size()*2;
if (pcmCache.size()) {
// collapse stereo data to mono if both channels are fully identical
// which cuts PCM data size in half for center-panned PCM events
if (pcmCtrlDCCache & 0x10) { // stereo bit is on
if (pcmCtrlDCCache&0x10) { // stereo bit is on
unsigned int e;
if (pcmCtrlDCCache & 0x20) { // 16-bit
if (pcmCtrlDCCache&0x20) { // 16-bit
// for 16-bit PCM data, the size must be a multiple of 4
if (pcmCache.size()%4==0) {
// check for identical L+R channels
for (e=0;e<pcmCache.size();e+=4) {
for (e=0; e<pcmCache.size(); e+=4) {
if (pcmCache[e]!=pcmCache[e+2] || pcmCache[e+1]!=pcmCache[e+3]) break;
}
if (e==pcmCache.size()) { // did not find a mismatch
// collapse the data to mono 16-bit
for (e=0;e<pcmCache.size()>>1;e+=2) {
for (e=0; e<pcmCache.size()>>1; e+=2) {
pcmCache[e]=pcmCache[e<<1];
pcmCache[e+1]=pcmCache[(e<<1)+1];
}
pcmCache.resize(pcmCache.size()>>1);
pcmCtrlDCCache &= ~0x10; // clear stereo bit
pcmCtrlDCCache&=(unsigned char)~0x10; // clear stereo bit
}
}
} else { // 8-bit
// for 8-bit PCM data, the size must be a multiple of 2
if (pcmCache.size()%2==0) {
// check for identical L+R channels
for (e=0;e<pcmCache.size();e+=2) {
for (e=0; e<pcmCache.size(); e+=2) {
if (pcmCache[e]!=pcmCache[e+1]) break;
}
if (e==pcmCache.size()) { // did not find a mismatch
// collapse the data to mono 8-bit
for (e=0;e<pcmCache.size()>>1;e++) {
for (e=0; e<pcmCache.size()>>1; e++) {
pcmCache[e]=pcmCache[e<<1];
}
pcmCache.resize(pcmCache.size()>>1);
pcmCtrlDCCache &= ~0x10; // clear stereo bit
pcmCtrlDCCache&=(unsigned char)~0x10; // clear stereo bit
}
}
}
@ -340,7 +344,7 @@ void DivZSM::flushWrites() {
pcmData.insert(pcmData.end(),pcmCache.begin(),pcmCache.end());
}
pcmCache.clear();
extCmdLen+=2;
extCmd0Len+=2;
// search for a matching PCM instrument definition
for (S_pcmInst& inst: pcmInsts) {
if (inst.offset==pcmOff && inst.length==pcmLen && inst.geometry==pcmCtrlDCCache)
@ -355,14 +359,14 @@ void DivZSM::flushWrites() {
pcmInsts.push_back(inst);
}
}
if (extCmdLen>63) { // this would be bad, but will almost certainly never happen
logE("ZSM: extCmd exceeded maximum length of 63: %d",extCmdLen);
extCmdLen=0;
if (extCmd0Len>63) { // this would be bad, but will almost certainly never happen
logE("ZSM: extCmd 0 exceeded maximum length of 63: %d",extCmd0Len);
extCmd0Len=0;
pcmMeta.clear();
}
if (extCmdLen) { // we have some PCM events to write
w->writeC(0x40);
w->writeC((unsigned char)extCmdLen); // the high two bits are guaranteed to be zero, meaning this is a PCM command
if (extCmd0Len) { // we have some PCM events to write
w->writeC(ZSM_EXT);
w->writeC(ZSM_EXT_PCM|(unsigned char)extCmd0Len);
for (DivRegWrite& write: pcmMeta) {
w->writeC(write.addr);
w->writeC(write.val);
@ -373,6 +377,18 @@ void DivZSM::flushWrites() {
w->writeC((unsigned char)pcmInst&0xff);
}
}
n=0;
while (n<(long)syncCache.size()) { // we have one or more sync events to write
int writes=syncCache.size()-n;
w->writeC(ZSM_EXT);
if (writes>ZSM_SYNC_MAX_WRITES) writes=ZSM_SYNC_MAX_WRITES;
w->writeC(ZSM_EXT_SYNC|(writes<<1));
for (; writes>0; writes--) {
w->writeC(0x00); // 0x00 = Arbitrary sync message
w->writeC(syncCache[n++]);
}
}
syncCache.clear();
numWrites=0;
}