mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-25 22:15:14 +00:00
OPL: ymfm core, part 1
This commit is contained in:
parent
1bcdedda3e
commit
955682b240
9 changed files with 467 additions and 29 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(""),
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue