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(
"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.",
{"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"},
@ -1326,7 +1326,7 @@ void DivEngine::registerSystems() {
);
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",
{"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"},
@ -1836,7 +1836,7 @@ void DivEngine::registerSystems() {
);
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.",
{"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"},
@ -1848,7 +1848,7 @@ void DivEngine::registerSystems() {
);
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.",
{"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"},

View File

@ -167,6 +167,7 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
case DIV_SYSTEM_YM2610_EXT:
case DIV_SYSTEM_YM2610_FULL_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
w->writeC(8|baseAddr1);
w->writeC(0x81+i);
@ -356,7 +357,6 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
w->writeC(0xd6+i);
}
break;
// TODO: it's 3:35am
case DIV_SYSTEM_OPL:
case DIV_SYSTEM_OPL_DRUMS:
// disable envelope
@ -381,6 +381,31 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
w->writeC(0);
}
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_DRUMS:
// disable envelope
@ -582,6 +607,21 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
w->writeC(write.addr&0xff);
w->writeC(write.val);
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_DRUMS:
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.val);
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_DRUMS:
w->writeC(0x0a|baseAddr1);
@ -830,7 +876,9 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
bool writeDACSamples=false;
bool writeNESSamples=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;
DivDispatch* writeX1010[2]={NULL,NULL};
DivDispatch* writeQSound[2]={NULL,NULL};
@ -940,11 +988,11 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
if (!hasOPNB) {
hasOPNB=disCont[i].dispatch->chipClock;
willExport[i]=true;
writeADPCM[0]=disCont[i].dispatch;
writeADPCM_OPNB[0]=disCont[i].dispatch;
} else if (!(hasOPNB&0x40000000)) {
isSecond[i]=true;
willExport[i]=true;
writeADPCM[1]=disCont[i].dispatch;
writeADPCM_OPNB[1]=disCont[i].dispatch;
hasOPNB|=0x40000000;
howManyChips++;
}
@ -1045,6 +1093,20 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
howManyChips++;
}
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_DRUMS:
case DIV_SYSTEM_VRC7:
@ -1125,6 +1187,20 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
howManyChips++;
}
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_DRUMS:
if (!hasOPL2) {
@ -1429,27 +1505,55 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version) {
delete[] pcmMem;
}
// ADPCM (OPNA)
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(0x66);
w->writeC(0x82);
w->writeI((writeADPCM[i]->getSampleMemUsage(0)+8)|(i*0x80000000));
w->writeI(writeADPCM[i]->getSampleMemCapacity(0));
w->writeC(0x81);
w->writeI((writeADPCM_OPNA[i]->getSampleMemUsage(0)+8)|(i*0x80000000));
w->writeI(writeADPCM_OPNA[i]->getSampleMemCapacity(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++) {
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(0x66);
w->writeC(0x83);
w->writeI((writeADPCM[i]->getSampleMemUsage(1)+8)|(i*0x80000000));
w->writeI(writeADPCM[i]->getSampleMemCapacity(1));
w->writeI((writeADPCM_OPNB[i]->getSampleMemUsage(1)+8)|(i*0x80000000));
w->writeI(writeADPCM_OPNB[i]->getSampleMemCapacity(1));
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));
}
}