VGM export: implement OPNA and Y8950 (partially)

see #459
This commit is contained in:
tildearrow 2022-05-19 18:09:46 -05:00
parent b01ebb3487
commit 976c1d3c0d
2 changed files with 121 additions and 17 deletions

View File

@ -1314,7 +1314,7 @@ void DivEngine::registerSystems() {
); );
sysDefs[DIV_SYSTEM_PC98]=new DivSysDef( sysDefs[DIV_SYSTEM_PC98]=new DivSysDef(
"Yamaha YM2608 (OPNA)", NULL, 0x8e, 0, 16, true, true, 0, false, "Yamaha YM2608 (OPNA)", NULL, 0x8e, 0, 16, true, true, 0x151, false,
"OPN but twice the FM channels, stereo makes a come-back and has rhythm and ADPCM channels.", "OPN but twice the FM channels, stereo makes a come-back and has rhythm and ADPCM channels.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"}, {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"},
{"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"}, {"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"},
@ -1326,7 +1326,7 @@ void DivEngine::registerSystems() {
); );
sysDefs[DIV_SYSTEM_PC98_EXT]=new DivSysDef( sysDefs[DIV_SYSTEM_PC98_EXT]=new DivSysDef(
"Yamaha YM2608 (OPNA) Extended Channel 3", NULL, 0xb7, 0, 19, true, true, 0, false, "Yamaha YM2608 (OPNA) Extended Channel 3", NULL, 0xb7, 0, 19, true, true, 0x151, false,
"OPN but twice the FM channels, stereo makes a come-back and has rhythm and ADPCM channels.\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies", "OPN but twice the FM channels, stereo makes a come-back and has rhythm and ADPCM channels.\nthis one is in Extended Channel mode, which turns the second FM channel into four operators with independent notes/frequencies",
{"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"}, {"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"},
{"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"}, {"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"},
@ -1836,7 +1836,7 @@ void DivEngine::registerSystems() {
); );
sysDefs[DIV_SYSTEM_Y8950]=new DivSysDef( sysDefs[DIV_SYSTEM_Y8950]=new DivSysDef(
"Yamaha Y8950", NULL, 0xb2, 0, 10, true, false, 0, false, "Yamaha Y8950", NULL, 0xb2, 0, 10, true, false, 0x151, false,
"like OPL but with an ADPCM channel.", "like OPL but with an ADPCM channel.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "PCM"}, {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9", "PCM"},
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "PCM"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "PCM"},
@ -1848,7 +1848,7 @@ void DivEngine::registerSystems() {
); );
sysDefs[DIV_SYSTEM_Y8950_DRUMS]=new DivSysDef( sysDefs[DIV_SYSTEM_Y8950_DRUMS]=new DivSysDef(
"Yamaha Y8950 with drums", NULL, 0xb3, 0, 12, true, false, 0, false, "Yamaha Y8950 with drums", NULL, 0xb3, 0, 12, true, false, 0x151, false,
"the Y8950 chip, in drums mode.", "the Y8950 chip, in drums mode.",
{"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat", "PCM"}, {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat", "PCM"},
{"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "PCM"}, {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH", "PCM"},

View File

@ -167,6 +167,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
case DIV_SYSTEM_YM2610_EXT: case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_YM2610_FULL_EXT: case DIV_SYSTEM_YM2610_FULL_EXT:
case DIV_SYSTEM_YM2610B_EXT: case DIV_SYSTEM_YM2610B_EXT:
// TODO: YM2610B channels 1 and 4 and ADPCM-B
for (int i=0; i<2; i++) { // set SL and RR to highest for (int i=0; i<2; i++) { // set SL and RR to highest
w->writeC(8|baseAddr1); w->writeC(8|baseAddr1);
w->writeC(0x81+i); w->writeC(0x81+i);
@ -356,7 +357,6 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
w->writeC(0xd6+i); w->writeC(0xd6+i);
} }
break; break;
// TODO: it's 3:35am
case DIV_SYSTEM_OPL: case DIV_SYSTEM_OPL:
case DIV_SYSTEM_OPL_DRUMS: case DIV_SYSTEM_OPL_DRUMS:
// disable envelope // disable envelope
@ -381,6 +381,31 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
w->writeC(0); w->writeC(0);
} }
break; break;
case DIV_SYSTEM_Y8950:
case DIV_SYSTEM_Y8950_DRUMS:
// disable envelope
for (int i=0; i<6; i++) {
w->writeC(0x0b|baseAddr1);
w->writeC(0x80+i);
w->writeC(0x0f);
w->writeC(0x0b|baseAddr1);
w->writeC(0x88+i);
w->writeC(0x0f);
w->writeC(0x0b|baseAddr1);
w->writeC(0x90+i);
w->writeC(0x0f);
}
// key off + freq reset
for (int i=0; i<9; i++) {
w->writeC(0x0b|baseAddr1);
w->writeC(0xa0+i);
w->writeC(0);
w->writeC(0x0b|baseAddr1);
w->writeC(0xb0+i);
w->writeC(0);
}
// TODO: ADPCM
break;
case DIV_SYSTEM_OPL2: case DIV_SYSTEM_OPL2:
case DIV_SYSTEM_OPL2_DRUMS: case DIV_SYSTEM_OPL2_DRUMS:
// disable envelope // disable envelope
@ -582,6 +607,21 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
w->writeC(write.addr&0xff); w->writeC(write.addr&0xff);
w->writeC(write.val); w->writeC(write.val);
break; break;
case DIV_SYSTEM_PC98:
case DIV_SYSTEM_PC98_EXT:
switch (write.addr>>8) {
case 0: // port 0
w->writeC(6|baseAddr1);
w->writeC(write.addr&0xff);
w->writeC(write.val);
break;
case 1: // port 1
w->writeC(7|baseAddr1);
w->writeC(write.addr&0xff);
w->writeC(write.val);
break;
}
break;
case DIV_SYSTEM_OPLL: case DIV_SYSTEM_OPLL:
case DIV_SYSTEM_OPLL_DRUMS: case DIV_SYSTEM_OPLL_DRUMS:
case DIV_SYSTEM_VRC7: case DIV_SYSTEM_VRC7:
@ -629,6 +669,12 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
w->writeC(write.addr&0xff); w->writeC(write.addr&0xff);
w->writeC(write.val); w->writeC(write.val);
break; break;
case DIV_SYSTEM_Y8950:
case DIV_SYSTEM_Y8950_DRUMS:
w->writeC(0x0c|baseAddr1);
w->writeC(write.addr&0xff);
w->writeC(write.val);
break;
case DIV_SYSTEM_OPL2: case DIV_SYSTEM_OPL2:
case DIV_SYSTEM_OPL2_DRUMS: case DIV_SYSTEM_OPL2_DRUMS:
w->writeC(0x0a|baseAddr1); w->writeC(0x0a|baseAddr1);
@ -830,7 +876,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
bool writeDACSamples=false; bool writeDACSamples=false;
bool writeNESSamples=false; bool writeNESSamples=false;
bool writePCESamples=false; bool writePCESamples=false;
DivDispatch* writeADPCM[2]={NULL,NULL}; DivDispatch* writeADPCM_OPNA[2]={NULL,NULL};
DivDispatch* writeADPCM_OPNB[2]={NULL,NULL};
DivDispatch* writeADPCM_Y8950[2]={NULL,NULL};
int writeSegaPCM=0; int writeSegaPCM=0;
DivDispatch* writeX1010[2]={NULL,NULL}; DivDispatch* writeX1010[2]={NULL,NULL};
DivDispatch* writeQSound[2]={NULL,NULL}; DivDispatch* writeQSound[2]={NULL,NULL};
@ -940,11 +988,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
if (!hasOPNB) { if (!hasOPNB) {
hasOPNB=disCont[i].dispatch->chipClock; hasOPNB=disCont[i].dispatch->chipClock;
willExport[i]=true; willExport[i]=true;
writeADPCM[0]=disCont[i].dispatch; writeADPCM_OPNB[0]=disCont[i].dispatch;
} else if (!(hasOPNB&0x40000000)) { } else if (!(hasOPNB&0x40000000)) {
isSecond[i]=true; isSecond[i]=true;
willExport[i]=true; willExport[i]=true;
writeADPCM[1]=disCont[i].dispatch; writeADPCM_OPNB[1]=disCont[i].dispatch;
hasOPNB|=0x40000000; hasOPNB|=0x40000000;
howManyChips++; howManyChips++;
} }
@ -1045,6 +1093,20 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
howManyChips++; howManyChips++;
} }
break; break;
case DIV_SYSTEM_PC98:
case DIV_SYSTEM_PC98_EXT:
if (!hasOPNA) {
hasOPNA=disCont[i].dispatch->chipClock;
willExport[i]=true;
writeADPCM_OPNA[0]=disCont[i].dispatch;
} else if (!(hasOPNA&0x40000000)) {
isSecond[i]=true;
willExport[i]=true;
writeADPCM_OPNA[1]=disCont[i].dispatch;
hasOPNA|=0x40000000;
howManyChips++;
}
break;
case DIV_SYSTEM_OPLL: case DIV_SYSTEM_OPLL:
case DIV_SYSTEM_OPLL_DRUMS: case DIV_SYSTEM_OPLL_DRUMS:
case DIV_SYSTEM_VRC7: case DIV_SYSTEM_VRC7:
@ -1125,6 +1187,20 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
howManyChips++; howManyChips++;
} }
break; break;
case DIV_SYSTEM_Y8950:
case DIV_SYSTEM_Y8950_DRUMS:
if (!hasY8950) {
hasY8950=disCont[i].dispatch->chipClock;
willExport[i]=true;
writeADPCM_Y8950[0]=disCont[i].dispatch;
} else if (!(hasY8950&0x40000000)) {
isSecond[i]=true;
willExport[i]=true;
writeADPCM_Y8950[1]=disCont[i].dispatch;
hasY8950|=0x40000000;
howManyChips++;
}
break;
case DIV_SYSTEM_OPL2: case DIV_SYSTEM_OPL2:
case DIV_SYSTEM_OPL2_DRUMS: case DIV_SYSTEM_OPL2_DRUMS:
if (!hasOPL2) { if (!hasOPL2) {
@ -1429,27 +1505,55 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
delete[] pcmMem; delete[] pcmMem;
} }
// ADPCM (OPNA)
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
if (writeADPCM[i]!=NULL && writeADPCM[i]->getSampleMemUsage(0)>0) { if (writeADPCM_OPNA[i]!=NULL && writeADPCM_OPNA[i]->getSampleMemUsage(0)>0) {
w->writeC(0x67); w->writeC(0x67);
w->writeC(0x66); w->writeC(0x66);
w->writeC(0x82); w->writeC(0x81);
w->writeI((writeADPCM[i]->getSampleMemUsage(0)+8)|(i*0x80000000)); w->writeI((writeADPCM_OPNA[i]->getSampleMemUsage(0)+8)|(i*0x80000000));
w->writeI(writeADPCM[i]->getSampleMemCapacity(0)); w->writeI(writeADPCM_OPNA[i]->getSampleMemCapacity(0));
w->writeI(0); w->writeI(0);
w->write(writeADPCM[i]->getSampleMem(0),writeADPCM[i]->getSampleMemUsage(0)); w->write(writeADPCM_OPNA[i]->getSampleMem(0),writeADPCM_OPNA[i]->getSampleMemUsage(0));
} }
} }
// ADPCM-A (OPNB)
for (int i=0; i<2; i++) { for (int i=0; i<2; i++) {
if (writeADPCM[i]!=NULL && writeADPCM[i]->getSampleMemUsage(1)>0) { if (writeADPCM_OPNB[i]!=NULL && writeADPCM_OPNB[i]->getSampleMemUsage(0)>0) {
w->writeC(0x67);
w->writeC(0x66);
w->writeC(0x82);
w->writeI((writeADPCM_OPNB[i]->getSampleMemUsage(0)+8)|(i*0x80000000));
w->writeI(writeADPCM_OPNB[i]->getSampleMemCapacity(0));
w->writeI(0);
w->write(writeADPCM_OPNB[i]->getSampleMem(0),writeADPCM_OPNB[i]->getSampleMemUsage(0));
}
}
// ADPCM-B (OPNB)
for (int i=0; i<2; i++) {
if (writeADPCM_OPNB[i]!=NULL && writeADPCM_OPNB[i]->getSampleMemUsage(1)>0) {
w->writeC(0x67); w->writeC(0x67);
w->writeC(0x66); w->writeC(0x66);
w->writeC(0x83); w->writeC(0x83);
w->writeI((writeADPCM[i]->getSampleMemUsage(1)+8)|(i*0x80000000)); w->writeI((writeADPCM_OPNB[i]->getSampleMemUsage(1)+8)|(i*0x80000000));
w->writeI(writeADPCM[i]->getSampleMemCapacity(1)); w->writeI(writeADPCM_OPNB[i]->getSampleMemCapacity(1));
w->writeI(0); w->writeI(0);
w->write(writeADPCM[i]->getSampleMem(1),writeADPCM[i]->getSampleMemUsage(1)); w->write(writeADPCM_OPNB[i]->getSampleMem(1),writeADPCM_OPNB[i]->getSampleMemUsage(1));
}
}
// ADPCM (Y8950)
for (int i=0; i<2; i++) {
if (writeADPCM_Y8950[i]!=NULL && writeADPCM_Y8950[i]->getSampleMemUsage(0)>0) {
w->writeC(0x67);
w->writeC(0x66);
w->writeC(0x88);
w->writeI((writeADPCM_Y8950[i]->getSampleMemUsage(0)+8)|(i*0x80000000));
w->writeI(writeADPCM_Y8950[i]->getSampleMemCapacity(0));
w->writeI(0);
w->write(writeADPCM_Y8950[i]->getSampleMem(0),writeADPCM_Y8950[i]->getSampleMemUsage(0));
} }
} }