mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-23 21:15:11 +00:00
YM2612: implement 9xxx, part 2
VGM export
This commit is contained in:
parent
0c5e58fa3e
commit
cf2c63caf7
3 changed files with 95 additions and 15 deletions
|
@ -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);
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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++;
|
||||||
|
|
Loading…
Reference in a new issue