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
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.

5
extern/opl/opl3.c vendored
View File

@ -1362,6 +1362,11 @@ void OPL3_Reset(opl3_chip *chip, uint32_t samplerate)
#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)
{
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_GenerateResampled(opl3_chip *chip, int16_t *buf);
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_WriteRegBuffered(opl3_chip *chip, uint16_t reg, uint8_t v);
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;
buf[0][h]=os[0];
if (oplType==3 || oplType==759) {
if (totalOutputs>1) {
buf[1][h]=os[1];
}
if (totalOutputs>2) {
buf[2][h]=os[2];
}
if (totalOutputs>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) {
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);
} else {
OPL3_Reset(&fm,rate);
@ -1671,7 +1680,7 @@ void DivPlatformOPL::reset() {
}
int DivPlatformOPL::getOutputCount() {
return (oplType==3 || oplType==759)?4:1;
return totalOutputs;
}
bool DivPlatformOPL::keyOffAffectsArp(int ch) {
@ -1730,6 +1739,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
if (type==8950) {
adpcmChan=drums?11:9;
}
totalOutputs=1;
break;
case 3: case 4: case 759:
slotsNonDrums=slotsOPL3;
@ -1748,6 +1758,7 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
chipFreqBase=32768*684;
downsample=true;
}
totalOutputs=(type==4)?6:4;
break;
}
chipType=type;
@ -1829,14 +1840,36 @@ void DivPlatformOPL::setFlags(const DivConfig& flags) {
case 0x04:
chipClock=15000000.0;
break;
case 0x05:
chipClock=33868800.0;
break;
default:
chipClock=COLOR_NTSC*4.0;
break;
}
CHECK_CUSTOM_CLOCK;
rate=chipClock/288;
chipRateBase=rate;
compatPan=flags.getBool("compatPan",false);
switch (flags.getInt("chipType",0)) {
case 1: // YMF289B
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;
case 4:
switch (flags.getInt("clockSel",0)) {
@ -1860,6 +1893,7 @@ void DivPlatformOPL::setFlags(const DivConfig& flags) {
chipClock=rate*288;
break;
}
compatPan=flags.getBool("compatPan",false);
for (int i=0; i<20; i++) {
oscBuf[i]->rate=rate;

View File

@ -82,7 +82,7 @@ class DivPlatformOPL: public DivDispatch {
const unsigned short* chanMap;
const unsigned char* outChanMap;
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 drumState;
unsigned char drumVol[5];

View File

@ -2334,6 +2334,22 @@ void FurnaceGUI::initSystemPresets() {
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) {
ENTRY(
"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_DRUMS: {
int clockSel=flags.getInt("clockSel",0);
int chipType=flags.getInt("chipType",0);
bool compatPan=flags.getBool("compatPan",false);
ImGui::Text("Clock rate:");
@ -1502,6 +1503,19 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
clockSel=4;
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();
if (ImGui::Checkbox("Compatible panning (0800)",&compatPan)) {
@ -1511,6 +1525,7 @@ bool FurnaceGUI::drawSysConf(int chan, DivSystem type, DivConfig& flags, bool mo
if (altered) {
e->lockSave([&]() {
flags.set("clockSel",clockSel);
flags.set("chipType",chipType);
flags.set("compatPan",compatPan);
});
}

View File

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