Merge pull request #825 from tildearrow/ymf289b

Prepare to YMF289B OPL3-L support
This commit is contained in:
tildearrow 2023-08-11 23:38:27 -05:00 committed by GitHub
commit 7be0079c62
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 87 additions and 10 deletions

View file

@ -1,4 +1,4 @@
# modification disclaimer # modification disclaimer
this is a modified version of Nuked-OPL3 which implements channel muting in the core. this is a modified version of Nuked-OPL3 which implements channel muting in the core, and resampling function.
see [this issue](https://github.com/tildearrow/furnace/issues/414) for more information. see [this issue](https://github.com/tildearrow/furnace/issues/414) for more information.

5
extern/opl/opl3.c vendored
View file

@ -1362,6 +1362,11 @@ void OPL3_Reset(opl3_chip *chip, uint32_t samplerate)
#endif #endif
} }
void OPL3_Resample(opl3_chip *chip, uint32_t samplerate)
{
chip->rateratio = (samplerate << RSM_FRAC) / 49716;
}
void OPL3_WriteReg(opl3_chip *chip, uint16_t reg, uint8_t v) void OPL3_WriteReg(opl3_chip *chip, uint16_t reg, uint8_t v)
{ {
uint8_t high = (reg >> 8) & 0x01; uint8_t high = (reg >> 8) & 0x01;

1
extern/opl/opl3.h vendored
View file

@ -158,6 +158,7 @@ struct _opl3_chip {
void OPL3_Generate(opl3_chip *chip, int16_t *buf); void OPL3_Generate(opl3_chip *chip, int16_t *buf);
void OPL3_GenerateResampled(opl3_chip *chip, int16_t *buf); void OPL3_GenerateResampled(opl3_chip *chip, int16_t *buf);
void OPL3_Reset(opl3_chip *chip, uint32_t samplerate); void OPL3_Reset(opl3_chip *chip, uint32_t samplerate);
void OPL3_Resample(opl3_chip *chip, uint32_t samplerate);
void OPL3_WriteReg(opl3_chip *chip, uint16_t reg, uint8_t v); void OPL3_WriteReg(opl3_chip *chip, uint16_t reg, uint8_t v);
void OPL3_WriteRegBuffered(opl3_chip *chip, uint16_t reg, uint8_t v); void OPL3_WriteRegBuffered(opl3_chip *chip, uint16_t reg, uint8_t v);
void OPL3_GenerateStream(opl3_chip *chip, int16_t *sndptr, uint32_t numsamples); void OPL3_GenerateStream(opl3_chip *chip, int16_t *sndptr, uint32_t numsamples);

View file

@ -275,11 +275,20 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
if (os[3]>32767) os[3]=32767; if (os[3]>32767) os[3]=32767;
buf[0][h]=os[0]; buf[0][h]=os[0];
if (oplType==3 || oplType==759) { if (totalOutputs>1) {
buf[1][h]=os[1]; buf[1][h]=os[1];
}
if (totalOutputs>2) {
buf[2][h]=os[2]; buf[2][h]=os[2];
}
if (totalOutputs>3) {
buf[3][h]=os[3]; buf[3][h]=os[3];
} }
if (totalOutputs==6) {
// placeholder for OPL4
buf[4][h]=0;
buf[5][h]=0;
}
} }
} }
@ -1590,7 +1599,7 @@ void DivPlatformOPL::reset() {
} }
*/ */
if (downsample) { if (downsample) {
const unsigned int downsampledRate=(unsigned int)((double)rate*rate/chipRateBase); const unsigned int downsampledRate=(unsigned int)((double)rate*round(COLOR_NTSC/72.0)/(double)chipRateBase);
OPL3_Reset(&fm,downsampledRate); OPL3_Reset(&fm,downsampledRate);
} else { } else {
OPL3_Reset(&fm,rate); OPL3_Reset(&fm,rate);
@ -1671,7 +1680,7 @@ void DivPlatformOPL::reset() {
} }
int DivPlatformOPL::getOutputCount() { int DivPlatformOPL::getOutputCount() {
return (oplType==3 || oplType==759)?4:1; return totalOutputs;
} }
bool DivPlatformOPL::keyOffAffectsArp(int ch) { bool DivPlatformOPL::keyOffAffectsArp(int ch) {
@ -1730,6 +1739,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
if (type==8950) { if (type==8950) {
adpcmChan=drums?11:9; adpcmChan=drums?11:9;
} }
totalOutputs=1;
break; break;
case 3: case 4: case 759: case 3: case 4: case 759:
slotsNonDrums=slotsOPL3; slotsNonDrums=slotsOPL3;
@ -1748,6 +1758,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
chipFreqBase=32768*684; chipFreqBase=32768*684;
downsample=true; downsample=true;
} }
totalOutputs=(type==4)?6:4;
break; break;
} }
chipType=type; chipType=type;
@ -1829,14 +1840,36 @@ void DivPlatformOPL::setFlags(const DivConfig& flags) {
case 0x04: case 0x04:
chipClock=15000000.0; chipClock=15000000.0;
break; break;
case 0x05:
chipClock=33868800.0;
break;
default: default:
chipClock=COLOR_NTSC*4.0; chipClock=COLOR_NTSC*4.0;
break; break;
} }
CHECK_CUSTOM_CLOCK; CHECK_CUSTOM_CLOCK;
rate=chipClock/288; switch (flags.getInt("chipType",0)) {
chipRateBase=rate; case 1: // YMF289B
compatPan=flags.getBool("compatPan",false); chipFreqBase=32768*684;
rate=chipClock/768;
chipRateBase=chipClock/684;
downsample=true;
totalOutputs=2; // Stereo output only
break;
default: // YMF262
chipFreqBase=32768*288;
rate=chipClock/288;
chipRateBase=rate;
downsample=false;
totalOutputs=4;
break;
}
if (downsample) {
const unsigned int downsampledRate=(unsigned int)((double)rate*round(COLOR_NTSC/72.0)/(double)chipRateBase);
OPL3_Resample(&fm,downsampledRate);
} else {
OPL3_Resample(&fm,rate);
}
break; break;
case 4: case 4:
switch (flags.getInt("clockSel",0)) { switch (flags.getInt("clockSel",0)) {
@ -1860,6 +1893,7 @@ void DivPlatformOPL::setFlags(const DivConfig& flags) {
chipClock=rate*288; chipClock=rate*288;
break; break;
} }
compatPan=flags.getBool("compatPan",false);
for (int i=0; i<20; i++) { for (int i=0; i<20; i++) {
oscBuf[i]->rate=rate; oscBuf[i]->rate=rate;

View file

@ -82,7 +82,7 @@ class DivPlatformOPL: public DivDispatch {
const unsigned short* chanMap; const unsigned short* chanMap;
const unsigned char* outChanMap; const unsigned char* outChanMap;
int chipFreqBase, chipRateBase; int chipFreqBase, chipRateBase;
int delay, chipType, oplType, chans, melodicChans, totalChans, adpcmChan, sampleBank; int delay, chipType, oplType, chans, melodicChans, totalChans, adpcmChan, sampleBank, totalOutputs;
unsigned char lastBusy; unsigned char lastBusy;
unsigned char drumState; unsigned char drumState;
unsigned char drumVol[5]; unsigned char drumVol[5];

View file

@ -2334,6 +2334,22 @@ void FurnaceGUI::initSystemPresets() {
CH(DIV_SYSTEM_OPL3_DRUMS, 1.0f, 0, "") CH(DIV_SYSTEM_OPL3_DRUMS, 1.0f, 0, "")
} }
); );
ENTRY(
"Yamaha YMF289B (OPL3-L)", {
CH(DIV_SYSTEM_OPL3, 1.0f, 0,
"clockSel=5\n"
"chipType=1\n"
)
}
);
ENTRY(
"Yamaha YMF289B (drums mode)", {
CH(DIV_SYSTEM_OPL3_DRUMS, 1.0f, 0,
"clockSel=5\n"
"chipType=1\n"
)
}
);
if (settings.hiddenSystems) { if (settings.hiddenSystems) {
ENTRY( ENTRY(
"Yamaha YMU759 (MA-2)", { "Yamaha YMU759 (MA-2)", {

View file

@ -1478,6 +1478,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
case DIV_SYSTEM_OPL3: case DIV_SYSTEM_OPL3:
case DIV_SYSTEM_OPL3_DRUMS: { case DIV_SYSTEM_OPL3_DRUMS: {
int clockSel=flags.getInt("clockSel",0); int clockSel=flags.getInt("clockSel",0);
int chipType=flags.getInt("chipType",0);
bool compatPan=flags.getBool("compatPan",false); bool compatPan=flags.getBool("compatPan",false);
ImGui::Text("Clock rate:"); ImGui::Text("Clock rate:");
@ -1502,6 +1503,19 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
clockSel=4; clockSel=4;
altered=true; altered=true;
} }
if (ImGui::RadioButton("33.8688MHz (OPL3-L)",clockSel==5)) {
clockSel=5;
altered=true;
}
ImGui::Text("Chip type:");
if (ImGui::RadioButton("OPL3 (YMF262)",chipType==0)) {
chipType=0;
altered=true;
}
if (ImGui::RadioButton("OPL3-L (YMF289B)",chipType==1)) {
chipType=1;
altered=true;
}
ImGui::Unindent(); ImGui::Unindent();
if (ImGui::Checkbox("Compatible panning (0800)",&compatPan)) { if (ImGui::Checkbox("Compatible panning (0800)",&compatPan)) {
@ -1511,6 +1525,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
if (altered) { if (altered) {
e->lockSave([&]() { e->lockSave([&]() {
flags.set("clockSel",clockSel); flags.set("clockSel",clockSel);
flags.set("chipType",chipType);
flags.set("compatPan",compatPan); flags.set("compatPan",compatPan);
}); });
} }

View file

@ -156,9 +156,15 @@ const char* FurnaceGUI::getSystemPartNumber(DivSystem sys, DivConfig& flags) {
return "YM3812"; return "YM3812";
break; break;
case DIV_SYSTEM_OPL3: case DIV_SYSTEM_OPL3:
case DIV_SYSTEM_OPL3_DRUMS: case DIV_SYSTEM_OPL3_DRUMS:{
return "YMF262"; int chipType=flags.getInt("chipType",0);
if (chipType==1) {
return "YMF289B";
} else {
return "YMF262";
}
break; break;
}
case DIV_SYSTEM_OPL4: case DIV_SYSTEM_OPL4:
case DIV_SYSTEM_OPL4_DRUMS: case DIV_SYSTEM_OPL4_DRUMS:
return "YMF278"; return "YMF278";