YM2612: implement 9xxx, part 2

VGM export
This commit is contained in:
tildearrow 2023-07-09 17:41:24 -05:00
parent 0c5e58fa3e
commit cf2c63caf7
3 changed files with 95 additions and 15 deletions

View file

@ -489,7 +489,7 @@ class DivEngine {
void processRow(int i, bool afterDelay); void processRow(int i, bool afterDelay);
void nextOrder(); void nextOrder();
void nextRow(); void nextRow();
void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, size_t bankOffset, bool directStream); void performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream);
// returns true if end of song. // returns true if end of song.
bool nextTick(bool noAccum=false, bool inhibitLowLat=false); bool nextTick(bool noAccum=false, bool inhibitLowLat=false);
bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal); bool perSystemEffect(int ch, unsigned char effect, unsigned char effectVal);

View file

@ -932,6 +932,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
if (c.chan<5) c.chan=5; if (c.chan<5) c.chan=5;
chan[c.chan].dacPos=c.value; chan[c.chan].dacPos=c.value;
chan[c.chan].setPos=true; chan[c.chan].setPos=true;
if (dumpWrites) addWrite(0xffff0005,chan[c.chan].dacPos);
break; break;
case DIV_CMD_LEGATO: { case DIV_CMD_LEGATO: {
if (c.chan==csmChan) { if (c.chan==csmChan) {

View file

@ -24,7 +24,7 @@
constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0; constexpr int MASTER_CLOCK_PREC=(sizeof(void*)==8)?8:0;
void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, size_t bankOffset, bool directStream) { void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write, int streamOff, double* loopTimer, double* loopFreq, int* loopSample, bool* sampleDir, bool isSecond, int* pendingFreq, int* playingSample, int* setPos, unsigned int* sampleOff8, unsigned int* sampleLen8, size_t bankOffset, bool directStream) {
unsigned char baseAddr1=isSecond?0xa0:0x50; unsigned char baseAddr1=isSecond?0xa0:0x50;
unsigned char baseAddr2=isSecond?0x80:0; unsigned char baseAddr2=isSecond?0x80:0;
unsigned short baseAddr2S=isSecond?0x8000:0; unsigned short baseAddr2S=isSecond?0x8000:0;
@ -610,15 +610,35 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
pendingFreq[streamID]=write.val; pendingFreq[streamID]=write.val;
} else { } else {
DivSample* sample=song.sample[write.val]; DivSample* sample=song.sample[write.val];
w->writeC(0x95); int pos=sampleOff8[write.val&0xff]+setPos[streamID];
w->writeC(streamID); int len=(int)sampleLen8[write.val&0xff]-setPos[streamID];
w->writeS(write.val); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags if (len<0) len=0;
if (setPos[streamID]!=0) {
if (len<=0) {
w->writeC(0x94);
w->writeC(streamID);
} else {
w->writeC(0x93);
w->writeC(streamID);
w->writeI(pos);
w->writeC(1|((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())?0x80:0)|(sampleDir[streamID]?0x10:0)); // flags
w->writeI(len);
}
} else {
w->writeC(0x95);
w->writeC(streamID);
w->writeS(write.val); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
}
if (sample->isLoopable() && !sampleDir[streamID]) { if (sample->isLoopable() && !sampleDir[streamID]) {
loopTimer[streamID]=sample->length8; loopTimer[streamID]=len;
loopSample[streamID]=write.val; loopSample[streamID]=write.val;
} }
playingSample[streamID]=write.val; playingSample[streamID]=write.val;
setPos[streamID]=0;
} }
} }
break; break;
@ -632,16 +652,36 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
loopFreq[streamID]=realFreq; loopFreq[streamID]=realFreq;
if (pendingFreq[streamID]!=-1) { if (pendingFreq[streamID]!=-1) {
DivSample* sample=song.sample[pendingFreq[streamID]]; DivSample* sample=song.sample[pendingFreq[streamID]];
w->writeC(0x95); int pos=sampleOff8[pendingFreq[streamID]&0xff]+setPos[streamID];
w->writeC(streamID); int len=(int)sampleLen8[pendingFreq[streamID]&0xff]-setPos[streamID];
w->writeS(pendingFreq[streamID]); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags if (len<0) len=0;
if (setPos[streamID]!=0) {
if (len<=0) {
w->writeC(0x94);
w->writeC(streamID);
} else {
w->writeC(0x93);
w->writeC(streamID);
w->writeI(pos);
w->writeC(1|((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())?0x80:0)|(sampleDir[streamID]?0x10:0)); // flags
w->writeI(len);
}
} else {
w->writeC(0x95);
w->writeC(streamID);
w->writeS(pendingFreq[streamID]); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
}
if (sample->isLoopable() && !sampleDir[streamID]) { if (sample->isLoopable() && !sampleDir[streamID]) {
loopTimer[streamID]=sample->length8; loopTimer[streamID]=len;
loopSample[streamID]=pendingFreq[streamID]; loopSample[streamID]=pendingFreq[streamID];
} }
playingSample[streamID]=pendingFreq[streamID]; playingSample[streamID]=pendingFreq[streamID];
pendingFreq[streamID]=-1; pendingFreq[streamID]=-1;
setPos[streamID]=0;
} }
break; break;
} }
@ -655,6 +695,41 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
case 3: // set sample direction case 3: // set sample direction
sampleDir[streamID]=write.val; sampleDir[streamID]=write.val;
break; break;
case 5: // set sample pos
setPos[streamID]=write.val;
if (playingSample[streamID]!=-1 && pendingFreq[streamID]==-1) {
// play the sample again
DivSample* sample=song.sample[playingSample[streamID]];
int pos=sampleOff8[playingSample[streamID]&0xff]+setPos[streamID];
int len=(int)sampleLen8[playingSample[streamID]&0xff]-setPos[streamID];
if (len<0) len=0;
if (setPos[streamID]!=0) {
if (len<=0) {
w->writeC(0x94);
w->writeC(streamID);
} else {
w->writeC(0x93);
w->writeC(streamID);
w->writeI(pos);
w->writeC(1|((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())?0x80:0)|(sampleDir[streamID]?0x10:0)); // flags
w->writeI(len);
}
} else {
w->writeC(0x95);
w->writeC(streamID);
w->writeS(playingSample[streamID]); // sample number
w->writeC((sample->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT)==0 && sample->isLoopable())|(sampleDir[streamID]?0x10:0)); // flags
}
if (sample->isLoopable() && !sampleDir[streamID]) {
loopTimer[streamID]=len;
loopSample[streamID]=playingSample[streamID];
}
}
break;
} }
} }
return; return;
@ -1067,6 +1142,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
int songTick=0; int songTick=0;
unsigned int sampleOff8[256]; unsigned int sampleOff8[256];
unsigned int sampleLen8[256];
unsigned int sampleOffSegaPCM[256]; unsigned int sampleOffSegaPCM[256];
SafeWriter* w=new SafeWriter; SafeWriter* w=new SafeWriter;
@ -1087,6 +1163,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
bool sampleDir[DIV_MAX_CHANS]; bool sampleDir[DIV_MAX_CHANS];
int pendingFreq[DIV_MAX_CHANS]; int pendingFreq[DIV_MAX_CHANS];
int playingSample[DIV_MAX_CHANS]; int playingSample[DIV_MAX_CHANS];
int setPos[DIV_MAX_CHANS];
std::vector<unsigned int> chipVol; std::vector<unsigned int> chipVol;
std::vector<DivDelayedWrite> delayedWrites[DIV_MAX_CHIPS]; std::vector<DivDelayedWrite> delayedWrites[DIV_MAX_CHIPS];
std::vector<std::pair<int,DivDelayedWrite>> sortedWrites; std::vector<std::pair<int,DivDelayedWrite>> sortedWrites;
@ -1106,6 +1183,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
loopSample[i]=-1; loopSample[i]=-1;
pendingFreq[i]=-1; pendingFreq[i]=-1;
playingSample[i]=-1; playingSample[i]=-1;
setPos[i]=0;
sampleDir[i]=false; sampleDir[i]=false;
} }
@ -1363,7 +1441,6 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
willExport[i]=true; willExport[i]=true;
CHIP_VOL(6,1.0); CHIP_VOL(6,1.0);
CHIP_VOL(0x86,1.7); CHIP_VOL(0x86,1.7);
writeDACSamples=true;
} else if (!(hasOPN&0x40000000)) { } else if (!(hasOPN&0x40000000)) {
isSecond[i]=true; isSecond[i]=true;
willExport[i]=true; willExport[i]=true;
@ -1842,6 +1919,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
// initialize sample offsets // initialize sample offsets
memset(sampleOff8,0,256*sizeof(unsigned int)); memset(sampleOff8,0,256*sizeof(unsigned int));
memset(sampleLen8,0,256*sizeof(unsigned int));
memset(sampleOffSegaPCM,0,256*sizeof(unsigned int)); memset(sampleOffSegaPCM,0,256*sizeof(unsigned int));
// write samples // write samples
@ -1850,6 +1928,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
DivSample* sample=song.sample[i]; DivSample* sample=song.sample[i];
logI("setting seek to %d",sampleSeek); logI("setting seek to %d",sampleSeek);
sampleOff8[i]=sampleSeek; sampleOff8[i]=sampleSeek;
sampleLen8[i]=sample->length8;
sampleSeek+=sample->length8; sampleSeek+=sample->length8;
} }
@ -2241,7 +2320,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
for (int i=0; i<song.systemLen; i++) { for (int i=0; i<song.systemLen; i++) {
std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites(); std::vector<DivRegWrite>& writes=disCont[i].dispatch->getRegisterWrites();
for (DivRegWrite& j: writes) { for (DivRegWrite& j: writes) {
performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i],pendingFreq,playingSample,bankOffset[i],directStream); performVGMWrite(w,song.system[i],j,streamIDs[i],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i],directStream);
writeCount++; writeCount++;
} }
writes.clear(); writes.clear();
@ -2281,7 +2360,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
lastOne=i.second.time; lastOne=i.second.time;
} }
// write write // write write
performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,bankOffset[i.first],directStream); performVGMWrite(w,song.system[i.first],i.second.write,streamIDs[i.first],loopTimer,loopFreq,loopSample,sampleDir,isSecond[i.first],pendingFreq,playingSample,setPos,sampleOff8,sampleLen8,bankOffset[i.first],directStream);
// handle global Furnace commands // handle global Furnace commands
writeCount++; writeCount++;