mirror of
https://github.com/tildearrow/furnace.git
synced 2024-11-01 02:22:39 +00:00
Some fleshing out YMF278B
Add OpenMSX YMF278B core option, Expand RAM size option
This commit is contained in:
parent
a8ec76699b
commit
221fa5aa42
11 changed files with 275 additions and 104 deletions
|
@ -763,14 +763,20 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
|||
case DIV_SYSTEM_OPL4:
|
||||
dispatch=new DivPlatformOPL;
|
||||
((DivPlatformOPL*)dispatch)->setOPLType(4,false);
|
||||
// YMFM for now
|
||||
((DivPlatformOPL*)dispatch)->setCore(1);
|
||||
if (isRender) {
|
||||
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl4CoreRender",0));
|
||||
} else {
|
||||
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl4Core",0));
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_OPL4_DRUMS:
|
||||
dispatch=new DivPlatformOPL;
|
||||
((DivPlatformOPL*)dispatch)->setOPLType(4,true);
|
||||
// YMFM for now
|
||||
((DivPlatformOPL*)dispatch)->setCore(1);
|
||||
if (isRender) {
|
||||
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl4CoreRender",0));
|
||||
} else {
|
||||
((DivPlatformOPL*)dispatch)->setCore(eng->getConfInt("opl4Core",0));
|
||||
}
|
||||
break;
|
||||
case DIV_SYSTEM_DUMMY:
|
||||
dispatch=new DivPlatformDummy;
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
#define KVSL(x,y) ((chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==2 && isOutputL[ops==4][chan[x].state.alg][y]) || chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==1)
|
||||
|
||||
#define CHIP_FREQBASE chipFreqBase
|
||||
#define PCM_FREQBASE (402653184)
|
||||
|
||||
#define NOTE_PCM(x) parent->calcBaseFreq(chipClock,PCM_FREQBASE,x,false)
|
||||
|
||||
#define PCM_CHECK(ch) ((chipType==4) && (ch>=pcmChanOffs))
|
||||
#define PCM_REG(ch) (ch-pcmChanOffs)
|
||||
|
||||
// N = invalid
|
||||
#define N 255
|
||||
|
@ -176,36 +182,42 @@ const int orderedOpsL[4]={
|
|||
#define PCM_ADDR_MIX_PCM 0x2f9
|
||||
|
||||
void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
|
||||
thread_local short o[4];
|
||||
thread_local int os[4];
|
||||
thread_local short o[8];
|
||||
thread_local int os[6];
|
||||
thread_local ymfm::ymfm_output<2> aOut;
|
||||
|
||||
for (size_t h=0; h<len; h++) {
|
||||
os[0]=0; os[1]=0; os[2]=0; os[3]=0;
|
||||
os[0]=0; os[1]=0; os[2]=0; os[3]=0; os[4]=0; os[5]=0;
|
||||
short pcmBuf[24]={0};
|
||||
if (!writes.empty() && --delay<0) {
|
||||
delay=1;
|
||||
QueuedWrite& w=writes.front();
|
||||
switch (w.addr) {
|
||||
case 8:
|
||||
if (adpcmChan>=0) {
|
||||
adpcmB->write(w.addr-7,(w.val&15)|0x80);
|
||||
OPL3_WriteReg(&fm,w.addr,w.val&0xc0);
|
||||
} else {
|
||||
if (w.addr>=0x200) {
|
||||
pcm.writeReg(w.addr&0xff,w.val);
|
||||
regPool[0x200|(w.addr&0xff)]=w.val;
|
||||
} else {
|
||||
switch (w.addr) {
|
||||
case 8:
|
||||
if (adpcmChan>=0) {
|
||||
adpcmB->write(w.addr-7,(w.val&15)|0x80);
|
||||
OPL3_WriteReg(&fm,w.addr,w.val&0xc0);
|
||||
} else {
|
||||
OPL3_WriteReg(&fm,w.addr,w.val);
|
||||
}
|
||||
break;
|
||||
case 7: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 21: case 22: case 23:
|
||||
if (adpcmChan>=0) {
|
||||
adpcmB->write(w.addr-7,w.val);
|
||||
} else {
|
||||
OPL3_WriteReg(&fm,w.addr,w.val);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OPL3_WriteReg(&fm,w.addr,w.val);
|
||||
}
|
||||
break;
|
||||
case 7: case 9: case 10: case 11: case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 21: case 22: case 23:
|
||||
if (adpcmChan>=0) {
|
||||
adpcmB->write(w.addr-7,w.val);
|
||||
} else {
|
||||
OPL3_WriteReg(&fm,w.addr,w.val);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OPL3_WriteReg(&fm,w.addr,w.val);
|
||||
break;
|
||||
break;
|
||||
}
|
||||
regPool[w.addr&511]=w.val;
|
||||
}
|
||||
regPool[w.addr&511]=w.val;
|
||||
writes.pop();
|
||||
}
|
||||
|
||||
|
@ -214,10 +226,20 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
|
|||
} else {
|
||||
OPL3_Generate4Ch(&fm,o);
|
||||
}
|
||||
os[0]+=o[0];
|
||||
os[1]+=o[1];
|
||||
os[2]+=o[2];
|
||||
os[3]+=o[3];
|
||||
if (chipType==4) {
|
||||
pcm.generateMix(o[0],o[1],o[4],o[5],o[6],o[7],pcmBuf);
|
||||
os[0]+=o[4];
|
||||
os[1]+=o[5];
|
||||
os[2]+=o[2];
|
||||
os[3]+=o[3];
|
||||
os[4]+=o[6];
|
||||
os[5]+=o[7];
|
||||
} else {
|
||||
os[0]+=o[0];
|
||||
os[1]+=o[1];
|
||||
os[2]+=o[2];
|
||||
os[3]+=o[3];
|
||||
}
|
||||
|
||||
if (adpcmChan>=0) {
|
||||
adpcmB->clock();
|
||||
|
@ -290,6 +312,12 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
|
|||
if (os[3]<-32768) os[3]=-32768;
|
||||
if (os[3]>32767) os[3]=32767;
|
||||
|
||||
if (os[4]<-32768) os[4]=-32768;
|
||||
if (os[4]>32767) os[4]=32767;
|
||||
|
||||
if (os[5]<-32768) os[5]=-32768;
|
||||
if (os[5]>32767) os[5]=32767;
|
||||
|
||||
buf[0][h]=os[0];
|
||||
if (totalOutputs>1) {
|
||||
buf[1][h]=os[1];
|
||||
|
@ -301,9 +329,8 @@ void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
|
|||
buf[3][h]=os[3];
|
||||
}
|
||||
if (totalOutputs==6) {
|
||||
// placeholder for OPL4
|
||||
buf[4][h]=0;
|
||||
buf[5][h]=0;
|
||||
buf[4][h]=os[4];
|
||||
buf[5][h]=os[5];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -947,22 +974,44 @@ double DivPlatformOPL::NOTE_ADPCMB(int note) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
double DivPlatformOPL::NOTE_OPL4(int ch, int note) { // TODO
|
||||
if (pcmChanOffs<0) return 0;
|
||||
if (chan[ch].sample>=0 && chan[ch].sample<parent->song.sampleLen) {
|
||||
double off=65535.0*(double)(parent->getSample(chan[ch].sample)->centerRate)/8363.0;
|
||||
return parent->calcBaseFreq((double)chipClock/768,off,note,false);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DivPlatformOPL::tick(bool sysTick) {
|
||||
for (int i=0; i<totalChans; i++) {
|
||||
if (i>=pcmChanOffs) { // OPL4 PCM
|
||||
if (PCM_CHECK(i)) { // OPL4 PCM
|
||||
chan[i].std.next();
|
||||
if (chan[i].std.vol.had) {
|
||||
chan[i].outVol=VOL_SCALE_LOG((chan[i].vol&0x7f),(0x7f*chan[i].std.vol.val)/chan[i].macroVolMul,0x7f);
|
||||
immWrite(PCM_ADDR_TL+(i-pcmChanOffs),((0x7f-chan[i].outVol)<<1)|(chan[i].levelDirect?1:0));
|
||||
immWrite(PCM_ADDR_TL+(PCM_REG(i)),((0x7f-chan[i].outVol)<<1)|(chan[i].levelDirect?1:0));
|
||||
}
|
||||
|
||||
if (NEW_ARP_STRAT) {
|
||||
chan[i].handleArp();
|
||||
} else if (chan[i].std.arp.had) {
|
||||
if (!chan[i].inPorta) {
|
||||
chan[i].baseFreq=NOTE_PCM(parent->calcArp(chan[i].note,chan[i].std.arp.val));
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
||||
if (chan[i].std.pitch.had) {
|
||||
if (chan[i].std.pitch.mode) {
|
||||
chan[i].pitch2+=chan[i].std.pitch.val;
|
||||
CLAMP_VAR(chan[i].pitch2,-131071,131071);
|
||||
} else {
|
||||
chan[i].pitch2=chan[i].std.pitch.val;
|
||||
}
|
||||
chan[i].freqChanged=true;
|
||||
}
|
||||
|
||||
if (chan[i].std.phaseReset.had) {
|
||||
if (chan[i].std.phaseReset.val==1 && chan[i].active) {
|
||||
chan[i].keyOn=true;
|
||||
}
|
||||
}
|
||||
|
||||
if (chan[i].std.panL.had) { // panning
|
||||
chan[i].pan=chan[i].std.panL.val&0xf;
|
||||
chan[i].freqChanged=true;
|
||||
chan[i].writeCtrl=true;
|
||||
}
|
||||
|
||||
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
|
||||
|
@ -1013,11 +1062,12 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
waveNum=MIN(waveNum,0x7f)|0x180;
|
||||
}
|
||||
if (chan[i].keyOn) {
|
||||
rWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+(i-pcmChanOffs),ctrl&~0x80); // force keyoff first
|
||||
rWrite(PCM_ADDR_WAVE_H_FN_L+(i-pcmChanOffs),((chan[i].freqL&0x7f)<<1)|((waveNum>>8)&1));
|
||||
rWrite(PCM_ADDR_WAVE_L+(i-pcmChanOffs),waveNum&0xff);
|
||||
rWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+PCM_REG(i),ctrl&~0x80); // force keyoff first
|
||||
rWrite(PCM_ADDR_WAVE_H_FN_L+PCM_REG(i),((chan[i].freqL&0x7f)<<1)|((waveNum>>8)&1));
|
||||
rWrite(PCM_ADDR_WAVE_L+PCM_REG(i),waveNum&0xff);
|
||||
if (!chan[i].std.vol.had) {
|
||||
chan[i].outVol=chan[i].vol;
|
||||
immWrite(PCM_ADDR_TL+(PCM_REG(i)),((0x7f-chan[i].outVol)<<1)|(chan[i].levelDirect?1:0));
|
||||
}
|
||||
chan[i].writeCtrl=true;
|
||||
chan[i].keyOn=false;
|
||||
|
@ -1027,12 +1077,12 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
chan[i].keyOff=false;
|
||||
}
|
||||
if (chan[i].freqChanged) {
|
||||
rWrite(PCM_ADDR_WAVE_H_FN_L+(i-pcmChanOffs),((chan[i].freqL&0x7f)<<1)|((waveNum>>8)&1));
|
||||
rWrite(PCM_ADDR_FN_H_PR_OCT+(i-pcmChanOffs),((chan[i].freqH&0xf)<<4)|(chan[i].pseudoReverb?0x08:0x00)|((chan[i].freqL>>7)&0x7));
|
||||
rWrite(PCM_ADDR_WAVE_H_FN_L+PCM_REG(i),((chan[i].freqL&0x7f)<<1)|((waveNum>>8)&1));
|
||||
rWrite(PCM_ADDR_FN_H_PR_OCT+PCM_REG(i),((chan[i].freqH&0xf)<<4)|(chan[i].pseudoReverb?0x08:0x00)|((chan[i].freqL>>7)&0x7));
|
||||
chan[i].freqChanged=false;
|
||||
}
|
||||
if (chan[i].writeCtrl) {
|
||||
rWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+(i-pcmChanOffs),ctrl);
|
||||
rWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+PCM_REG(i),ctrl);
|
||||
chan[i].writeCtrl=false;
|
||||
}
|
||||
}
|
||||
|
@ -1309,7 +1359,7 @@ void DivPlatformOPL::tick(bool sysTick) {
|
|||
|
||||
bool updateDrums=false;
|
||||
for (int i=0; i<totalChans; i++) {
|
||||
if (i>=pcmChanOffs) { // OPL4 PCM
|
||||
if (PCM_CHECK(i)) { // OPL4 PCM
|
||||
|
||||
} else {
|
||||
if (chan[i].freqChanged) {
|
||||
|
@ -1426,7 +1476,7 @@ int DivPlatformOPL::toFreq(int freq) {
|
|||
|
||||
void DivPlatformOPL::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
if (ch>=pcmChanOffs) {
|
||||
if (PCM_CHECK(ch)) {
|
||||
chan[ch].freqChanged=true;
|
||||
chan[ch].writeCtrl=true;
|
||||
return;
|
||||
|
@ -1479,6 +1529,9 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) {
|
|||
}
|
||||
|
||||
void DivPlatformOPL::commitState(int ch, DivInstrument* ins) {
|
||||
if (PCM_CHECK(ch)) {
|
||||
return;
|
||||
}
|
||||
if (chan[ch].insChanged) {
|
||||
if (ch>melodicChans && ins->type==DIV_INS_OPL_DRUMS) {
|
||||
for (int i=0; i<4; i++) {
|
||||
|
@ -1583,7 +1636,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
}
|
||||
switch (c.cmd) {
|
||||
case DIV_CMD_NOTE_ON: {
|
||||
if (c.chan>=pcmChanOffs) { // OPL4 PCM
|
||||
if (PCM_CHECK(c.chan)) { // OPL4 PCM
|
||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_AMIGA);
|
||||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:127;
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
|
@ -1593,7 +1646,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
chan[c.chan].sampleNoteDelta=c.value-chan[c.chan].sampleNote;
|
||||
}
|
||||
if (c.value!=DIV_NOTE_NULL) {
|
||||
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
|
||||
chan[c.chan].baseFreq=NOTE_PCM(c.value);
|
||||
}
|
||||
if (chan[c.chan].sample<0 || chan[c.chan].sample>=parent->song.sampleLen) {
|
||||
chan[c.chan].sample=-1;
|
||||
|
@ -1733,7 +1786,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
chan[c.chan].keyOff=true;
|
||||
chan[c.chan].keyOn=false;
|
||||
chan[c.chan].active=false;
|
||||
if (c.chan>=pcmChanOffs) {
|
||||
if (PCM_CHECK(c.chan)) {
|
||||
chan[c.chan].sample=-1;
|
||||
chan[c.chan].macroInit(NULL);
|
||||
}
|
||||
|
@ -1757,8 +1810,8 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
if (!chan[c.chan].std.vol.has) {
|
||||
chan[c.chan].outVol=c.value;
|
||||
}
|
||||
if (c.chan>=pcmChanOffs) { // OPL4 PCM
|
||||
immWrite(PCM_ADDR_TL+(c.chan-pcmChanOffs),((0x7f-chan[c.chan].outVol)<<1)|(chan[c.chan].levelDirect?1:0));
|
||||
if (PCM_CHECK(c.chan)) { // OPL4 PCM
|
||||
immWrite(PCM_ADDR_TL+PCM_REG(c.chan),((0x7f-chan[c.chan].outVol)<<1)|(chan[c.chan].levelDirect?1:0));
|
||||
break;
|
||||
}
|
||||
if (c.chan==adpcmChan) { // ADPCM-B
|
||||
|
@ -1798,6 +1851,12 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
chan[c.chan].ins=c.value;
|
||||
break;
|
||||
case DIV_CMD_PANNING: {
|
||||
if (PCM_CHECK(c.chan)) {
|
||||
chan[c.chan].pan=8^MIN(parent->convertPanSplitToLinearLR(c.value,c.value2,15)+1,15);
|
||||
chan[c.chan].freqChanged=true;
|
||||
chan[c.chan].writeCtrl=true;
|
||||
break;
|
||||
}
|
||||
if (oplType!=3) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
chan[c.chan].pan&=~3;
|
||||
|
@ -1856,6 +1915,29 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_NOTE_PORTA: {
|
||||
if (PCM_CHECK(c.chan)) {
|
||||
int destFreq=NOTE_PCM(c.value2+chan[c.chan].sampleNoteDelta);
|
||||
bool return2=false;
|
||||
if (destFreq>chan[c.chan].baseFreq) {
|
||||
chan[c.chan].baseFreq+=c.value;
|
||||
if (chan[c.chan].baseFreq>=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
} else {
|
||||
chan[c.chan].baseFreq-=c.value;
|
||||
if (chan[c.chan].baseFreq<=destFreq) {
|
||||
chan[c.chan].baseFreq=destFreq;
|
||||
return2=true;
|
||||
}
|
||||
}
|
||||
chan[c.chan].freqChanged=true;
|
||||
if (return2) {
|
||||
chan[c.chan].inPorta=false;
|
||||
return 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
int destFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(c.value2)):(NOTE_FREQUENCY(c.value2));
|
||||
int newFreq;
|
||||
bool return2=false;
|
||||
|
@ -1901,13 +1983,14 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
commitState(c.chan,ins);
|
||||
chan[c.chan].insChanged=false;
|
||||
}
|
||||
chan[c.chan].baseFreq=(c.chan==adpcmChan)?(NOTE_ADPCMB(c.value)):(NOTE_FREQUENCY(c.value));
|
||||
chan[c.chan].baseFreq=(PCM_CHECK(c.chan))?NOTE_PCM(c.value):
|
||||
(c.chan==adpcmChan)?(NOTE_ADPCMB(c.value)):(NOTE_FREQUENCY(c.value));
|
||||
chan[c.chan].note=c.value;
|
||||
chan[c.chan].freqChanged=true;
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_LFO: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
if (c.value&2) {
|
||||
dvb=c.value&1;
|
||||
|
@ -1918,7 +2001,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FB: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
chan[c.chan].state.fb=c.value&7;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
|
@ -1936,7 +2019,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_MULT: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value>=ops) break;
|
||||
|
@ -1949,7 +2032,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value>=ops) break;
|
||||
|
@ -1970,7 +2053,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
|
@ -1994,7 +2077,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
|
@ -2018,7 +2101,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
|
@ -2042,7 +2125,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
|
@ -2066,7 +2149,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
|
@ -2090,7 +2173,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_VIB: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
|
@ -2114,7 +2197,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SUS: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
|
@ -2138,7 +2221,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_KSR: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
|
@ -2162,7 +2245,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_WS: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
if (oplType<2) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
|
@ -2187,7 +2270,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.chan>=pcmChanOffs) break;
|
||||
if (PCM_CHECK(c.chan)) break;
|
||||
if (c.chan==adpcmChan) break;
|
||||
if (oplType<2) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
|
@ -2261,7 +2344,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
chan[c.chan].std.restart(c.value);
|
||||
break;
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
if (c.chan>=pcmChanOffs) return 127;
|
||||
if (PCM_CHECK(c.chan)) return 127;
|
||||
if (c.chan==adpcmChan) return 255;
|
||||
if (pretendYMU) return 127;
|
||||
return 63;
|
||||
|
@ -2397,7 +2480,7 @@ DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) {
|
|||
}
|
||||
|
||||
int DivPlatformOPL::mapVelocity(int ch, float vel) {
|
||||
if (ch>=pcmChanOffs) return vel*127.0;
|
||||
if (PCM_CHECK(ch)) return vel*127.0;
|
||||
if (ch==adpcmChan) return vel*255.0;
|
||||
// -0.75dB per step
|
||||
// -6: 64: 8
|
||||
|
@ -2487,6 +2570,7 @@ void DivPlatformOPL::reset() {
|
|||
OPL3_Reset(&fm,rate);
|
||||
}
|
||||
}
|
||||
pcm.reset();
|
||||
|
||||
if (dumpWrites) {
|
||||
addWrite(0xffffffff,0);
|
||||
|
@ -2512,9 +2596,9 @@ void DivPlatformOPL::reset() {
|
|||
for (int i=0; i<totalChans; i++) {
|
||||
chan[i]=DivPlatformOPL::Channel();
|
||||
chan[i].std.setEngine(parent);
|
||||
chan[i].vol=(i>=pcmChanOffs)?0x7f:0x3f;
|
||||
chan[i].outVol=(i>=pcmChanOffs)?0x7f:0x3f;
|
||||
chan[i].pan=(i>=pcmChanOffs)?0:3;
|
||||
chan[i].vol=(PCM_CHECK(i))?0x7f:0x3f;
|
||||
chan[i].outVol=(PCM_CHECK(i))?0x7f:0x3f;
|
||||
chan[i].pan=(PCM_CHECK(i))?0:3;
|
||||
}
|
||||
|
||||
if (adpcmChan>=0) {
|
||||
|
@ -2791,16 +2875,22 @@ void DivPlatformOPL::setFlags(const DivConfig& flags) {
|
|||
break;
|
||||
}
|
||||
switch (flags.getInt("ramSize",0)) {
|
||||
case 0x01:
|
||||
case 0x01: // 2MB (512KB 512KB 512KB 512KB)
|
||||
ramSize=0x200000;
|
||||
break;
|
||||
case 0x02:
|
||||
case 0x02: // 1MB (512KB 512KB)
|
||||
ramSize=0x100000;
|
||||
break;
|
||||
case 0x03:
|
||||
case 0x03: // 640KB (512KB 128KB)
|
||||
ramSize=0xa0000;
|
||||
break;
|
||||
case 0x04: // 512KB
|
||||
ramSize=0x80000;
|
||||
break;
|
||||
case 0x04:
|
||||
case 0x05: // 256KB (128KB 128KB)
|
||||
ramSize=0x40000;
|
||||
break;
|
||||
case 0x06: // 128KB
|
||||
ramSize=0x20000;
|
||||
break;
|
||||
default:
|
||||
|
@ -2808,6 +2898,7 @@ void DivPlatformOPL::setFlags(const DivConfig& flags) {
|
|||
break;
|
||||
}
|
||||
CHECK_CUSTOM_CLOCK;
|
||||
pcm.setClockFrequency(chipClock);
|
||||
rate=chipClock/768;
|
||||
chipRateBase=chipClock/684;
|
||||
immWrite(0x202,(ramSize<=0x200000)?0x10:0x00);
|
||||
|
@ -3038,6 +3129,7 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, const DivConfi
|
|||
pcmMemLen=0;
|
||||
iface.pcmMem=pcmMem;
|
||||
iface.sampleBank=0;
|
||||
pcmMemory.memory=pcmMem;
|
||||
}
|
||||
|
||||
reset();
|
||||
|
|
|
@ -30,6 +30,7 @@ extern "C" {
|
|||
#include "sound/ymfm/ymfm_adpcm.h"
|
||||
#include "sound/ymfm/ymfm_opl.h"
|
||||
#include "sound/ymfm/ymfm_pcm.h"
|
||||
#include "sound/ymf278b/ymf278.h"
|
||||
|
||||
class DivOPLAInterface: public ymfm::ymfm_interface {
|
||||
public:
|
||||
|
@ -41,6 +42,18 @@ class DivOPLAInterface: public ymfm::ymfm_interface {
|
|||
DivOPLAInterface(): adpcmBMem(NULL), pcmMem(NULL), sampleBank(0) {}
|
||||
};
|
||||
|
||||
class DivYMF278MemoryInterface: public MemoryInterface {
|
||||
public:
|
||||
unsigned char* memory;
|
||||
DivYMF278MemoryInterface(unsigned size_) : memory(NULL), size(size_) {};
|
||||
byte operator[](unsigned address) const override;
|
||||
unsigned getSize() const override { return size; };
|
||||
void write(unsigned address, byte value) override {};
|
||||
void clear(byte value) override {};
|
||||
private:
|
||||
unsigned size;
|
||||
};
|
||||
|
||||
class DivPlatformOPL: public DivDispatch {
|
||||
protected:
|
||||
struct Channel: public SharedChannel<int> {
|
||||
|
@ -96,6 +109,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
unsigned char* pcmMem;
|
||||
size_t pcmMemLen;
|
||||
DivOPLAInterface iface;
|
||||
DivYMF278MemoryInterface pcmMemory;
|
||||
unsigned int sampleOffB[256];
|
||||
unsigned int sampleOffPCM[256];
|
||||
bool sampleLoaded[256];
|
||||
|
@ -130,6 +144,7 @@ class DivPlatformOPL: public DivDispatch {
|
|||
|
||||
// chips
|
||||
opl3_chip fm;
|
||||
YMF278 pcm;
|
||||
ymfm::ym3526* fm_ymfm1;
|
||||
ymfm::ym3812* fm_ymfm2;
|
||||
ymfm::y8950* fm_ymfm8950;
|
||||
|
@ -143,7 +158,6 @@ class DivPlatformOPL: public DivDispatch {
|
|||
int octave(int freq);
|
||||
int toFreq(int freq);
|
||||
double NOTE_ADPCMB(int note);
|
||||
double NOTE_OPL4(int ch, int note);
|
||||
void commitState(int ch, DivInstrument* ins);
|
||||
|
||||
friend void putDispatchChip(void*,int);
|
||||
|
@ -194,6 +208,10 @@ class DivPlatformOPL: public DivDispatch {
|
|||
void renderSamples(int chipID);
|
||||
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
|
||||
void quit();
|
||||
YMF278& getChip();
|
||||
DivPlatformOPL():
|
||||
pcmMemory(0x400000),
|
||||
pcm(pcmMemory) {}
|
||||
~DivPlatformOPL();
|
||||
};
|
||||
#endif
|
||||
|
|
|
@ -41,3 +41,10 @@ uint8_t DivOPLAInterface::ymfm_external_read(ymfm::access_class type, uint32_t a
|
|||
|
||||
void DivOPLAInterface::ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data) {
|
||||
}
|
||||
|
||||
byte DivYMF278MemoryInterface::operator[](unsigned address) const {
|
||||
if (memory && address<size) {
|
||||
return memory[address];
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -29,6 +29,10 @@
|
|||
// interaction with the FM registers (e.g. the NEW2 bit) is currently handled
|
||||
// in the MSXMoonSound class.
|
||||
|
||||
// MODIFIED:
|
||||
// Add YMW258 support by Grauw
|
||||
// Add DO1 output support by cam900
|
||||
|
||||
#include "ymf278.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
@ -476,10 +480,12 @@ static constexpr int vol_factor(int x, unsigned envVol)
|
|||
return (x * ((0x8000 * vol_mul) >> vol_shift)) >> 15;
|
||||
}
|
||||
|
||||
void YMF278Base::generate(short& left, short& right, short* channelBufs)
|
||||
void YMF278Base::generate(short& fleft, short& fright, short& rleft, short& rright, short* channelBufs)
|
||||
{
|
||||
int sampleLeft = 0;
|
||||
int sampleRight = 0;
|
||||
int sampleFLeft = 0;
|
||||
int sampleFRight = 0;
|
||||
int sampleRLeft = 0;
|
||||
int sampleRRight = 0;
|
||||
for (size_t i = 0, count = slots.size(); i < count; i++) {
|
||||
Slot& sl = slots[i];
|
||||
if (sl.state == EG_OFF) {
|
||||
|
@ -512,8 +518,16 @@ void YMF278Base::generate(short& left, short& right, short* channelBufs)
|
|||
volLeft = (0x20 - (volLeft & 0x0f)) >> (volLeft >> 4);
|
||||
volRight = (0x20 - (volRight & 0x0f)) >> (volRight >> 4);
|
||||
|
||||
sampleLeft += (smplOut * volLeft ) >> 5;
|
||||
sampleRight += (smplOut * volRight) >> 5;
|
||||
if (sl.ch)
|
||||
{
|
||||
sampleRLeft += (smplOut * volLeft ) >> 5;
|
||||
sampleRRight += (smplOut * volRight) >> 5;
|
||||
}
|
||||
else
|
||||
{
|
||||
sampleFLeft += (smplOut * volLeft ) >> 5;
|
||||
sampleFRight += (smplOut * volRight) >> 5;
|
||||
}
|
||||
|
||||
unsigned step = (sl.lfo_active && sl.vib)
|
||||
? calcStep(sl.OCT, sl.FN, sl.compute_vib())
|
||||
|
@ -531,8 +545,10 @@ void YMF278Base::generate(short& left, short& right, short* channelBufs)
|
|||
}
|
||||
advance();
|
||||
|
||||
left = sampleLeft >> 4;
|
||||
right = sampleRight >> 4;
|
||||
fleft = sampleFLeft >> 4;
|
||||
fright = sampleFRight >> 4;
|
||||
rleft = sampleRLeft >> 4;
|
||||
rright = sampleRRight >> 4;
|
||||
}
|
||||
|
||||
void YMF278Base::keyOnHelper(Slot& slot)
|
||||
|
@ -683,14 +699,8 @@ void YMF278::writeReg(byte reg, byte data)
|
|||
break;
|
||||
}
|
||||
case 4:
|
||||
if (data & 0x10) {
|
||||
// output to DO1 pin:
|
||||
// this pin is not used in moonsound
|
||||
// we emulate this by muting the sound
|
||||
slot.pan = 8; // both left/right -inf dB
|
||||
} else {
|
||||
slot.pan = data & 0x0F;
|
||||
}
|
||||
slot.ch = data & 0x10;
|
||||
slot.pan = data & 0x0F;
|
||||
|
||||
if (data & 0x20) {
|
||||
// LFO reset
|
||||
|
|
|
@ -35,7 +35,7 @@ public:
|
|||
double getSampleRate();
|
||||
virtual void reset();
|
||||
|
||||
void generate(short& left, short& right, short* channelBufs = nullptr);
|
||||
void generate(short& fleft, short& fright, short& rleft, short& rright, short* channelBufs = nullptr);
|
||||
|
||||
class Slot final {
|
||||
public:
|
||||
|
@ -71,6 +71,7 @@ public:
|
|||
uint8_t TLdest; // destination total level
|
||||
uint8_t TL; // total level (goes towards TLdest)
|
||||
uint8_t pan; // panpot 0..15
|
||||
bool ch; // channel select
|
||||
bool keyon; // slot keyed on
|
||||
bool DAMP;
|
||||
uint8_t lfo; // LFO speed 0..7
|
||||
|
@ -115,10 +116,10 @@ public:
|
|||
byte readReg(byte reg);
|
||||
byte peekReg(byte reg) const;
|
||||
|
||||
void generateMix(short fmL, short fmR, short& bufL, short& bufR, short* channelBufs = nullptr) {
|
||||
generate(bufL, bufR, channelBufs);
|
||||
bufL = std::min(std::max((pcmMixL * bufL + fmMixL * fmL) >> 4, -0x8000), 0x7fff);
|
||||
bufR = std::min(std::max((pcmMixR * bufR + fmMixR * fmR) >> 4, -0x8000), 0x7fff);;
|
||||
void generateMix(short fmL, short fmR, short& bufFL, short& bufFR, short& bufRL, short& bufRR, short* channelBufs = nullptr) {
|
||||
generate(bufFL, bufFR, bufRL, bufRR, channelBufs);
|
||||
bufFL = std::min(std::max((pcmMixL * bufFL + fmMixL * fmL) >> 4, -0x8000), 0x7fff);
|
||||
bufFR = std::min(std::max((pcmMixR * bufFR + fmMixR * fmR) >> 4, -0x8000), 0x7fff);;
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -294,6 +294,7 @@ const char* aboutLine[]={
|
|||
_N("PowerNoise emulator by scratchminer"),
|
||||
_N("ep128emu by Istvan Varga"),
|
||||
_N("NDS sound emulator by cam900"),
|
||||
_N("OpenMSX YMF278 emulator (modified version) by the openMSX developers"),
|
||||
"",
|
||||
_N("greetings to:"),
|
||||
"NEOART Costa Rica",
|
||||
|
|
|
@ -1737,6 +1737,7 @@ class FurnaceGUI {
|
|||
int opnbCore;
|
||||
int opl2Core;
|
||||
int opl3Core;
|
||||
int opl4Core;
|
||||
int esfmCore;
|
||||
int opllCore;
|
||||
int ayCore;
|
||||
|
@ -1763,6 +1764,7 @@ class FurnaceGUI {
|
|||
int opnbCoreRender;
|
||||
int opl2CoreRender;
|
||||
int opl3CoreRender;
|
||||
int opl4CoreRender;
|
||||
int esfmCoreRender;
|
||||
int opllCoreRender;
|
||||
int ayCoreRender;
|
||||
|
@ -1995,6 +1997,7 @@ class FurnaceGUI {
|
|||
opnbCore(1),
|
||||
opl2Core(0),
|
||||
opl3Core(0),
|
||||
opl4Core(0),
|
||||
esfmCore(0),
|
||||
opllCore(0),
|
||||
ayCore(0),
|
||||
|
@ -2021,6 +2024,7 @@ class FurnaceGUI {
|
|||
opnbCoreRender(1),
|
||||
opl2CoreRender(0),
|
||||
opl3CoreRender(0),
|
||||
opl4CoreRender(0),
|
||||
esfmCoreRender(0),
|
||||
opllCoreRender(0),
|
||||
ayCoreRender(0),
|
||||
|
|
|
@ -189,6 +189,11 @@ const char* opl3Cores[]={
|
|||
"YMF262-LLE"
|
||||
};
|
||||
|
||||
const char* opl4Cores[]={
|
||||
"Nuked-OPL3 + OpenMSX",
|
||||
"ymfm"
|
||||
};
|
||||
|
||||
const char* esfmCores[]={
|
||||
"ESFMu",
|
||||
_N("ESFMu (fast)")
|
||||
|
@ -2046,6 +2051,17 @@ void FurnaceGUI::drawSettings() {
|
|||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::Combo("##OPL3CoreRender",&settings.opl3CoreRender,opl3Cores,3)) settingsChanged=true;
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
ImGui::Text("OPL4");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::Combo("##OPL4Core",&settings.opl4Core,opl4Cores,2)) settingsChanged=true;
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::Combo("##OPL4CoreRender",&settings.opl4CoreRender,opl4Cores,2)) settingsChanged=true;
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::AlignTextToFramePadding();
|
||||
|
@ -4959,6 +4975,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
settings.opnbCore=conf.getInt("opnbCore",1);
|
||||
settings.opl2Core=conf.getInt("opl2Core",0);
|
||||
settings.opl3Core=conf.getInt("opl3Core",0);
|
||||
settings.opl4Core=conf.getInt("opl4Core",0);
|
||||
settings.esfmCore=conf.getInt("esfmCore",0);
|
||||
settings.opllCore=conf.getInt("opllCore",0);
|
||||
settings.ayCore=conf.getInt("ayCore",0);
|
||||
|
@ -4987,6 +5004,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
settings.opnbCoreRender=conf.getInt("opnbCoreRender",1);
|
||||
settings.opl2CoreRender=conf.getInt("opl2CoreRender",0);
|
||||
settings.opl3CoreRender=conf.getInt("opl3CoreRender",0);
|
||||
settings.opl4CoreRender=conf.getInt("opl4CoreRender",0);
|
||||
settings.esfmCoreRender=conf.getInt("esfmCoreRender",0);
|
||||
settings.opllCoreRender=conf.getInt("opllCoreRender",0);
|
||||
settings.ayCoreRender=conf.getInt("ayCoreRender",0);
|
||||
|
@ -5032,6 +5050,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
clampSetting(settings.opnbCore,0,2);
|
||||
clampSetting(settings.opl2Core,0,2);
|
||||
clampSetting(settings.opl3Core,0,2);
|
||||
clampSetting(settings.opl4Core,0,1);
|
||||
clampSetting(settings.esfmCore,0,1);
|
||||
clampSetting(settings.opllCore,0,1);
|
||||
clampSetting(settings.ayCore,0,1);
|
||||
|
@ -5058,6 +5077,7 @@ void FurnaceGUI::readConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
clampSetting(settings.opnbCoreRender,0,2);
|
||||
clampSetting(settings.opl2CoreRender,0,2);
|
||||
clampSetting(settings.opl3CoreRender,0,2);
|
||||
clampSetting(settings.opl4CoreRender,0,1);
|
||||
clampSetting(settings.esfmCoreRender,0,1);
|
||||
clampSetting(settings.opllCoreRender,0,1);
|
||||
clampSetting(settings.ayCoreRender,0,1);
|
||||
|
@ -5543,6 +5563,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
conf.set("opnbCore",settings.opnbCore);
|
||||
conf.set("opl2Core",settings.opl2Core);
|
||||
conf.set("opl3Core",settings.opl3Core);
|
||||
conf.set("opl4Core",settings.opl4Core);
|
||||
conf.set("esfmCore",settings.esfmCore);
|
||||
conf.set("opllCore",settings.opllCore);
|
||||
conf.set("ayCore",settings.ayCore);
|
||||
|
@ -5571,6 +5592,7 @@ void FurnaceGUI::writeConfig(DivConfig& conf, FurnaceGUISettingGroups groups) {
|
|||
conf.set("opnbCoreRender",settings.opnbCoreRender);
|
||||
conf.set("opl2CoreRender",settings.opl2CoreRender);
|
||||
conf.set("opl3CoreRender",settings.opl3CoreRender);
|
||||
conf.set("opl4CoreRender",settings.opl4CoreRender);
|
||||
conf.set("esfmCoreRender",settings.esfmCoreRender);
|
||||
conf.set("opllCoreRender",settings.opllCoreRender);
|
||||
conf.set("ayCoreRender",settings.ayCoreRender);
|
||||
|
@ -5634,6 +5656,7 @@ void FurnaceGUI::commitSettings() {
|
|||
settings.opnbCore!=e->getConfInt("opnbCore",1) ||
|
||||
settings.opl2Core!=e->getConfInt("opl2Core",0) ||
|
||||
settings.opl3Core!=e->getConfInt("opl3Core",0) ||
|
||||
settings.opl4Core!=e->getConfInt("opl4Core",0) ||
|
||||
settings.esfmCore!=e->getConfInt("esfmCore",0) ||
|
||||
settings.opllCore!=e->getConfInt("opllCore",0) ||
|
||||
settings.ayCore!=e->getConfInt("ayCore",0) ||
|
||||
|
|
|
@ -2538,14 +2538,22 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
|||
ramSize=2;
|
||||
altered=true;
|
||||
}
|
||||
if (ImGui::RadioButton(_("512KB"),ramSize==3)) {
|
||||
if (ImGui::RadioButton(_("640KB"),ramSize==3)) {
|
||||
ramSize=3;
|
||||
altered=true;
|
||||
}
|
||||
if (ImGui::RadioButton(_("128KB"),ramSize==4)) {
|
||||
if (ImGui::RadioButton(_("512KB"),ramSize==4)) {
|
||||
ramSize=4;
|
||||
altered=true;
|
||||
}
|
||||
if (ImGui::RadioButton(_("256KB"),ramSize==5)) {
|
||||
ramSize=5;
|
||||
altered=true;
|
||||
}
|
||||
if (ImGui::RadioButton(_("128KB"),ramSize==6)) {
|
||||
ramSize=6;
|
||||
altered=true;
|
||||
}
|
||||
ImGui::Unindent();
|
||||
|
||||
if (altered) {
|
||||
|
|
|
@ -333,6 +333,7 @@ TAParamResult pVersion(String) {
|
|||
printf("- PowerNoise emulator by scratchminer (MIT)\n");
|
||||
printf("- ep128emu by Istvan Varga (GPLv2)\n");
|
||||
printf("- NDS sound emulator by cam900 (zlib license)\n");
|
||||
printf("- OpenMSX YMF278 emulator (modified version) by the openMSX developers (GPLv2)\n");
|
||||
return TA_PARAM_QUIT;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue