implement YMF276-LLE core
thanks LTVA
This commit is contained in:
parent
3512591fd1
commit
892ee12d91
14
extern/YMF276-LLE/fmopn2.c
vendored
14
extern/YMF276-LLE/fmopn2.c
vendored
|
@ -2066,6 +2066,8 @@ void FMOPN2_YMF276Accumulator1(fmopn2_t *chip)
|
||||||
int acc_l = 0;
|
int acc_l = 0;
|
||||||
int acc_r = 0;
|
int acc_r = 0;
|
||||||
|
|
||||||
|
chip->osc_out = 0;
|
||||||
|
|
||||||
for (i = 0; i < 14; i++)
|
for (i = 0; i < 14; i++)
|
||||||
accm += ((chip->ch_accm[i][1] >> 5) & 1) << i;
|
accm += ((chip->ch_accm[i][1] >> 5) & 1) << i;
|
||||||
if (chip->alg_output && !test_dac)
|
if (chip->alg_output && !test_dac)
|
||||||
|
@ -2106,12 +2108,12 @@ void FMOPN2_YMF276Accumulator1(fmopn2_t *chip)
|
||||||
chip->fsm_op1_sel_l3[0] = chip->fsm_op1_sel;
|
chip->fsm_op1_sel_l3[0] = chip->fsm_op1_sel;
|
||||||
|
|
||||||
if (sel_dac)
|
if (sel_dac)
|
||||||
out |= chip->mode_dac_data[1] << 6;
|
chip->osc_out |= chip->mode_dac_data[1] << 6;
|
||||||
if (sel_fm)
|
if (sel_fm)
|
||||||
out |= accm;
|
chip->osc_out |= accm;
|
||||||
|
|
||||||
if (out & 0x2000)
|
if (chip->osc_out & 0x2000)
|
||||||
out |= 0x1c000;
|
chip->osc_out |= 0x1c000;
|
||||||
|
|
||||||
for (i = 0; i < 2; i++)
|
for (i = 0; i < 2; i++)
|
||||||
pan |= (((chip->chan_pan[i][1] >> 5) & 1) ^ 1) << i;
|
pan |= (((chip->chan_pan[i][1] >> 5) & 1) ^ 1) << i;
|
||||||
|
@ -2130,8 +2132,8 @@ void FMOPN2_YMF276Accumulator1(fmopn2_t *chip)
|
||||||
acc_r = chip->ch_accm_r[1];
|
acc_r = chip->ch_accm_r[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
chip->ch_accm_l[0] = acc_l + ((pan & 2) != 0 ? out : 0);
|
chip->ch_accm_l[0] = acc_l + ((pan & 2) != 0 ? chip->osc_out : 0);
|
||||||
chip->ch_accm_r[0] = acc_r + ((pan & 1) != 0 ? out : 0);
|
chip->ch_accm_r[0] = acc_r + ((pan & 1) != 0 ? chip->osc_out : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FMOPN2_YMF276Accumulator2(fmopn2_t *chip)
|
void FMOPN2_YMF276Accumulator2(fmopn2_t *chip)
|
||||||
|
|
3
extern/YMF276-LLE/fmopn2.h
vendored
3
extern/YMF276-LLE/fmopn2.h
vendored
|
@ -72,6 +72,9 @@ typedef struct {
|
||||||
int out_l;
|
int out_l;
|
||||||
int out_r;
|
int out_r;
|
||||||
|
|
||||||
|
// added by LTVA for Furnace tracker per-channel oscilloscopes!
|
||||||
|
int osc_out;
|
||||||
|
|
||||||
// io
|
// io
|
||||||
int write_addr_trig;
|
int write_addr_trig;
|
||||||
int write_addr_trig_sync;
|
int write_addr_trig_sync;
|
||||||
|
|
|
@ -143,7 +143,7 @@ void DivPlatformGenesis::acquire_nuked(short** buf, size_t len) {
|
||||||
if (!writes.empty()) {
|
if (!writes.empty()) {
|
||||||
QueuedWrite& w=writes.front();
|
QueuedWrite& w=writes.front();
|
||||||
if (w.addrOrVal) {
|
if (w.addrOrVal) {
|
||||||
//logV("%.3x = %.2x",w.addr,w.val);
|
//logV("%.3x=%.2x",w.addr,w.val);
|
||||||
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
|
OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
|
||||||
regPool[w.addr&0x1ff]=w.val;
|
regPool[w.addr&0x1ff]=w.val;
|
||||||
writes.pop_front();
|
writes.pop_front();
|
||||||
|
@ -289,8 +289,279 @@ void DivPlatformGenesis::acquire_ymfm(short** buf, size_t len) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unsigned char chanMap276[6]={
|
||||||
|
1, 5, 3, 0, 4, 2
|
||||||
|
};
|
||||||
|
|
||||||
|
// thanks LTVA
|
||||||
|
void DivPlatformGenesis::acquire276OscSub() {
|
||||||
|
if (fm_276.fsm_cnt2[1]==0 && llePrevCycle!=0) {
|
||||||
|
lleCycle=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
llePrevCycle=fm_276.fsm_cnt2[1];
|
||||||
|
|
||||||
|
if (fm_276.flags==fmopn2_flags_ym3438) {
|
||||||
|
lleOscData[lleCycle/(24*2)]+=fm_276.out_l+fm_276.out_r;
|
||||||
|
|
||||||
|
lleCycle++;
|
||||||
|
|
||||||
|
if (lleCycle==(144*2)) {
|
||||||
|
lleCycle=0;
|
||||||
|
|
||||||
|
for (int i=0; i<6; i++) {
|
||||||
|
if ((softPCM && ((chanMap276[i]!=5) || !chan[5].dacMode)) || (!softPCM)) {
|
||||||
|
oscBuf[chanMap276[i]]->data[oscBuf[chanMap276[i]]->needle++]=lleOscData[i];
|
||||||
|
}
|
||||||
|
lleOscData[i]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (softPCM && chan[5].dacMode) {
|
||||||
|
oscBuf[5]->data[oscBuf[5]->needle++]=chan[5].dacOutput<<6;
|
||||||
|
oscBuf[6]->data[oscBuf[6]->needle++]=chan[6].dacOutput<<6;
|
||||||
|
} else {
|
||||||
|
oscBuf[6]->data[oscBuf[6]->needle++]=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i=0; i<6; i++) {
|
||||||
|
if (lleCycle==((7+i)*12)) {
|
||||||
|
oscBuf[i]->data[oscBuf[i]->needle]=(fm_276.osc_out>>1)*8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lleCycle++;
|
||||||
|
|
||||||
|
if (lleCycle==(144*2)) {
|
||||||
|
lleCycle=0;
|
||||||
|
|
||||||
|
for (int i=0; i<6; i++) {
|
||||||
|
oscBuf[i]->data[oscBuf[i]->needle]>>=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (softPCM && chan[5].dacMode) {
|
||||||
|
oscBuf[5]->data[oscBuf[5]->needle]=chan[5].dacOutput<<6;
|
||||||
|
oscBuf[6]->data[oscBuf[6]->needle]=chan[6].dacOutput<<6;
|
||||||
|
} else {
|
||||||
|
oscBuf[6]->data[oscBuf[6]->needle]=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<7; i++) {
|
||||||
|
oscBuf[i]->needle++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// thanks LTVA
|
||||||
void DivPlatformGenesis::acquire_nuked276(short** buf, size_t len) {
|
void DivPlatformGenesis::acquire_nuked276(short** buf, size_t len) {
|
||||||
// TODO
|
for (size_t h=0; h<len; h++) {
|
||||||
|
processDAC(rate);
|
||||||
|
|
||||||
|
int sum_l=0;
|
||||||
|
int sum_r=0;
|
||||||
|
|
||||||
|
int sample_l=0;
|
||||||
|
int sample_r=0;
|
||||||
|
|
||||||
|
bool was_reg_write=false;
|
||||||
|
|
||||||
|
//lleCycle=0;
|
||||||
|
|
||||||
|
if (!writes.empty()) {
|
||||||
|
QueuedWrite& w=writes.front();
|
||||||
|
if (w.addrOrVal) {
|
||||||
|
//logV("%.3x=%.2x",w.addr,w.val);
|
||||||
|
//OPN2_Write(&fm,0x1+((w.addr>>8)<<1),w.val);
|
||||||
|
was_reg_write=true;
|
||||||
|
|
||||||
|
fm_276.input.address=w.addr<0x100?0:2;
|
||||||
|
fm_276.input.data=w.addr&0xff;
|
||||||
|
fm_276.input.wr=1;
|
||||||
|
FMOPN2_Clock(&fm_276,0);
|
||||||
|
sum_l+=fm_276.out_l;
|
||||||
|
sum_r+=fm_276.out_r;
|
||||||
|
|
||||||
|
acquire276OscSub();
|
||||||
|
|
||||||
|
fm_276.input.wr=0;
|
||||||
|
FMOPN2_Clock(&fm_276,1);
|
||||||
|
sum_l+=fm_276.out_l;
|
||||||
|
sum_r+=fm_276.out_r;
|
||||||
|
|
||||||
|
acquire276OscSub();
|
||||||
|
|
||||||
|
if (chipType==2) {
|
||||||
|
if (!o_bco && fm_276.o_bco) {
|
||||||
|
dacShifter=(dacShifter<<1)|fm_276.o_so;
|
||||||
|
|
||||||
|
if (o_lro!=fm_276.o_lro) {
|
||||||
|
if (o_lro)
|
||||||
|
sample_l=dacShifter;
|
||||||
|
else
|
||||||
|
sample_r=dacShifter;
|
||||||
|
}
|
||||||
|
|
||||||
|
o_lro=fm_276.o_lro;
|
||||||
|
}
|
||||||
|
o_bco=fm_276.o_bco;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int c=0; c<17; c++) {
|
||||||
|
FMOPN2_Clock(&fm_276,0);
|
||||||
|
sum_l+=fm_276.out_l;
|
||||||
|
sum_r+=fm_276.out_r;
|
||||||
|
|
||||||
|
acquire276OscSub();
|
||||||
|
|
||||||
|
FMOPN2_Clock(&fm_276,1);
|
||||||
|
sum_l+=fm_276.out_l;
|
||||||
|
sum_r+=fm_276.out_r;
|
||||||
|
|
||||||
|
acquire276OscSub();
|
||||||
|
|
||||||
|
if (chipType==2) {
|
||||||
|
if (!o_bco && fm_276.o_bco) {
|
||||||
|
dacShifter=(dacShifter<<1)|fm_276.o_so;
|
||||||
|
|
||||||
|
if (o_lro!=fm_276.o_lro) {
|
||||||
|
if (o_lro)
|
||||||
|
sample_l=dacShifter;
|
||||||
|
else
|
||||||
|
sample_r=dacShifter;
|
||||||
|
}
|
||||||
|
|
||||||
|
o_lro=fm_276.o_lro;
|
||||||
|
}
|
||||||
|
o_bco=fm_276.o_bco;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fm_276.input.address=w.addr<0x100?1:3;
|
||||||
|
fm_276.input.data=w.val;
|
||||||
|
fm_276.input.wr=1;
|
||||||
|
FMOPN2_Clock(&fm_276,0);
|
||||||
|
sum_l+=fm_276.out_l;
|
||||||
|
sum_r+=fm_276.out_r;
|
||||||
|
fm_276.input.wr=0;
|
||||||
|
|
||||||
|
acquire276OscSub();
|
||||||
|
|
||||||
|
FMOPN2_Clock(&fm_276,1);
|
||||||
|
sum_l+=fm_276.out_l;
|
||||||
|
sum_r+=fm_276.out_r;
|
||||||
|
|
||||||
|
acquire276OscSub();
|
||||||
|
|
||||||
|
if (chipType==2) {
|
||||||
|
if (!o_bco && fm_276.o_bco) {
|
||||||
|
dacShifter=(dacShifter<<1)|fm_276.o_so;
|
||||||
|
|
||||||
|
if (o_lro!=fm_276.o_lro) {
|
||||||
|
if (o_lro)
|
||||||
|
sample_l=dacShifter;
|
||||||
|
else
|
||||||
|
sample_r=dacShifter;
|
||||||
|
}
|
||||||
|
|
||||||
|
o_lro=fm_276.o_lro;
|
||||||
|
}
|
||||||
|
o_bco=fm_276.o_bco;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int c=0; c<83; c++) {
|
||||||
|
FMOPN2_Clock(&fm_276,0);
|
||||||
|
sum_l+=fm_276.out_l;
|
||||||
|
sum_r+=fm_276.out_r;
|
||||||
|
|
||||||
|
acquire276OscSub();
|
||||||
|
|
||||||
|
FMOPN2_Clock(&fm_276,1);
|
||||||
|
sum_l+=fm_276.out_l;
|
||||||
|
sum_r+=fm_276.out_r;
|
||||||
|
|
||||||
|
acquire276OscSub();
|
||||||
|
|
||||||
|
if (chipType==2) {
|
||||||
|
if (!o_bco && fm_276.o_bco) {
|
||||||
|
dacShifter=(dacShifter<<1)|fm_276.o_so;
|
||||||
|
|
||||||
|
if (o_lro!=fm_276.o_lro) {
|
||||||
|
if (o_lro) {
|
||||||
|
sample_l=dacShifter;
|
||||||
|
} else {
|
||||||
|
sample_r=dacShifter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
o_lro=fm_276.o_lro;
|
||||||
|
}
|
||||||
|
o_bco=fm_276.o_bco;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
regPool[w.addr&0x1ff]=w.val;
|
||||||
|
writes.pop_front();
|
||||||
|
|
||||||
|
if (dacWrite>=0) {
|
||||||
|
if (!canWriteDAC) {
|
||||||
|
canWriteDAC=true;
|
||||||
|
} else {
|
||||||
|
urgentWrite(0x2a,dacWrite);
|
||||||
|
dacWrite=-1;
|
||||||
|
canWriteDAC=writes.empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
w.addrOrVal=true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
canWriteDAC=true;
|
||||||
|
if (dacWrite>=0) {
|
||||||
|
urgentWrite(0x2a,dacWrite);
|
||||||
|
dacWrite=-1;
|
||||||
|
}
|
||||||
|
flushFirst=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int j=0; j<(was_reg_write?(144-83-19):144); j++) {
|
||||||
|
FMOPN2_Clock(&fm_276,0);
|
||||||
|
sum_l+=fm_276.out_l;
|
||||||
|
sum_r+=fm_276.out_r;
|
||||||
|
|
||||||
|
acquire276OscSub();
|
||||||
|
|
||||||
|
FMOPN2_Clock(&fm_276,1);
|
||||||
|
sum_l+=fm_276.out_l;
|
||||||
|
sum_r+=fm_276.out_r;
|
||||||
|
|
||||||
|
acquire276OscSub();
|
||||||
|
|
||||||
|
if (chipType==2) {
|
||||||
|
if (!o_bco && fm_276.o_bco) {
|
||||||
|
dacShifter=(dacShifter<<1)|fm_276.o_so;
|
||||||
|
|
||||||
|
if (o_lro!=fm_276.o_lro) {
|
||||||
|
if (o_lro)
|
||||||
|
sample_l=dacShifter;
|
||||||
|
else
|
||||||
|
sample_r=dacShifter;
|
||||||
|
}
|
||||||
|
|
||||||
|
o_lro=fm_276.o_lro;
|
||||||
|
}
|
||||||
|
o_bco=fm_276.o_bco;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chipType==2) {
|
||||||
|
buf[0][h]=sample_l;
|
||||||
|
buf[1][h]=sample_r;
|
||||||
|
} else {
|
||||||
|
buf[0][h]=(sum_l*3)>>2;
|
||||||
|
buf[1][h]=(sum_r*3)>>2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformGenesis::acquire(short** buf, size_t len) {
|
void DivPlatformGenesis::acquire(short** buf, size_t len) {
|
||||||
|
@ -1333,7 +1604,48 @@ void DivPlatformGenesis::reset() {
|
||||||
writes.clear();
|
writes.clear();
|
||||||
memset(regPool,0,512);
|
memset(regPool,0,512);
|
||||||
if (useYMFM==2) {
|
if (useYMFM==2) {
|
||||||
|
dacShifter=0;
|
||||||
|
o_bco=0;
|
||||||
|
o_lro=0;
|
||||||
|
|
||||||
|
lleCycle=0;
|
||||||
|
llePrevCycle=0;
|
||||||
|
|
||||||
|
for (int i=0; i<6; i++) {
|
||||||
|
lleOscData[i]=0;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&fm_276,0,sizeof(fmopn2_t));
|
memset(&fm_276,0,sizeof(fmopn2_t));
|
||||||
|
|
||||||
|
fm_276.input.cs=1;
|
||||||
|
fm_276.input.rd=0;
|
||||||
|
fm_276.input.wr=0;
|
||||||
|
fm_276.input.address=0;
|
||||||
|
fm_276.input.data=0;
|
||||||
|
|
||||||
|
if (chipType==2) {
|
||||||
|
fm_276.flags=0;
|
||||||
|
} else {
|
||||||
|
fm_276.flags=fmopn2_flags_ym3438;
|
||||||
|
}
|
||||||
|
|
||||||
|
fm_276.input.ic=0;
|
||||||
|
for (int i=0; i<288; i++) {
|
||||||
|
FMOPN2_Clock(&fm_276,0);
|
||||||
|
FMOPN2_Clock(&fm_276,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fm_276.input.ic=1;
|
||||||
|
for (int i=0; i<288*2; i++) {
|
||||||
|
FMOPN2_Clock(&fm_276,0);
|
||||||
|
FMOPN2_Clock(&fm_276,1);
|
||||||
|
}
|
||||||
|
|
||||||
|
fm_276.input.ic=0;
|
||||||
|
for (int i=0; i<288*2; i++) {
|
||||||
|
FMOPN2_Clock(&fm_276,0);
|
||||||
|
FMOPN2_Clock(&fm_276,1);
|
||||||
|
}
|
||||||
} else if (useYMFM==1) {
|
} else if (useYMFM==1) {
|
||||||
fm_ymfm->reset();
|
fm_ymfm->reset();
|
||||||
}
|
}
|
||||||
|
@ -1474,6 +1786,8 @@ void DivPlatformGenesis::setFlags(const DivConfig& flags) {
|
||||||
fm_ymfm=new ymfm::ym3438(iface);
|
fm_ymfm=new ymfm::ym3438(iface);
|
||||||
}
|
}
|
||||||
rate=chipClock/144;
|
rate=chipClock/144;
|
||||||
|
} else if (useYMFM==2) {
|
||||||
|
rate=chipClock/144;
|
||||||
} else {
|
} else {
|
||||||
rate=chipClock/36;
|
rate=chipClock/36;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,9 @@
|
||||||
|
|
||||||
#include "fmshared_OPN.h"
|
#include "fmshared_OPN.h"
|
||||||
#include "sound/ymfm/ymfm_opn.h"
|
#include "sound/ymfm/ymfm_opn.h"
|
||||||
|
extern "C" {
|
||||||
#include "../../../extern/YMF276-LLE/fmopn2.h"
|
#include "../../../extern/YMF276-LLE/fmopn2.h"
|
||||||
|
}
|
||||||
|
|
||||||
class DivYM2612Interface: public ymfm::ymfm_interface {
|
class DivYM2612Interface: public ymfm::ymfm_interface {
|
||||||
int setA, setB;
|
int setA, setB;
|
||||||
|
@ -90,6 +92,11 @@ class DivPlatformGenesis: public DivPlatformOPN {
|
||||||
unsigned char chipType;
|
unsigned char chipType;
|
||||||
short dacWrite;
|
short dacWrite;
|
||||||
|
|
||||||
|
int lleCycle;
|
||||||
|
int llePrevCycle;
|
||||||
|
int lleOscData[6];
|
||||||
|
int dacShifter, o_lro, o_bco;
|
||||||
|
|
||||||
unsigned char dacVolTable[128];
|
unsigned char dacVolTable[128];
|
||||||
|
|
||||||
friend void putDispatchChip(void*,int);
|
friend void putDispatchChip(void*,int);
|
||||||
|
@ -97,6 +104,7 @@ class DivPlatformGenesis: public DivPlatformOPN {
|
||||||
|
|
||||||
inline void processDAC(int iRate);
|
inline void processDAC(int iRate);
|
||||||
inline void commitState(int ch, DivInstrument* ins);
|
inline void commitState(int ch, DivInstrument* ins);
|
||||||
|
void acquire276OscSub();
|
||||||
void acquire_nuked(short** buf, size_t len);
|
void acquire_nuked(short** buf, size_t len);
|
||||||
void acquire_nuked276(short** buf, size_t len);
|
void acquire_nuked276(short** buf, size_t len);
|
||||||
void acquire_ymfm(short** buf, size_t len);
|
void acquire_ymfm(short** buf, size_t len);
|
||||||
|
|
|
@ -1541,10 +1541,10 @@ void FurnaceGUI::drawSettings() {
|
||||||
ImGui::Text("YM2612");
|
ImGui::Text("YM2612");
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
if (ImGui::Combo("##YM2612Core",&settings.ym2612Core,ym2612Cores,2)) settingsChanged=true;
|
if (ImGui::Combo("##YM2612Core",&settings.ym2612Core,ym2612Cores,3)) settingsChanged=true;
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||||
if (ImGui::Combo("##YM2612CoreRender",&settings.ym2612CoreRender,ym2612Cores,2)) settingsChanged=true;
|
if (ImGui::Combo("##YM2612CoreRender",&settings.ym2612CoreRender,ym2612Cores,3)) settingsChanged=true;
|
||||||
|
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|
Loading…
Reference in a new issue