OPL: ymfm core, part 1

This commit is contained in:
tildearrow 2023-11-22 19:28:36 -05:00
parent 1bcdedda3e
commit 955682b240
9 changed files with 467 additions and 29 deletions

View file

@ -489,6 +489,8 @@ extern/Nuked-PSG/ympsg.c
extern/opm/opm.c
extern/Nuked-OPLL/opll.c
extern/opl/opl3.c
extern/YM3812-LLE/fmopl2.c
extern/YMF262-LLE/fmopl3.c
src/pch.cpp

View file

@ -427,34 +427,74 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
case DIV_SYSTEM_OPL:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(1,false);
if (isRender) {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl2CoreRender",0));
} else {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl2Core",0));
}
break;
case DIV_SYSTEM_OPL_DRUMS:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(1,true);
if (isRender) {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl2CoreRender",0));
} else {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl2Core",0));
}
break;
case DIV_SYSTEM_OPL2:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(2,false);
if (isRender) {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl2CoreRender",0));
} else {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl2Core",0));
}
break;
case DIV_SYSTEM_OPL2_DRUMS:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(2,true);
if (isRender) {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl2CoreRender",0));
} else {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl2Core",0));
}
break;
case DIV_SYSTEM_OPL3:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(3,false);
if (isRender) {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl3CoreRender",0));
} else {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl3Core",0));
}
break;
case DIV_SYSTEM_OPL3_DRUMS:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(3,true);
if (isRender) {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl3CoreRender",0));
} else {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl3Core",0));
}
break;
case DIV_SYSTEM_Y8950:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(8950,false);
if (isRender) {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl2CoreRender",0));
} else {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl2Core",0));
}
break;
case DIV_SYSTEM_Y8950_DRUMS:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(8950,true);
if (isRender) {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl2CoreRender",0));
} else {
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl2Core",0));
}
break;
case DIV_SYSTEM_OPZ:
dispatch=new DivPlatformTX81Z;

View file

@ -292,12 +292,252 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
}
}
void DivPlatformOPL::acquire_ymfm1(short** buf, size_t len) {
ymfm::ymfm_output<1> out;
ymfm::ym3526::fm_engine* fme=fm_ymfm1->debug_fm_engine();
ymfm::fm_channel<ymfm::opl_registers_base<1>>* fmChan[9];
for (int i=0; i<9; i++) {
fmChan[i]=fme->debug_channel(i);
}
for (size_t h=0; h<len; h++) {
if (!writes.empty() && --delay<0) {
delay=1;
QueuedWrite& w=writes.front();
fm_ymfm1->write(0,w.addr);
fm_ymfm1->write(1,w.val);
regPool[w.addr&511]=w.val;
writes.pop();
}
fm_ymfm1->generate(&out,1);
buf[0][h]=out.data[0];
if (properDrums) {
for (int i=0; i<7; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fmChan[i]->debug_output(0)<<2,-32768,32767);
}
oscBuf[7]->data[oscBuf[7]->needle++]=CLAMP(fmChan[7]->debug_special1()<<2,-32768,32767);
oscBuf[8]->data[oscBuf[8]->needle++]=CLAMP(fmChan[8]->debug_special1()<<2,-32768,32767);
oscBuf[9]->data[oscBuf[9]->needle++]=CLAMP(fmChan[8]->debug_special2()<<2,-32768,32767);
oscBuf[10]->data[oscBuf[10]->needle++]=CLAMP(fmChan[7]->debug_special2()<<2,-32768,32767);
} else {
for (int i=0; i<9; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fmChan[i]->debug_output(0)<<2,-32768,32767);
}
}
}
}
void DivPlatformOPL::acquire_ymfm2(short** buf, size_t len) {
ymfm::ymfm_output<1> out;
ymfm::ym3812::fm_engine* fme=fm_ymfm2->debug_fm_engine();
ymfm::fm_channel<ymfm::opl_registers_base<2>>* fmChan[9];
for (int i=0; i<9; i++) {
fmChan[i]=fme->debug_channel(i);
}
for (size_t h=0; h<len; h++) {
if (!writes.empty() && --delay<0) {
delay=1;
QueuedWrite& w=writes.front();
fm_ymfm2->write(0,w.addr);
fm_ymfm2->write(1,w.val);
regPool[w.addr&511]=w.val;
writes.pop();
}
fm_ymfm2->generate(&out,1);
buf[0][h]=out.data[0];
if (properDrums) {
for (int i=0; i<7; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fmChan[i]->debug_output(0)<<2,-32768,32767);
}
oscBuf[7]->data[oscBuf[7]->needle++]=CLAMP(fmChan[7]->debug_special1()<<2,-32768,32767);
oscBuf[8]->data[oscBuf[8]->needle++]=CLAMP(fmChan[8]->debug_special1()<<2,-32768,32767);
oscBuf[9]->data[oscBuf[9]->needle++]=CLAMP(fmChan[8]->debug_special2()<<2,-32768,32767);
oscBuf[10]->data[oscBuf[10]->needle++]=CLAMP(fmChan[7]->debug_special2()<<2,-32768,32767);
} else {
for (int i=0; i<9; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fmChan[i]->debug_output(0)<<2,-32768,32767);
}
}
}
}
// TODO: ADPCM
void DivPlatformOPL::acquire_ymfm8950(short** buf, size_t len) {
ymfm::ymfm_output<1> out;
ymfm::y8950::fm_engine* fme=fm_ymfm8950->debug_fm_engine();
ymfm::fm_channel<ymfm::opl_registers_base<1>>* fmChan[9];
for (int i=0; i<9; i++) {
fmChan[i]=fme->debug_channel(i);
}
for (size_t h=0; h<len; h++) {
if (!writes.empty() && --delay<0) {
delay=1;
QueuedWrite& w=writes.front();
fm_ymfm8950->write(0,w.addr);
fm_ymfm8950->write(1,w.val);
regPool[w.addr&511]=w.val;
writes.pop();
}
fm_ymfm8950->generate(&out,1);
buf[0][h]=out.data[0];
if (properDrums) {
for (int i=0; i<7; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fmChan[i]->debug_output(0)<<2,-32768,32767);
}
oscBuf[7]->data[oscBuf[7]->needle++]=CLAMP(fmChan[7]->debug_special1()<<2,-32768,32767);
oscBuf[8]->data[oscBuf[8]->needle++]=CLAMP(fmChan[8]->debug_special1()<<2,-32768,32767);
oscBuf[9]->data[oscBuf[9]->needle++]=CLAMP(fmChan[8]->debug_special2()<<2,-32768,32767);
oscBuf[10]->data[oscBuf[10]->needle++]=CLAMP(fmChan[7]->debug_special2()<<2,-32768,32767);
} else {
for (int i=0; i<9; i++) {
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(fmChan[i]->debug_output(0)<<2,-32768,32767);
}
}
}
}
void DivPlatformOPL::acquire_ymfm3(short** buf, size_t len) {
ymfm::ymfm_output<4> out;
ymfm::ymf262::fm_engine* fme=fm_ymfm3->debug_fm_engine();
ymfm::fm_channel<ymfm::opl_registers_base<3>>* fmChan[18];
for (int i=0; i<18; i++) {
fmChan[i]=fme->debug_channel(i);
}
for (size_t h=0; h<len; h++) {
if (!writes.empty() && --delay<0) {
delay=1;
QueuedWrite& w=writes.front();
fm_ymfm3->write((w.addr&0x100)?2:0,w.addr);
fm_ymfm3->write(1,w.val);
regPool[w.addr&511]=w.val;
writes.pop();
}
fm_ymfm3->generate(&out,1);
buf[0][h]=out.data[0]>>1;
if (totalOutputs>1) {
buf[1][h]=out.data[1]>>1;
}
if (totalOutputs>2) {
buf[2][h]=out.data[2]>>1;
}
if (totalOutputs>3) {
buf[3][h]=out.data[3]>>1;
}
if (totalOutputs==6) {
// placeholder for OPL4
buf[4][h]=0;
buf[5][h]=0;
}
// TODO: fix 4-op view
if (properDrums) {
for (int i=0; i<16; i++) {
unsigned char ch=outChanMap[i];
if (ch==255) continue;
int chOut=fmChan[ch]->debug_output(0);
if (chOut==0) {
chOut=fmChan[ch]->debug_output(1);
}
if (chOut==0) {
chOut=fmChan[ch]->debug_output(2);
}
if (chOut==0) {
chOut=fmChan[ch]->debug_output(3);
}
if (i==15) {
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut,-32768,32767);
} else {
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut<<1,-32768,32767);
}
}
oscBuf[16]->data[oscBuf[16]->needle++]=CLAMP(fmChan[7]->debug_special2()<<1,-32768,32767);
oscBuf[17]->data[oscBuf[17]->needle++]=CLAMP(fmChan[8]->debug_special1()<<1,-32768,32767);
oscBuf[18]->data[oscBuf[18]->needle++]=CLAMP(fmChan[8]->debug_special2()<<1,-32768,32767);
oscBuf[19]->data[oscBuf[19]->needle++]=CLAMP(fmChan[7]->debug_special1()<<1,-32768,32767);
} else {
for (int i=0; i<18; i++) {
unsigned char ch=outChanMap[i];
if (ch==255) continue;
int chOut=fmChan[ch]->debug_output(0);
if (chOut==0) {
chOut=fmChan[ch]->debug_output(1);
}
if (chOut==0) {
chOut=fmChan[ch]->debug_output(2);
}
if (chOut==0) {
chOut=fmChan[ch]->debug_output(3);
}
oscBuf[i]->data[oscBuf[i]->needle++]=CLAMP(chOut<<1,-32768,32767);
}
}
}
}
void DivPlatformOPL::acquire_nukedLLE2(short** buf, size_t len) {
}
void DivPlatformOPL::acquire_nukedLLE3(short** buf, size_t len) {
}
void DivPlatformOPL::acquire(short** buf, size_t len) {
//if (useYMFM) {
// acquire_ymfm(buf,len);
//} else {
if (emuCore==2) { // LLE
switch (chipType) {
case 1: case 2: case 8950:
acquire_nukedLLE2(buf,len);
break;
case 3: case 759:
acquire_nukedLLE3(buf,len);
break;
}
} else if (emuCore==1) { // ymfm
switch (chipType) {
case 1:
acquire_ymfm1(buf,len);
break;
case 2:
acquire_ymfm2(buf,len);
break;
case 8950:
acquire_ymfm8950(buf,len);
break;
case 3: case 759:
acquire_ymfm3(buf,len);
break;
}
} else { // OPL3
acquire_nuked(buf,len);
//}
}
}
double DivPlatformOPL::NOTE_ADPCMB(int note) {
@ -1620,17 +1860,34 @@ int DivPlatformOPL::getRegisterPoolSize() {
void DivPlatformOPL::reset() {
while (!writes.empty()) writes.pop();
memset(regPool,0,512);
/*
if (useYMFM) {
fm_ymfm->reset();
}
*/
if (downsample) {
const unsigned int downsampledRate=(unsigned int)((double)rate*round(COLOR_NTSC/72.0)/(double)chipRateBase);
OPL3_Reset(&fm,downsampledRate);
const unsigned int downsampledRate=(unsigned int)((double)rate*round(COLOR_NTSC/72.0)/(double)chipRateBase);
if (emuCore==2) {
// TODO: LLE reset
} else if (emuCore==1) {
switch (chipType) {
case 1:
fm_ymfm1->reset();
break;
case 2:
fm_ymfm2->reset();
break;
case 8950:
fm_ymfm8950->reset();
break;
case 3: case 759:
fm_ymfm3->reset();
break;
}
} else {
OPL3_Reset(&fm,rate);
if (downsample) {
OPL3_Reset(&fm,downsampledRate);
} else {
OPL3_Reset(&fm,rate);
}
}
if (dumpWrites) {
addWrite(0xffffffff,0);
}
@ -1744,8 +2001,8 @@ int DivPlatformOPL::getPortaFloor(int ch) {
return (ch>5)?12:0;
}
void DivPlatformOPL::setYMFM(bool use) {
useYMFM=use;
void DivPlatformOPL::setCore(unsigned char which) {
emuCore=which;
}
void DivPlatformOPL::setOPLType(int type, bool drums) {
@ -1891,11 +2148,13 @@ void DivPlatformOPL::setFlags(const DivConfig& flags) {
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);
if (emuCore!=1 && emuCore!=2) {
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:
@ -1990,6 +2249,29 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, const DivConfi
for (int i=0; i<20; i++) {
oscBuf[i]=new DivDispatchOscBuffer;
}
fm_ymfm1=NULL;
fm_ymfm2=NULL;
fm_ymfm8950=NULL;
fm_ymfm3=NULL;
if (emuCore==1) {
switch (chipType) {
case 1:
fm_ymfm1=new ymfm::ym3526(iface);
break;
case 2:
fm_ymfm2=new ymfm::ym3812(iface);
break;
case 8950:
fm_ymfm8950=new ymfm::y8950(iface);
break;
case 3: case 759:
fm_ymfm3=new ymfm::ymf262(iface);
break;
}
}
setFlags(flags);
if (adpcmChan>=0) {
@ -2012,6 +2294,22 @@ void DivPlatformOPL::quit() {
delete adpcmB;
delete[] adpcmBMem;
}
if (fm_ymfm1!=NULL) {
delete fm_ymfm1;
fm_ymfm1=NULL;
}
if (fm_ymfm2!=NULL) {
delete fm_ymfm2;
fm_ymfm2=NULL;
}
if (fm_ymfm8950!=NULL) {
delete fm_ymfm8950;
fm_ymfm8950=NULL;
}
if (fm_ymfm3!=NULL) {
delete fm_ymfm3;
fm_ymfm3=NULL;
}
}
DivPlatformOPL::~DivPlatformOPL() {

View file

@ -23,7 +23,12 @@
#include "../dispatch.h"
#include "../../fixedQueue.h"
#include "../../../extern/opl/opl3.h"
extern "C" {
#include "../../../extern/YM3812-LLE/fmopl2.h"
#include "../../../extern/YMF262-LLE/fmopl3.h"
}
#include "sound/ymfm/ymfm_adpcm.h"
#include "sound/ymfm/ymfm_opl.h"
class DivOPLAInterface: public ymfm::ymfm_interface {
public:
@ -68,7 +73,7 @@ class DivPlatformOPL: public DivDispatch {
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
};
FixedQueue<QueuedWrite,2048> writes;
opl3_chip fm;
unsigned char* adpcmBMem;
size_t adpcmBMemLen;
DivOPLAInterface iface;
@ -93,11 +98,25 @@ class DivPlatformOPL: public DivDispatch {
unsigned char lfoValue;
bool useYMFM, update4OpMask, pretendYMU, downsample, compatPan;
// 0: Nuked-OPL3
// 1: ymfm
// 2: YM3812-LLE/YMF262-LLE
unsigned char emuCore;
bool update4OpMask, pretendYMU, downsample, compatPan;
short oldWrites[512];
short pendingWrites[512];
// chips
opl3_chip fm;
ymfm::ym3526* fm_ymfm1;
ymfm::ym3812* fm_ymfm2;
ymfm::y8950* fm_ymfm8950;
ymfm::ymf262* fm_ymfm3;
fmopl2_t fm_lle2;
fmopl3_t fm_lle3;
int octave(int freq);
int toFreq(int freq);
double NOTE_ADPCMB(int note);
@ -106,8 +125,13 @@ class DivPlatformOPL: public DivDispatch {
friend void putDispatchChip(void*,int);
friend void putDispatchChan(void*,int,int);
void acquire_nukedLLE2(short** buf, size_t len);
void acquire_nukedLLE3(short** buf, size_t len);
void acquire_nuked(short** buf, size_t len);
//void acquire_ymfm(short** buf, size_t len);
void acquire_ymfm3(short** buf, size_t len);
void acquire_ymfm8950(short** buf, size_t len);
void acquire_ymfm2(short** buf, size_t len);
void acquire_ymfm1(short** buf, size_t len);
public:
void acquire(short** buf, size_t len);
@ -124,7 +148,7 @@ class DivPlatformOPL: public DivDispatch {
void tick(bool sysTick=true);
void muteChannel(int ch, bool mute);
int getOutputCount();
void setYMFM(bool use);
void setCore(unsigned char which);
void setOPLType(int type, bool drums);
bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch);

View file

@ -305,6 +305,8 @@ public:
// simple getters for debugging
fm_operator<RegisterType> *debug_operator(uint32_t index) const { return m_op[index]; }
int32_t debug_output(uint32_t index) const { return m_output[index]; }
int32_t debug_special1() const { return m_special1; }
int32_t debug_special2() const { return m_special2; }
private:
// helper to add values to the outputs based on channel enables
@ -343,6 +345,8 @@ private:
RegisterType &m_regs; // direct reference to registers
fm_engine_base<RegisterType> &m_owner; // reference to the owning engine
mutable int32_t m_output[4];
mutable int32_t m_special1;
mutable int32_t m_special2;
};

View file

@ -808,7 +808,9 @@ fm_channel<RegisterType>::fm_channel(fm_engine_base<RegisterType> &owner, uint32
m_op{ nullptr, nullptr, nullptr, nullptr },
m_regs(owner.regs()),
m_owner(owner),
m_output{ 0, 0, 0, 0 }
m_output{ 0, 0, 0, 0 },
m_special1(0),
m_special2(0)
{
}
@ -1139,13 +1141,13 @@ void fm_channel<RegisterType>::output_rhythm_ch7(uint32_t phase_select, output_d
// and a combination of noise and the operator 13/17 phase select
// to compute the phase
uint32_t phase = (phase_select << 9) | (0xd0 >> (2 * (noise_state ^ phase_select)));
int32_t result = m_op[0]->compute_volume(phase, am_offset) >> rshift;
int32_t result = m_special1 = m_op[0]->compute_volume(phase, am_offset) >> rshift;
// Snare Drum: this uses the envelope from operator 16 (channel 7),
// and a combination of noise and operator 13 phase to pick a phase
uint32_t op13phase = m_op[0]->phase();
phase = (0x100 << bitfield(op13phase, 8)) ^ (noise_state << 8);
result += m_op[1]->compute_volume(phase, am_offset) >> rshift;
result += m_special2 = m_op[1]->compute_volume(phase, am_offset) >> rshift;
result = clamp(result, -clipmax - 1, clipmax);
// add to the output
@ -1166,12 +1168,12 @@ void fm_channel<RegisterType>::output_rhythm_ch8(uint32_t phase_select, output_d
uint32_t am_offset = m_regs.lfo_am_offset(m_choffs);
// Tom Tom: this is just a single operator processed normally
int32_t result = m_op[0]->compute_volume(m_op[0]->phase(), am_offset) >> rshift;
int32_t result = m_special1 = m_op[0]->compute_volume(m_op[0]->phase(), am_offset) >> rshift;
// Top Cymbal: this uses the envelope from operator 17 (channel 8),
// and the operator 13/17 phase select to compute the phase
uint32_t phase = 0x100 | (phase_select << 9);
result += m_op[1]->compute_volume(phase, am_offset) >> rshift;
result += m_special2 = m_op[1]->compute_volume(phase, am_offset) >> rshift;
result = clamp(result, -clipmax - 1, clipmax);
// add to the output

View file

@ -528,6 +528,8 @@ public:
// generate samples of sound
void generate(output_data *output, uint32_t numsamples = 1);
fm_engine* debug_fm_engine() { return &m_fm; }
protected:
// internal state
uint8_t m_address; // address register
@ -575,6 +577,9 @@ public:
// generate samples of sound
void generate(output_data *output, uint32_t numsamples = 1);
fm_engine* debug_fm_engine() { return &m_fm; }
adpcm_b_engine* debug_adpcm_b_engine() { return &m_adpcm_b; }
protected:
// internal state
uint8_t m_address; // address register
@ -623,6 +628,8 @@ public:
// generate samples of sound
void generate(output_data *output, uint32_t numsamples = 1);
fm_engine* debug_fm_engine() { return &m_fm; }
protected:
// internal state
uint8_t m_address; // address register
@ -670,6 +677,8 @@ public:
// generate samples of sound
void generate(output_data *output, uint32_t numsamples = 1);
fm_engine* debug_fm_engine() { return &m_fm; }
protected:
// internal state
uint16_t m_address; // address register

View file

@ -1476,6 +1476,8 @@ class FurnaceGUI {
int c64Core;
int pokeyCore;
int opnCore;
int opl2Core;
int opl3Core;
int arcadeCoreRender;
int ym2612CoreRender;
int snCoreRender;
@ -1484,6 +1486,8 @@ class FurnaceGUI {
int c64CoreRender;
int pokeyCoreRender;
int opnCoreRender;
int opl2CoreRender;
int opl3CoreRender;
int pcSpeakerOutMethod;
String yrw801Path;
String tg100Path;
@ -1669,6 +1673,8 @@ class FurnaceGUI {
c64Core(0),
pokeyCore(1),
opnCore(1),
opl2Core(0),
opl3Core(0),
arcadeCoreRender(1),
ym2612CoreRender(0),
snCoreRender(0),
@ -1677,6 +1683,8 @@ class FurnaceGUI {
c64CoreRender(1),
pokeyCoreRender(1),
opnCoreRender(1),
opl2CoreRender(0),
opl3CoreRender(0),
pcSpeakerOutMethod(0),
yrw801Path(""),
tg100Path(""),

View file

@ -156,6 +156,18 @@ const char* opnCores[]={
"Nuked-OPN2 (FM) + ymfm (SSG/ADPCM)"
};
const char* opl2Cores[]={
"Nuked-OPL3",
"ymfm",
"YM3812-LLE"
};
const char* opl3Cores[]={
"Nuked-OPL3",
"ymfm",
"YMF262-LLE"
};
const char* pcspkrOutMethods[]={
"evdev SND_TONE",
"KIOCSOUND on /dev/tty1",
@ -1557,6 +1569,29 @@ void FurnaceGUI::drawSettings() {
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##OPNCoreRender",&settings.opnCoreRender,opnCores,2)) settingsChanged=true;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("OPL/OPL2/Y8950");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##OPL2Core",&settings.opl2Core,opl2Cores,3)) settingsChanged=true;
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##OPL2CoreRender",&settings.opl2CoreRender,opl2Cores,3)) settingsChanged=true;
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::AlignTextToFramePadding();
ImGui::Text("OPL3");
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##OPL3Core",&settings.opl3Core,opl3Cores,3)) settingsChanged=true;
ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::Combo("##OPL3CoreRender",&settings.opl3CoreRender,opl3Cores,3)) settingsChanged=true;
ImGui::EndTable();
}
ImGui::Separator();
@ -3594,6 +3629,8 @@ void FurnaceGUI::syncSettings() {
settings.c64Core=e->getConfInt("c64Core",0);
settings.pokeyCore=e->getConfInt("pokeyCore",1);
settings.opnCore=e->getConfInt("opnCore",1);
settings.opl2Core=e->getConfInt("opl2Core",0);
settings.opl3Core=e->getConfInt("opl3Core",0);
settings.arcadeCoreRender=e->getConfInt("arcadeCoreRender",1);
settings.ym2612CoreRender=e->getConfInt("ym2612CoreRender",0);
settings.snCoreRender=e->getConfInt("snCoreRender",0);
@ -3602,6 +3639,8 @@ void FurnaceGUI::syncSettings() {
settings.c64CoreRender=e->getConfInt("c64CoreRender",1);
settings.pokeyCoreRender=e->getConfInt("pokeyCoreRender",1);
settings.opnCoreRender=e->getConfInt("opnCoreRender",1);
settings.opl2CoreRender=e->getConfInt("opl2CoreRender",0);
settings.opl3CoreRender=e->getConfInt("opl3CoreRender",0);
settings.pcSpeakerOutMethod=e->getConfInt("pcSpeakerOutMethod",0);
settings.yrw801Path=e->getConfString("yrw801Path","");
settings.tg100Path=e->getConfString("tg100Path","");
@ -3778,6 +3817,8 @@ void FurnaceGUI::syncSettings() {
clampSetting(settings.c64Core,0,2);
clampSetting(settings.pokeyCore,0,1);
clampSetting(settings.opnCore,0,1);
clampSetting(settings.opl2Core,0,2);
clampSetting(settings.opl3Core,0,2);
clampSetting(settings.arcadeCoreRender,0,1);
clampSetting(settings.ym2612CoreRender,0,1);
clampSetting(settings.snCoreRender,0,1);
@ -3786,6 +3827,8 @@ void FurnaceGUI::syncSettings() {
clampSetting(settings.c64CoreRender,0,2);
clampSetting(settings.pokeyCoreRender,0,1);
clampSetting(settings.opnCoreRender,0,1);
clampSetting(settings.opl2CoreRender,0,2);
clampSetting(settings.opl3CoreRender,0,2);
clampSetting(settings.pcSpeakerOutMethod,0,4);
clampSetting(settings.mainFont,0,6);
clampSetting(settings.patFont,0,6);
@ -3991,6 +4034,8 @@ void FurnaceGUI::commitSettings() {
settings.c64Core!=e->getConfInt("c64Core",0) ||
settings.pokeyCore!=e->getConfInt("pokeyCore",1) ||
settings.opnCore!=e->getConfInt("opnCore",1) ||
settings.opl2Core!=e->getConfInt("opl2Core",0) ||
settings.opl3Core!=e->getConfInt("opl3Core",0) ||
settings.arcadeCoreRender!=e->getConfInt("arcadeCoreRender",0) ||
settings.ym2612CoreRender!=e->getConfInt("ym2612CoreRender",0) ||
settings.snCoreRender!=e->getConfInt("snCoreRender",0) ||
@ -3999,6 +4044,8 @@ void FurnaceGUI::commitSettings() {
settings.c64CoreRender!=e->getConfInt("c64CoreRender",0) ||
settings.pokeyCoreRender!=e->getConfInt("pokeyCoreRender",1) ||
settings.opnCoreRender!=e->getConfInt("opnCoreRender",1) ||
settings.opl2CoreRender!=e->getConfInt("opl2CoreRender",0) ||
settings.opl3CoreRender!=e->getConfInt("opl3CoreRender",0) ||
settings.audioQuality!=e->getConfInt("audioQuality",0) ||
settings.audioHiPass!=e->getConfInt("audioHiPass",1)
);
@ -4026,6 +4073,8 @@ void FurnaceGUI::commitSettings() {
e->setConf("c64Core",settings.c64Core);
e->setConf("pokeyCore",settings.pokeyCore);
e->setConf("opnCore",settings.opnCore);
e->setConf("opl2Core",settings.opl2Core);
e->setConf("opl3Core",settings.opl3Core);
e->setConf("arcadeCoreRender",settings.arcadeCoreRender);
e->setConf("ym2612CoreRender",settings.ym2612CoreRender);
e->setConf("snCoreRender",settings.snCoreRender);
@ -4034,6 +4083,8 @@ void FurnaceGUI::commitSettings() {
e->setConf("c64CoreRender",settings.c64CoreRender);
e->setConf("pokeyCoreRender",settings.pokeyCoreRender);
e->setConf("opnCoreRender",settings.opnCoreRender);
e->setConf("opl2CoreRender",settings.opl2CoreRender);
e->setConf("opl3CoreRender",settings.opl3CoreRender);
e->setConf("pcSpeakerOutMethod",settings.pcSpeakerOutMethod);
e->setConf("yrw801Path",settings.yrw801Path);
e->setConf("tg100Path",settings.tg100Path);