Prepare to (very) partially OPL4 support
This commit is contained in:
parent
73c301dd0e
commit
c08edb1254
1
extern/adpcm-xq
vendored
Submodule
1
extern/adpcm-xq
vendored
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 6220fed7655e86a29702b45dbc641a028ed5a4bf
|
|
@ -760,6 +760,18 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
|
||||||
case DIV_SYSTEM_SID2:
|
case DIV_SYSTEM_SID2:
|
||||||
dispatch=new DivPlatformSID2;
|
dispatch=new DivPlatformSID2;
|
||||||
break;
|
break;
|
||||||
|
case DIV_SYSTEM_OPL4:
|
||||||
|
dispatch=new DivPlatformOPL;
|
||||||
|
((DivPlatformOPL*)dispatch)->setOPLType(4,false);
|
||||||
|
// YMFM for now
|
||||||
|
((DivPlatformOPL*)dispatch)->setCore(1);
|
||||||
|
break;
|
||||||
|
case DIV_SYSTEM_OPL4_DRUMS:
|
||||||
|
dispatch=new DivPlatformOPL;
|
||||||
|
((DivPlatformOPL*)dispatch)->setOPLType(4,true);
|
||||||
|
// YMFM for now
|
||||||
|
((DivPlatformOPL*)dispatch)->setCore(1);
|
||||||
|
break;
|
||||||
case DIV_SYSTEM_DUMMY:
|
case DIV_SYSTEM_DUMMY:
|
||||||
dispatch=new DivPlatformDummy;
|
dispatch=new DivPlatformDummy;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -159,6 +159,22 @@ const int orderedOpsL[4]={
|
||||||
#define ADDR_FREQH 0xb0
|
#define ADDR_FREQH 0xb0
|
||||||
#define ADDR_LR_FB_ALG 0xc0
|
#define ADDR_LR_FB_ALG 0xc0
|
||||||
|
|
||||||
|
|
||||||
|
#define PCM_ADDR_WAVE_L 0x208 // Wavetable number LSB
|
||||||
|
#define PCM_ADDR_WAVE_H_FN_L 0x220 // Wavetable number MSB, F-number LSB
|
||||||
|
#define PCM_ADDR_FN_H_PR_OCT 0x238 // F-number MSB, Pseudo-reverb, Octave
|
||||||
|
#define PCM_ADDR_TL 0x250 // Total level, Level direct
|
||||||
|
#define PCM_ADDR_KEY_DAMP_LFORST_CH_PAN 0x268 // Key, Damp, LFO Reset, Channel select, Panpot
|
||||||
|
|
||||||
|
#define PCM_ADDR_LFO_VIB 0x280
|
||||||
|
#define PCM_ADDR_AR_D1R 0x298
|
||||||
|
#define PCM_ADDR_DL_D2R 0x2b0
|
||||||
|
#define PCM_ADDR_RC_RR 0x2c8
|
||||||
|
#define PCM_ADDR_AM 0x2e0
|
||||||
|
|
||||||
|
#define PCM_ADDR_MIX_FM 0x2f8
|
||||||
|
#define PCM_ADDR_MIX_PCM 0x2f9
|
||||||
|
|
||||||
void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
|
void DivPlatformOPL::acquire_nuked(short** buf, size_t len) {
|
||||||
thread_local short o[4];
|
thread_local short o[4];
|
||||||
thread_local int os[4];
|
thread_local int os[4];
|
||||||
|
@ -505,6 +521,103 @@ void DivPlatformOPL::acquire_ymfm3(short** buf, size_t len) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DivPlatformOPL::acquire_ymfm4(short** buf, size_t len) {
|
||||||
|
ymfm::ymfm_output<6> out;
|
||||||
|
|
||||||
|
ymfm::ymf278b::fm_engine* fme=fm_ymfm4->debug_fm_engine();
|
||||||
|
ymfm::pcm_engine* pcme=fm_ymfm4->debug_pcm_engine();
|
||||||
|
ymfm::fm_channel<ymfm::opl_registers_base<4>>* fmChan[18];
|
||||||
|
ymfm::pcm_channel* pcmChan[24];
|
||||||
|
|
||||||
|
for (int i=0; i<18; i++) {
|
||||||
|
fmChan[i]=fme->debug_channel(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i=0; i<24; i++) {
|
||||||
|
pcmChan[i]=pcme->debug_channel(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t h=0; h<len; h++) {
|
||||||
|
if (!writes.empty() && --delay<0) {
|
||||||
|
delay=1;
|
||||||
|
QueuedWrite& w=writes.front();
|
||||||
|
|
||||||
|
fm_ymfm4->write((w.addr&0x200)?4:(w.addr&0x100)?2:0,w.addr);
|
||||||
|
fm_ymfm4->write((w.addr&0x200)?5:1,w.val);
|
||||||
|
|
||||||
|
regPool[(w.addr&0x200)?(0x200+(w.addr&255)):(w.addr&511)]=w.val;
|
||||||
|
writes.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
fm_ymfm4->generate(&out,1);
|
||||||
|
|
||||||
|
buf[0][h]=out.data[4]>>1; // FM + PCM left
|
||||||
|
if (totalOutputs>1) {
|
||||||
|
buf[1][h]=out.data[5]>>1; // FM + PCM right
|
||||||
|
}
|
||||||
|
if (totalOutputs>2) {
|
||||||
|
buf[2][h]=out.data[0]>>1; // FM left
|
||||||
|
}
|
||||||
|
if (totalOutputs>3) {
|
||||||
|
buf[3][h]=out.data[1]>>1; // FM right
|
||||||
|
}
|
||||||
|
if (totalOutputs==6) {
|
||||||
|
buf[4][h]=out.data[2]>>1; // PCM left
|
||||||
|
buf[5][h]=out.data[3]>>1; // PCM right
|
||||||
|
}
|
||||||
|
|
||||||
|
if (properDrums) {
|
||||||
|
for (int i=0; i<16; i++) {
|
||||||
|
unsigned char ch=(i<12 && chan[i&(~1)].fourOp)?outChanMap[i^1]: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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i=0; i<24; i++) {
|
||||||
|
unsigned char oscOffs=i+pcmChanOffs;
|
||||||
|
int chOut=pcmChan[i]->debug_output(0);
|
||||||
|
chOut+=pcmChan[i]->debug_output(1);
|
||||||
|
chOut+=pcmChan[i]->debug_output(2);
|
||||||
|
chOut+=pcmChan[i]->debug_output(3);
|
||||||
|
oscBuf[oscOffs]->data[oscBuf[oscOffs]->needle++]=CLAMP(chOut>>3,-32768,32767);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const int cycleMap[18]={
|
static const int cycleMap[18]={
|
||||||
6, 7, 8, 6, 7, 8, 0, 1, 2,
|
6, 7, 8, 6, 7, 8, 0, 1, 2,
|
||||||
0, 1, 2, 3, 4, 5, 3, 4, 5,
|
0, 1, 2, 3, 4, 5, 3, 4, 5,
|
||||||
|
@ -816,6 +929,9 @@ void DivPlatformOPL::acquire(short** buf, size_t len) {
|
||||||
case 3: case 759:
|
case 3: case 759:
|
||||||
acquire_ymfm3(buf,len);
|
acquire_ymfm3(buf,len);
|
||||||
break;
|
break;
|
||||||
|
case 4:
|
||||||
|
acquire_ymfm4(buf,len);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else { // OPL3
|
} else { // OPL3
|
||||||
acquire_nuked(buf,len);
|
acquire_nuked(buf,len);
|
||||||
|
@ -833,6 +949,9 @@ double DivPlatformOPL::NOTE_ADPCMB(int note) {
|
||||||
|
|
||||||
void DivPlatformOPL::tick(bool sysTick) {
|
void DivPlatformOPL::tick(bool sysTick) {
|
||||||
for (int i=0; i<totalChans; i++) {
|
for (int i=0; i<totalChans; i++) {
|
||||||
|
if (i>=pcmChanOffs) { // OPL4 PCM
|
||||||
|
chan[i].std.next();
|
||||||
|
} else {
|
||||||
int ops=(slots[3][i]!=255 && chan[i].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][i]!=255 && chan[i].state.ops==4 && oplType==3)?4:2;
|
||||||
chan[i].std.next();
|
chan[i].std.next();
|
||||||
|
|
||||||
|
@ -976,6 +1095,7 @@ void DivPlatformOPL::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int hardResetElapsed=0;
|
int hardResetElapsed=0;
|
||||||
bool mustHardReset=false;
|
bool mustHardReset=false;
|
||||||
|
@ -1090,7 +1210,7 @@ void DivPlatformOPL::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<512; i++) {
|
for (int i=0; i<768; i++) {
|
||||||
if (pendingWrites[i]!=oldWrites[i]) {
|
if (pendingWrites[i]!=oldWrites[i]) {
|
||||||
if ((i>=0x80 && i<0xa0)) {
|
if ((i>=0x80 && i<0xa0)) {
|
||||||
if (weWillWriteRRLater[i-0x80]) continue;
|
if (weWillWriteRRLater[i-0x80]) continue;
|
||||||
|
@ -1104,6 +1224,9 @@ void DivPlatformOPL::tick(bool sysTick) {
|
||||||
|
|
||||||
bool updateDrums=false;
|
bool updateDrums=false;
|
||||||
for (int i=0; i<totalChans; i++) {
|
for (int i=0; i<totalChans; i++) {
|
||||||
|
if (i>=pcmChanOffs) { // OPL4 PCM
|
||||||
|
|
||||||
|
} else {
|
||||||
if (chan[i].freqChanged) {
|
if (chan[i].freqChanged) {
|
||||||
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,octave(chan[i].baseFreq)*2,chan[i].pitch2,chipClock,CHIP_FREQBASE);
|
chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,octave(chan[i].baseFreq)*2,chan[i].pitch2,chipClock,CHIP_FREQBASE);
|
||||||
if (chan[i].fixedFreq>0) chan[i].freq=chan[i].fixedFreq;
|
if (chan[i].fixedFreq>0) chan[i].freq=chan[i].fixedFreq;
|
||||||
|
@ -1137,6 +1260,7 @@ void DivPlatformOPL::tick(bool sysTick) {
|
||||||
}
|
}
|
||||||
chan[i].freqChanged=false;
|
chan[i].freqChanged=false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (updateDrums) {
|
if (updateDrums) {
|
||||||
immWrite(0xbd,(dam<<7)|(dvb<<6)|(properDrums<<5)|drumState);
|
immWrite(0xbd,(dam<<7)|(dvb<<6)|(properDrums<<5)|drumState);
|
||||||
|
@ -1369,7 +1493,9 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
}
|
}
|
||||||
switch (c.cmd) {
|
switch (c.cmd) {
|
||||||
case DIV_CMD_NOTE_ON: {
|
case DIV_CMD_NOTE_ON: {
|
||||||
if (c.chan==adpcmChan) { // ADPCM
|
if (c.chan>=pcmChanOffs) { // OPL4 PCM
|
||||||
|
|
||||||
|
} else if (c.chan==adpcmChan) { // ADPCM
|
||||||
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
DivInstrument* ins=parent->getIns(chan[c.chan].ins,DIV_INS_FM);
|
||||||
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255;
|
chan[c.chan].macroVolMul=ins->type==DIV_INS_AMIGA?64:255;
|
||||||
if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) {
|
if (ins->type==DIV_INS_AMIGA || ins->type==DIV_INS_ADPCMB) {
|
||||||
|
@ -1553,7 +1679,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
if (oplType!=3) break;
|
if (oplType!=3) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
chan[c.chan].pan&=~3;
|
chan[c.chan].pan&=~3;
|
||||||
if (c.value==0 && c.value2==0 && compatPan) {
|
if (c.value==0 && c.value2==0 && ((chipType!=4) && compatPan)) {
|
||||||
chan[c.chan].pan|=3;
|
chan[c.chan].pan|=3;
|
||||||
} else {
|
} else {
|
||||||
chan[c.chan].pan|=(c.value>0)|((c.value2>0)<<1);
|
chan[c.chan].pan|=(c.value>0)|((c.value2>0)<<1);
|
||||||
|
@ -1659,6 +1785,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_LFO: {
|
case DIV_CMD_FM_LFO: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
if (c.value&2) {
|
if (c.value&2) {
|
||||||
dvb=c.value&1;
|
dvb=c.value&1;
|
||||||
|
@ -1669,6 +1796,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_FB: {
|
case DIV_CMD_FM_FB: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
chan[c.chan].state.fb=c.value&7;
|
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;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
|
@ -1686,6 +1814,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_MULT: {
|
case DIV_CMD_FM_MULT: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value>=ops) break;
|
if (c.value>=ops) break;
|
||||||
|
@ -1698,6 +1827,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_TL: {
|
case DIV_CMD_FM_TL: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value>=ops) break;
|
if (c.value>=ops) break;
|
||||||
|
@ -1718,6 +1848,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_AR: {
|
case DIV_CMD_FM_AR: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
|
@ -1741,6 +1872,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_DR: {
|
case DIV_CMD_FM_DR: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
|
@ -1764,6 +1896,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_SL: {
|
case DIV_CMD_FM_SL: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
|
@ -1787,6 +1920,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_RR: {
|
case DIV_CMD_FM_RR: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
|
@ -1810,6 +1944,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_AM: {
|
case DIV_CMD_FM_AM: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
|
@ -1833,6 +1968,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_VIB: {
|
case DIV_CMD_FM_VIB: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
|
@ -1856,6 +1992,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_SUS: {
|
case DIV_CMD_FM_SUS: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
|
@ -1879,6 +2016,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_KSR: {
|
case DIV_CMD_FM_KSR: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
if (c.value<0) {
|
if (c.value<0) {
|
||||||
|
@ -1902,6 +2040,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_WS: {
|
case DIV_CMD_FM_WS: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
if (oplType<2) break;
|
if (oplType<2) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
|
@ -1926,6 +2065,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DIV_CMD_FM_RS: {
|
case DIV_CMD_FM_RS: {
|
||||||
|
if (c.chan>=pcmChanOffs) break;
|
||||||
if (c.chan==adpcmChan) break;
|
if (c.chan==adpcmChan) break;
|
||||||
if (oplType<2) break;
|
if (oplType<2) break;
|
||||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||||
|
@ -1974,6 +2114,10 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
chanMap=properDrums?chanMapOPL3Drums:chanMapOPL3;
|
chanMap=properDrums?chanMapOPL3Drums:chanMapOPL3;
|
||||||
melodicChans=properDrums?15:18;
|
melodicChans=properDrums?15:18;
|
||||||
totalChans=properDrums?20:18;
|
totalChans=properDrums?20:18;
|
||||||
|
if (chipType==4) {
|
||||||
|
pcmChanOffs=totalChans;
|
||||||
|
totalChans+=24;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
chanMap=properDrums?chanMapOPL2Drums:chanMapOPL2;
|
chanMap=properDrums?chanMapOPL2Drums:chanMapOPL2;
|
||||||
melodicChans=properDrums?6:9;
|
melodicChans=properDrums?6:9;
|
||||||
|
@ -1995,6 +2139,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
||||||
chan[c.chan].std.restart(c.value);
|
chan[c.chan].std.restart(c.value);
|
||||||
break;
|
break;
|
||||||
case DIV_CMD_GET_VOLMAX:
|
case DIV_CMD_GET_VOLMAX:
|
||||||
|
if (c.chan>=pcmChanOffs) return 127;
|
||||||
if (c.chan==adpcmChan) return 255;
|
if (c.chan==adpcmChan) return 255;
|
||||||
if (pretendYMU) return 127;
|
if (pretendYMU) return 127;
|
||||||
return 63;
|
return 63;
|
||||||
|
@ -2019,6 +2164,10 @@ void DivPlatformOPL::forceIns() {
|
||||||
chanMap=properDrums?chanMapOPL3Drums:chanMapOPL3;
|
chanMap=properDrums?chanMapOPL3Drums:chanMapOPL3;
|
||||||
melodicChans=properDrums?15:18;
|
melodicChans=properDrums?15:18;
|
||||||
totalChans=properDrums?20:18;
|
totalChans=properDrums?20:18;
|
||||||
|
if (chipType==4) {
|
||||||
|
pcmChanOffs=totalChans;
|
||||||
|
totalChans+=24;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
chanMap=properDrums?chanMapOPL2Drums:chanMapOPL2;
|
chanMap=properDrums?chanMapOPL2Drums:chanMapOPL2;
|
||||||
melodicChans=properDrums?6:9;
|
melodicChans=properDrums?6:9;
|
||||||
|
@ -2067,7 +2216,7 @@ void DivPlatformOPL::forceIns() {
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
for (int i=0; i<512; i++) {
|
for (int i=0; i<768; i++) {
|
||||||
oldWrites[i]=-1;
|
oldWrites[i]=-1;
|
||||||
}
|
}
|
||||||
immWrite(0xbd,(dam<<7)|(dvb<<6)|(properDrums<<5)|drumState);
|
immWrite(0xbd,(dam<<7)|(dvb<<6)|(properDrums<<5)|drumState);
|
||||||
|
@ -2145,12 +2294,12 @@ unsigned char* DivPlatformOPL::getRegisterPool() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformOPL::getRegisterPoolSize() {
|
int DivPlatformOPL::getRegisterPoolSize() {
|
||||||
return (oplType<3)?256:512;
|
return (chipType==4)?768:((oplType<3)?256:512);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformOPL::reset() {
|
void DivPlatformOPL::reset() {
|
||||||
while (!writes.empty()) writes.pop();
|
while (!writes.empty()) writes.pop();
|
||||||
memset(regPool,0,512);
|
memset(regPool,0,768);
|
||||||
|
|
||||||
dacVal=0;
|
dacVal=0;
|
||||||
dacVal2=0;
|
dacVal2=0;
|
||||||
|
@ -2204,6 +2353,9 @@ void DivPlatformOPL::reset() {
|
||||||
case 3: case 759:
|
case 3: case 759:
|
||||||
fm_ymfm3->reset();
|
fm_ymfm3->reset();
|
||||||
break;
|
break;
|
||||||
|
case 4:
|
||||||
|
fm_ymfm4->reset();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (downsample) {
|
if (downsample) {
|
||||||
|
@ -2223,6 +2375,10 @@ void DivPlatformOPL::reset() {
|
||||||
outChanMap=outChanMapOPL3;
|
outChanMap=outChanMapOPL3;
|
||||||
melodicChans=properDrums?15:18;
|
melodicChans=properDrums?15:18;
|
||||||
totalChans=properDrums?20:18;
|
totalChans=properDrums?20:18;
|
||||||
|
if (chipType==4) {
|
||||||
|
pcmChanOffs=totalChans;
|
||||||
|
totalChans+=24;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
chanMap=properDrums?chanMapOPL2Drums:chanMapOPL2;
|
chanMap=properDrums?chanMapOPL2Drums:chanMapOPL2;
|
||||||
outChanMap=outChanMapOPL2;
|
outChanMap=outChanMapOPL2;
|
||||||
|
@ -2256,7 +2412,7 @@ void DivPlatformOPL::reset() {
|
||||||
fm.channel[outChanMap[i]].muted=isMuted[i];
|
fm.channel[outChanMap[i]].muted=isMuted[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i=0; i<512; i++) {
|
for (int i=0; i<768; i++) {
|
||||||
oldWrites[i]=-1;
|
oldWrites[i]=-1;
|
||||||
pendingWrites[i]=-1;
|
pendingWrites[i]=-1;
|
||||||
}
|
}
|
||||||
|
@ -2277,8 +2433,14 @@ void DivPlatformOPL::reset() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oplType==3) { // enable OPL3 features
|
if (oplType==3) { // enable OPL3 features
|
||||||
|
if (chipType==4) {
|
||||||
|
immWrite(0x105,3);
|
||||||
|
// Reset wavetable header
|
||||||
|
immWrite(0x202,(ramSize<=0x200000)?0x10:0x00);
|
||||||
|
} else {
|
||||||
immWrite(0x105,1);
|
immWrite(0x105,1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
update4OpMask=true;
|
update4OpMask=true;
|
||||||
dam=false;
|
dam=false;
|
||||||
|
@ -2368,6 +2530,8 @@ void DivPlatformOPL::setOPLType(int type, bool drums) {
|
||||||
pretendYMU=true;
|
pretendYMU=true;
|
||||||
adpcmChan=16;
|
adpcmChan=16;
|
||||||
} else if (type==4) {
|
} else if (type==4) {
|
||||||
|
pcmChanOffs=totalChans;
|
||||||
|
totalChans+=24;
|
||||||
chipFreqBase=32768*684;
|
chipFreqBase=32768*684;
|
||||||
downsample=true;
|
downsample=true;
|
||||||
}
|
}
|
||||||
|
@ -2493,18 +2657,36 @@ void DivPlatformOPL::setFlags(const DivConfig& flags) {
|
||||||
case 4:
|
case 4:
|
||||||
switch (flags.getInt("clockSel",0)) {
|
switch (flags.getInt("clockSel",0)) {
|
||||||
case 0x01:
|
case 0x01:
|
||||||
chipClock=COLOR_PAL*32.0/5.0;
|
chipClock=COLOR_NTSC*8.0;
|
||||||
break;
|
break;
|
||||||
case 0x02:
|
case 0x02:
|
||||||
chipClock=33868800.0;
|
chipClock=COLOR_PAL*32.0/5.0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
chipClock=COLOR_NTSC*8.0;
|
chipClock=33868800.0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (flags.getInt("ramSize",0)) {
|
||||||
|
case 0x01:
|
||||||
|
ramSize=0x200000;
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
ramSize=0x100000;
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
ramSize=0x80000;
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
ramSize=0x20000;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ramSize=0x400000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
CHECK_CUSTOM_CLOCK;
|
CHECK_CUSTOM_CLOCK;
|
||||||
rate=chipClock/768;
|
rate=chipClock/768;
|
||||||
chipRateBase=chipClock/684;
|
chipRateBase=chipClock/684;
|
||||||
|
immWrite(0x202,(ramSize<=0x200000)?0x10:0x00);
|
||||||
break;
|
break;
|
||||||
case 759:
|
case 759:
|
||||||
rate=48000;
|
rate=48000;
|
||||||
|
@ -2514,21 +2696,25 @@ void DivPlatformOPL::setFlags(const DivConfig& flags) {
|
||||||
}
|
}
|
||||||
compatPan=flags.getBool("compatPan",false);
|
compatPan=flags.getBool("compatPan",false);
|
||||||
|
|
||||||
for (int i=0; i<20; i++) {
|
for (int i=0; i<44; i++) {
|
||||||
oscBuf[i]->rate=rate;
|
oscBuf[i]->rate=rate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const void* DivPlatformOPL::getSampleMem(int index) {
|
const void* DivPlatformOPL::getSampleMem(int index) {
|
||||||
return (index==0 && adpcmChan>=0) ? adpcmBMem : NULL;
|
return (index==0 && pcmChanOffs>=0)?pcmMem:
|
||||||
|
(index==0 && adpcmChan>=0)?adpcmBMem:NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t DivPlatformOPL::getSampleMemCapacity(int index) {
|
size_t DivPlatformOPL::getSampleMemCapacity(int index) {
|
||||||
return (index==0 && adpcmChan>=0) ? 262144 : 0;
|
return (index==0 && pcmChanOffs>=0)?
|
||||||
|
((ramSize<=0x200000)?0x200000+ramSize:ramSize):
|
||||||
|
((index==0 && adpcmChan>=0)?262144:0);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t DivPlatformOPL::getSampleMemUsage(int index) {
|
size_t DivPlatformOPL::getSampleMemUsage(int index) {
|
||||||
return (index==0 && adpcmChan>=0) ? adpcmBMemLen : 0;
|
return (index==0 && pcmChanOffs>=0)?pcmMemLen:
|
||||||
|
(index==0 && adpcmChan>=0)?adpcmBMemLen:0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DivPlatformOPL::isSampleLoaded(int index, int sample) {
|
bool DivPlatformOPL::isSampleLoaded(int index, int sample) {
|
||||||
|
@ -2538,20 +2724,109 @@ bool DivPlatformOPL::isSampleLoaded(int index, int sample) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const DivMemoryComposition* DivPlatformOPL::getMemCompo(int index) {
|
const DivMemoryComposition* DivPlatformOPL::getMemCompo(int index) {
|
||||||
if (adpcmChan<0) return NULL;
|
if ((adpcmChan<0) && (pcmChanOffs<0)) return NULL;
|
||||||
if (index!=0) return NULL;
|
if (index!=0) return NULL;
|
||||||
return &memCompo;
|
return &memCompo;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformOPL::renderSamples(int sysID) {
|
void DivPlatformOPL::renderSamples(int sysID) {
|
||||||
if (adpcmChan<0) return;
|
if (adpcmChan<0 && pcmChanOffs<0) return;
|
||||||
memset(adpcmBMem,0,getSampleMemCapacity(0));
|
if (adpcmBMem!=NULL) {
|
||||||
|
memset(adpcmBMem,0,262144);
|
||||||
|
}
|
||||||
|
if (pcmMem!=NULL) {
|
||||||
|
memset(pcmMem,0,4194304);
|
||||||
|
}
|
||||||
|
memset(sampleOffPCM,0,256*sizeof(unsigned int));
|
||||||
memset(sampleOffB,0,256*sizeof(unsigned int));
|
memset(sampleOffB,0,256*sizeof(unsigned int));
|
||||||
memset(sampleLoaded,0,256*sizeof(bool));
|
memset(sampleLoaded,0,256*sizeof(bool));
|
||||||
|
|
||||||
memCompo=DivMemoryComposition();
|
memCompo=DivMemoryComposition();
|
||||||
memCompo.name="Sample Memory";
|
memCompo.name="Sample Memory";
|
||||||
|
|
||||||
|
if (pcmChanOffs>=0) { // OPL4 PCM
|
||||||
|
size_t memPos=((ramSize<=0x200000)?0x200600:0x1800);
|
||||||
|
int sampleCount=parent->song.sampleLen;
|
||||||
|
if (sampleCount>511) sampleCount=511;
|
||||||
|
for (int i=0; i<sampleCount; i++) {
|
||||||
|
DivSample* s=parent->song.sample[i];
|
||||||
|
if (!s->renderOn[0][sysID]) {
|
||||||
|
sampleOffPCM[i]=0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int length;
|
||||||
|
switch (s->depth) {
|
||||||
|
default:
|
||||||
|
case DIV_SAMPLE_DEPTH_8BIT:
|
||||||
|
length=MIN(65535,s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT));
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_16BIT:
|
||||||
|
length=MIN(131070,s->getLoopEndPosition(DIV_SAMPLE_DEPTH_16BIT));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unsigned char* src=(unsigned char*)s->getCurBuf();
|
||||||
|
int actualLength=MIN((int)(getSampleMemCapacity(0)-memPos),length);
|
||||||
|
if (actualLength>0) {
|
||||||
|
#ifdef TA_BIG_ENDIAN
|
||||||
|
memcpy(&pcmMem[memPos],src,actualLength);
|
||||||
|
#else
|
||||||
|
if (s->depth==DIV_SAMPLE_DEPTH_16BIT) {
|
||||||
|
for (int i=0; i<actualLength; i++) {
|
||||||
|
pcmMem[memPos+i]=src[i^1];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
memcpy(&pcmMem[memPos],src,actualLength);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
sampleOffPCM[i]=memPos;
|
||||||
|
memCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_SAMPLE,"Sample",i,memPos,memPos+length));
|
||||||
|
memPos+=length;
|
||||||
|
}
|
||||||
|
if (actualLength<length) {
|
||||||
|
logW("out of OPL4 PCM memory for sample %d!",i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pcmMemLen=memPos+256;
|
||||||
|
|
||||||
|
// instrument table
|
||||||
|
for (int i=0; i<sampleCount; i++) {
|
||||||
|
DivSample* s=parent->song.sample[i];
|
||||||
|
unsigned int insAddr=(i*12)+((ramSize<=0x200000)?0x200000:0);
|
||||||
|
unsigned char bitDepth;
|
||||||
|
int loop=CLAMP(s->getLoopStartPosition(DIV_SAMPLE_DEPTH_8BIT),0,0xffff);
|
||||||
|
int endPos=CLAMP(s->getLoopEndPosition(DIV_SAMPLE_DEPTH_8BIT),1,0x10000);
|
||||||
|
switch (s->depth) {
|
||||||
|
default:
|
||||||
|
case DIV_SAMPLE_DEPTH_8BIT:
|
||||||
|
bitDepth=0;
|
||||||
|
break;
|
||||||
|
case DIV_SAMPLE_DEPTH_16BIT:
|
||||||
|
bitDepth=2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pcmMem[insAddr]=(bitDepth<<6)|((sampleOffPCM[i]>>16)&0x3f);
|
||||||
|
pcmMem[1+insAddr]=(sampleOffPCM[i]>>8)&0xff;
|
||||||
|
pcmMem[2+insAddr]=(sampleOffPCM[i])&0xff;
|
||||||
|
pcmMem[3+insAddr]=(loop>>8)&0xff;
|
||||||
|
pcmMem[4+insAddr]=(loop)&0xff;
|
||||||
|
pcmMem[5+insAddr]=(endPos>>8)&0xff;
|
||||||
|
pcmMem[6+insAddr]=(endPos)&0xff;
|
||||||
|
// TODO: how to fill in rest of instrument table?
|
||||||
|
pcmMem[7+insAddr]=0; // LFO, VIB
|
||||||
|
pcmMem[8+insAddr]=0; // AR, D1R
|
||||||
|
pcmMem[9+insAddr]=0; // DL, D2R
|
||||||
|
pcmMem[10+insAddr]=0; // RC, RR
|
||||||
|
pcmMem[11+insAddr]=0; // AM
|
||||||
|
}
|
||||||
|
if (ramSize<=0x200000) {
|
||||||
|
memCompo.entries.push_back(DivMemoryEntry(DIV_MEMORY_RESERVED,"ROM data",0,0,0x200000));
|
||||||
|
}
|
||||||
|
|
||||||
|
memCompo.used=pcmMemLen;
|
||||||
|
memCompo.capacity=getSampleMemCapacity(0);
|
||||||
|
} else if (adpcmChan>=0) { // ADPCM
|
||||||
size_t memPos=0;
|
size_t memPos=0;
|
||||||
for (int i=0; i<parent->song.sampleLen; i++) {
|
for (int i=0; i<parent->song.sampleLen; i++) {
|
||||||
DivSample* s=parent->song.sample[i];
|
DivSample* s=parent->song.sample[i];
|
||||||
|
@ -2583,16 +2858,17 @@ void DivPlatformOPL::renderSamples(int sysID) {
|
||||||
|
|
||||||
memCompo.used=adpcmBMemLen;
|
memCompo.used=adpcmBMemLen;
|
||||||
memCompo.capacity=getSampleMemCapacity(0);
|
memCompo.capacity=getSampleMemCapacity(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, const DivConfig& flags) {
|
||||||
parent=p;
|
parent=p;
|
||||||
dumpWrites=false;
|
dumpWrites=false;
|
||||||
skipRegisterWrites=false;
|
skipRegisterWrites=false;
|
||||||
for (int i=0; i<20; i++) {
|
for (int i=0; i<44; i++) {
|
||||||
isMuted[i]=false;
|
isMuted[i]=false;
|
||||||
}
|
}
|
||||||
for (int i=0; i<20; i++) {
|
for (int i=0; i<44; i++) {
|
||||||
oscBuf[i]=new DivDispatchOscBuffer;
|
oscBuf[i]=new DivDispatchOscBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2600,6 +2876,7 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, const DivConfi
|
||||||
fm_ymfm2=NULL;
|
fm_ymfm2=NULL;
|
||||||
fm_ymfm8950=NULL;
|
fm_ymfm8950=NULL;
|
||||||
fm_ymfm3=NULL;
|
fm_ymfm3=NULL;
|
||||||
|
fm_ymfm4=NULL;
|
||||||
|
|
||||||
if (emuCore==1) {
|
if (emuCore==1) {
|
||||||
switch (chipType) {
|
switch (chipType) {
|
||||||
|
@ -2615,31 +2892,44 @@ int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, const DivConfi
|
||||||
case 3: case 759:
|
case 3: case 759:
|
||||||
fm_ymfm3=new ymfm::ymf262(iface);
|
fm_ymfm3=new ymfm::ymf262(iface);
|
||||||
break;
|
break;
|
||||||
|
case 4:
|
||||||
|
fm_ymfm4=new ymfm::ymf278b(iface);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setFlags(flags);
|
setFlags(flags);
|
||||||
|
|
||||||
if (adpcmChan>=0) {
|
if (adpcmChan>=0) {
|
||||||
adpcmBMem=new unsigned char[getSampleMemCapacity(0)];
|
adpcmBMem=new unsigned char[262144];
|
||||||
adpcmBMemLen=0;
|
adpcmBMemLen=0;
|
||||||
iface.adpcmBMem=adpcmBMem;
|
iface.adpcmBMem=adpcmBMem;
|
||||||
iface.sampleBank=0;
|
iface.sampleBank=0;
|
||||||
adpcmB=new ymfm::adpcm_b_engine(iface,2);
|
adpcmB=new ymfm::adpcm_b_engine(iface,2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pcmChanOffs>=0) {
|
||||||
|
pcmMem=new unsigned char[4194304];
|
||||||
|
pcmMemLen=0;
|
||||||
|
iface.pcmMem=pcmMem;
|
||||||
|
iface.sampleBank=0;
|
||||||
|
}
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
return totalChans;
|
return totalChans;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DivPlatformOPL::quit() {
|
void DivPlatformOPL::quit() {
|
||||||
for (int i=0; i<20; i++) {
|
for (int i=0; i<44; i++) {
|
||||||
delete oscBuf[i];
|
delete oscBuf[i];
|
||||||
}
|
}
|
||||||
if (adpcmChan>=0) {
|
if (adpcmChan>=0) {
|
||||||
delete adpcmB;
|
delete adpcmB;
|
||||||
delete[] adpcmBMem;
|
delete[] adpcmBMem;
|
||||||
}
|
}
|
||||||
|
if (pcmChanOffs>=0) {
|
||||||
|
delete[] pcmMem;
|
||||||
|
}
|
||||||
if (fm_ymfm1!=NULL) {
|
if (fm_ymfm1!=NULL) {
|
||||||
delete fm_ymfm1;
|
delete fm_ymfm1;
|
||||||
fm_ymfm1=NULL;
|
fm_ymfm1=NULL;
|
||||||
|
@ -2656,6 +2946,10 @@ void DivPlatformOPL::quit() {
|
||||||
delete fm_ymfm3;
|
delete fm_ymfm3;
|
||||||
fm_ymfm3=NULL;
|
fm_ymfm3=NULL;
|
||||||
}
|
}
|
||||||
|
if (fm_ymfm4!=NULL) {
|
||||||
|
delete fm_ymfm4;
|
||||||
|
fm_ymfm4=NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DivPlatformOPL::~DivPlatformOPL() {
|
DivPlatformOPL::~DivPlatformOPL() {
|
||||||
|
|
|
@ -29,14 +29,16 @@ extern "C" {
|
||||||
}
|
}
|
||||||
#include "sound/ymfm/ymfm_adpcm.h"
|
#include "sound/ymfm/ymfm_adpcm.h"
|
||||||
#include "sound/ymfm/ymfm_opl.h"
|
#include "sound/ymfm/ymfm_opl.h"
|
||||||
|
#include "sound/ymfm/ymfm_pcm.h"
|
||||||
|
|
||||||
class DivOPLAInterface: public ymfm::ymfm_interface {
|
class DivOPLAInterface: public ymfm::ymfm_interface {
|
||||||
public:
|
public:
|
||||||
unsigned char* adpcmBMem;
|
unsigned char* adpcmBMem;
|
||||||
|
unsigned char* pcmMem;
|
||||||
int sampleBank;
|
int sampleBank;
|
||||||
uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address);
|
uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address);
|
||||||
void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data);
|
void ymfm_external_write(ymfm::access_class type, uint32_t address, uint8_t data);
|
||||||
DivOPLAInterface(): adpcmBMem(NULL), sampleBank(0) {}
|
DivOPLAInterface(): adpcmBMem(NULL), pcmMem(NULL), sampleBank(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class DivPlatformOPL: public DivDispatch {
|
class DivPlatformOPL: public DivDispatch {
|
||||||
|
@ -62,9 +64,9 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
state.ops=2;
|
state.ops=2;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Channel chan[20];
|
Channel chan[44];
|
||||||
DivDispatchOscBuffer* oscBuf[20];
|
DivDispatchOscBuffer* oscBuf[44];
|
||||||
bool isMuted[20];
|
bool isMuted[44];
|
||||||
struct QueuedWrite {
|
struct QueuedWrite {
|
||||||
unsigned short addr;
|
unsigned short addr;
|
||||||
unsigned char val;
|
unsigned char val;
|
||||||
|
@ -72,7 +74,7 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
QueuedWrite(): addr(0), val(0), addrOrVal(false) {}
|
QueuedWrite(): addr(0), val(0), addrOrVal(false) {}
|
||||||
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
|
QueuedWrite(unsigned short a, unsigned char v): addr(a), val(v), addrOrVal(false) {}
|
||||||
};
|
};
|
||||||
FixedQueue<QueuedWrite,2048> writes;
|
FixedQueue<QueuedWrite,4096> writes;
|
||||||
|
|
||||||
unsigned int dacVal;
|
unsigned int dacVal;
|
||||||
unsigned int dacVal2;
|
unsigned int dacVal2;
|
||||||
|
@ -86,8 +88,11 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
|
|
||||||
unsigned char* adpcmBMem;
|
unsigned char* adpcmBMem;
|
||||||
size_t adpcmBMemLen;
|
size_t adpcmBMemLen;
|
||||||
|
unsigned char* pcmMem;
|
||||||
|
size_t pcmMemLen;
|
||||||
DivOPLAInterface iface;
|
DivOPLAInterface iface;
|
||||||
unsigned int sampleOffB[256];
|
unsigned int sampleOffB[256];
|
||||||
|
unsigned int sampleOffPCM[256];
|
||||||
bool sampleLoaded[256];
|
bool sampleLoaded[256];
|
||||||
|
|
||||||
ymfm::adpcm_b_engine* adpcmB;
|
ymfm::adpcm_b_engine* adpcmB;
|
||||||
|
@ -97,12 +102,12 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
const unsigned short* chanMap;
|
const unsigned short* chanMap;
|
||||||
const unsigned char* outChanMap;
|
const unsigned char* outChanMap;
|
||||||
int chipFreqBase, chipRateBase;
|
int chipFreqBase, chipRateBase;
|
||||||
int delay, chipType, oplType, chans, melodicChans, totalChans, adpcmChan, sampleBank, totalOutputs;
|
int delay, chipType, oplType, chans, melodicChans, totalChans, adpcmChan=-1, pcmChanOffs=-1, sampleBank, totalOutputs, ramSize;
|
||||||
unsigned char lastBusy;
|
unsigned char lastBusy;
|
||||||
unsigned char drumState;
|
unsigned char drumState;
|
||||||
unsigned char drumVol[5];
|
unsigned char drumVol[5];
|
||||||
|
|
||||||
unsigned char regPool[512];
|
unsigned char regPool[768];
|
||||||
|
|
||||||
bool properDrums, properDrumsSys, dam, dvb;
|
bool properDrums, properDrumsSys, dam, dvb;
|
||||||
|
|
||||||
|
@ -115,8 +120,8 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
|
|
||||||
bool update4OpMask, pretendYMU, downsample, compatPan;
|
bool update4OpMask, pretendYMU, downsample, compatPan;
|
||||||
|
|
||||||
short oldWrites[512];
|
short oldWrites[768];
|
||||||
short pendingWrites[512];
|
short pendingWrites[768];
|
||||||
|
|
||||||
// chips
|
// chips
|
||||||
opl3_chip fm;
|
opl3_chip fm;
|
||||||
|
@ -124,6 +129,7 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
ymfm::ym3812* fm_ymfm2;
|
ymfm::ym3812* fm_ymfm2;
|
||||||
ymfm::y8950* fm_ymfm8950;
|
ymfm::y8950* fm_ymfm8950;
|
||||||
ymfm::ymf262* fm_ymfm3;
|
ymfm::ymf262* fm_ymfm3;
|
||||||
|
ymfm::ymf278b* fm_ymfm4;
|
||||||
fmopl2_t fm_lle2;
|
fmopl2_t fm_lle2;
|
||||||
fmopl3_t fm_lle3;
|
fmopl3_t fm_lle3;
|
||||||
|
|
||||||
|
@ -141,6 +147,7 @@ class DivPlatformOPL: public DivDispatch {
|
||||||
void acquire_nukedLLE3(short** buf, size_t len);
|
void acquire_nukedLLE3(short** buf, size_t len);
|
||||||
void acquire_nuked(short** buf, size_t len);
|
void acquire_nuked(short** buf, size_t len);
|
||||||
void acquire_ymfm3(short** buf, size_t len);
|
void acquire_ymfm3(short** buf, size_t len);
|
||||||
|
void acquire_ymfm4(short** buf, size_t len);
|
||||||
void acquire_ymfm8950(short** buf, size_t len);
|
void acquire_ymfm8950(short** buf, size_t len);
|
||||||
void acquire_ymfm2(short** buf, size_t len);
|
void acquire_ymfm2(short** buf, size_t len);
|
||||||
void acquire_ymfm1(short** buf, size_t len);
|
void acquire_ymfm1(short** buf, size_t len);
|
||||||
|
|
|
@ -28,6 +28,11 @@ uint8_t DivOPLAInterface::ymfm_external_read(ymfm::access_class type, uint32_t a
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return adpcmBMem[address&0xffffff];
|
return adpcmBMem[address&0xffffff];
|
||||||
|
case ymfm::ACCESS_PCM:
|
||||||
|
if (pcmMem==NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return pcmMem[address&0x3fffff];
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -791,6 +791,8 @@ public:
|
||||||
// generate samples of sound
|
// generate samples of sound
|
||||||
void generate(output_data *output, uint32_t numsamples = 1);
|
void generate(output_data *output, uint32_t numsamples = 1);
|
||||||
|
|
||||||
|
fm_engine* debug_fm_engine() { return &m_fm; }
|
||||||
|
pcm_engine* debug_pcm_engine() { return &m_pcm; }
|
||||||
protected:
|
protected:
|
||||||
// internal state
|
// internal state
|
||||||
uint16_t m_address; // address register
|
uint16_t m_address; // address register
|
||||||
|
|
|
@ -309,6 +309,7 @@ void pcm_channel::clock(uint32_t env_counter)
|
||||||
|
|
||||||
void pcm_channel::output(output_data &output) const
|
void pcm_channel::output(output_data &output) const
|
||||||
{
|
{
|
||||||
|
m_output[0] = m_output[1] = m_output[2] = m_output[3] = 0;
|
||||||
// early out if the envelope is effectively off
|
// early out if the envelope is effectively off
|
||||||
uint32_t envelope = m_env_attenuation;
|
uint32_t envelope = m_env_attenuation;
|
||||||
if (envelope > EG_QUIET)
|
if (envelope > EG_QUIET)
|
||||||
|
@ -340,6 +341,8 @@ void pcm_channel::output(output_data &output) const
|
||||||
uint32_t outnum = m_regs.ch_output_channel(m_choffs) * 2;
|
uint32_t outnum = m_regs.ch_output_channel(m_choffs) * 2;
|
||||||
output.data[outnum + 0] += (lvol * sample) >> 15;
|
output.data[outnum + 0] += (lvol * sample) >> 15;
|
||||||
output.data[outnum + 1] += (rvol * sample) >> 15;
|
output.data[outnum + 1] += (rvol * sample) >> 15;
|
||||||
|
m_output[outnum + 0] = output.data[outnum + 0];
|
||||||
|
m_output[outnum + 1] = output.data[outnum + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -267,6 +267,8 @@ public:
|
||||||
// load a new wavetable entry
|
// load a new wavetable entry
|
||||||
void load_wavetable();
|
void load_wavetable();
|
||||||
|
|
||||||
|
int32_t debug_output(uint32_t index) const { return m_output[index]; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// internal helpers
|
// internal helpers
|
||||||
void start_attack();
|
void start_attack();
|
||||||
|
@ -291,6 +293,7 @@ private:
|
||||||
pcm_cache m_cache; // cached data
|
pcm_cache m_cache; // cached data
|
||||||
pcm_registers &m_regs; // reference to registers
|
pcm_registers &m_regs; // reference to registers
|
||||||
pcm_engine &m_owner; // reference to our owner
|
pcm_engine &m_owner; // reference to our owner
|
||||||
|
mutable int32_t m_output[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -331,6 +334,8 @@ public:
|
||||||
// return a reference to our registers
|
// return a reference to our registers
|
||||||
pcm_registers ®s() { return m_regs; }
|
pcm_registers ®s() { return m_regs; }
|
||||||
|
|
||||||
|
// simple getters for debugging
|
||||||
|
pcm_channel *debug_channel(uint32_t index) const { return m_channel[index].get(); }
|
||||||
private:
|
private:
|
||||||
// internal state
|
// internal state
|
||||||
ymfm_interface &m_intf; // reference to the interface
|
ymfm_interface &m_intf; // reference to the interface
|
||||||
|
|
|
@ -1621,7 +1621,10 @@ void DivEngine::registerSystems() {
|
||||||
{_("4OP 1"), _("FM 2"), _("4OP 3"), _("FM 4"), _("4OP 5"), _("FM 6"), _("4OP 7"), _("FM 8"), _("4OP 9"), _("FM 10"), _("4OP 11"), _("FM 12"), _("FM 13"), _("FM 14"), _("FM 15"), _("FM 16"), _("FM 17"), _("FM 18"), _("PCM 1"), _("PCM 2"), _("PCM 3"), _("PCM 4"), _("PCM 5"), _("PCM 6"), _("PCM 7"), _("PCM 8"), _("PCM 9"), _("PCM 10"), _("PCM 11"), _("PCM 12"), _("PCM 13"), _("PCM 14"), _("PCM 15"), _("PCM 16"), _("PCM 17"), _("PCM 18"), _("PCM 19"), _("PCM 20"), _("PCM 21"), _("PCM 22"), _("PCM 23"), _("PCM 24")},
|
{_("4OP 1"), _("FM 2"), _("4OP 3"), _("FM 4"), _("4OP 5"), _("FM 6"), _("4OP 7"), _("FM 8"), _("4OP 9"), _("FM 10"), _("4OP 11"), _("FM 12"), _("FM 13"), _("FM 14"), _("FM 15"), _("FM 16"), _("FM 17"), _("FM 18"), _("PCM 1"), _("PCM 2"), _("PCM 3"), _("PCM 4"), _("PCM 5"), _("PCM 6"), _("PCM 7"), _("PCM 8"), _("PCM 9"), _("PCM 10"), _("PCM 11"), _("PCM 12"), _("PCM 13"), _("PCM 14"), _("PCM 15"), _("PCM 16"), _("PCM 17"), _("PCM 18"), _("PCM 19"), _("PCM 20"), _("PCM 21"), _("PCM 22"), _("PCM 23"), _("PCM 24")},
|
||||||
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P8", "P10", "P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20", "P21", "P22", "P23", "P24"},
|
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "F16", "F17", "F18", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P8", "P10", "P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20", "P21", "P22", "P23", "P24"},
|
||||||
{DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
{DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||||
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM}
|
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM},
|
||||||
|
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||||
|
fmEffectHandlerMap,
|
||||||
|
fmOPLPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO: same here
|
// TODO: same here
|
||||||
|
@ -1631,7 +1634,10 @@ void DivEngine::registerSystems() {
|
||||||
{_("4OP 1"), _("FM 2"), _("4OP 3"), _("FM 4"), _("4OP 5"), _("FM 6"), _("4OP 7"), _("FM 8"), _("4OP 9"), _("FM 10"), _("4OP 11"), _("FM 12"), _("FM 13"), _("FM 14"), _("FM 15"), _("Kick/FM 16"), _("Snare"), _("Tom"), _("Top"), _("HiHat"), _("PCM 1"), _("PCM 2"), _("PCM 3"), _("PCM 4"), _("PCM 5"), _("PCM 6"), _("PCM 7"), _("PCM 8"), _("PCM 9"), _("PCM 10"), _("PCM 11"), _("PCM 12"), _("PCM 13"), _("PCM 14"), _("PCM 15"), _("PCM 16"), _("PCM 17"), _("PCM 18"), _("PCM 19"), _("PCM 20"), _("PCM 21"), _("PCM 22"), _("PCM 23"), _("PCM 24")},
|
{_("4OP 1"), _("FM 2"), _("4OP 3"), _("FM 4"), _("4OP 5"), _("FM 6"), _("4OP 7"), _("FM 8"), _("4OP 9"), _("FM 10"), _("4OP 11"), _("FM 12"), _("FM 13"), _("FM 14"), _("FM 15"), _("Kick/FM 16"), _("Snare"), _("Tom"), _("Top"), _("HiHat"), _("PCM 1"), _("PCM 2"), _("PCM 3"), _("PCM 4"), _("PCM 5"), _("PCM 6"), _("PCM 7"), _("PCM 8"), _("PCM 9"), _("PCM 10"), _("PCM 11"), _("PCM 12"), _("PCM 13"), _("PCM 14"), _("PCM 15"), _("PCM 16"), _("PCM 17"), _("PCM 18"), _("PCM 19"), _("PCM 20"), _("PCM 21"), _("PCM 22"), _("PCM 23"), _("PCM 24")},
|
||||||
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "BD", "SD", "TM", "TP", "HH", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P8", "P10", "P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20", "P21", "P22", "P23", "P24"},
|
{"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14", "F15", "BD", "SD", "TM", "TP", "HH", "P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P8", "P10", "P11", "P12", "P13", "P14", "P15", "P16", "P17", "P18", "P19", "P20", "P21", "P22", "P23", "P24"},
|
||||||
{DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
{DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM},
|
||||||
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM}
|
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM, DIV_INS_MULTIPCM},
|
||||||
|
{DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA},
|
||||||
|
fmOPLDrumsEffectHandlerMap,
|
||||||
|
fmOPLPostEffectHandlerMap
|
||||||
);
|
);
|
||||||
|
|
||||||
EffectHandlerMap es5506PreEffectHandlerMap={
|
EffectHandlerMap es5506PreEffectHandlerMap={
|
||||||
|
|
|
@ -987,6 +987,13 @@ void DivEngine::performVGMWrite(SafeWriter* w, DivSystem sys, DivRegWrite& write
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DIV_SYSTEM_OPL4:
|
||||||
|
case DIV_SYSTEM_OPL4_DRUMS:
|
||||||
|
w->writeC(0xd0|baseAddr2);
|
||||||
|
w->writeC(write.addr>>8);
|
||||||
|
w->writeC(write.addr&0xff);
|
||||||
|
w->writeC(write.val);
|
||||||
|
break;
|
||||||
case DIV_SYSTEM_SCC:
|
case DIV_SYSTEM_SCC:
|
||||||
if (write.addr<0x80) {
|
if (write.addr<0x80) {
|
||||||
w->writeC(0xd2);
|
w->writeC(0xd2);
|
||||||
|
@ -1254,6 +1261,7 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
bool writeVOXSamples=false;
|
bool writeVOXSamples=false;
|
||||||
DivDispatch* writeADPCM_OPNA[2]={NULL,NULL};
|
DivDispatch* writeADPCM_OPNA[2]={NULL,NULL};
|
||||||
DivDispatch* writeADPCM_OPNB[2]={NULL,NULL};
|
DivDispatch* writeADPCM_OPNB[2]={NULL,NULL};
|
||||||
|
DivDispatch* writePCM_OPL4[2]={NULL,NULL};
|
||||||
DivDispatch* writeADPCM_Y8950[2]={NULL,NULL};
|
DivDispatch* writeADPCM_Y8950[2]={NULL,NULL};
|
||||||
DivDispatch* writeSegaPCM[2]={NULL,NULL};
|
DivDispatch* writeSegaPCM[2]={NULL,NULL};
|
||||||
DivDispatch* writeX1010[2]={NULL,NULL};
|
DivDispatch* writeX1010[2]={NULL,NULL};
|
||||||
|
@ -1706,6 +1714,20 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
howManyChips++;
|
howManyChips++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case DIV_SYSTEM_OPL4:
|
||||||
|
case DIV_SYSTEM_OPL4_DRUMS:
|
||||||
|
if (!hasOPL4) {
|
||||||
|
hasOPL4=disCont[i].dispatch->chipClock;
|
||||||
|
CHIP_VOL(12,1.0);
|
||||||
|
willExport[i]=true;
|
||||||
|
} else if (!(hasOPL4&0x40000000)) {
|
||||||
|
isSecond[i]=true;
|
||||||
|
CHIP_VOL_SECOND(12,1.0);
|
||||||
|
willExport[i]=true;
|
||||||
|
hasOPL4|=0x40000000;
|
||||||
|
howManyChips++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case DIV_SYSTEM_SCC:
|
case DIV_SYSTEM_SCC:
|
||||||
case DIV_SYSTEM_SCC_PLUS:
|
case DIV_SYSTEM_SCC_PLUS:
|
||||||
if (!hasK051649) {
|
if (!hasK051649) {
|
||||||
|
@ -2150,6 +2172,16 @@ SafeWriter* DivEngine::saveVGM(bool* sysToExport, bool loop, int version, bool p
|
||||||
w->writeI(0);
|
w->writeI(0);
|
||||||
w->write(writeADPCM_OPNB[i]->getSampleMem(1),writeADPCM_OPNB[i]->getSampleMemUsage(1));
|
w->write(writeADPCM_OPNB[i]->getSampleMem(1),writeADPCM_OPNB[i]->getSampleMemUsage(1));
|
||||||
}
|
}
|
||||||
|
// PCM (OPL4)
|
||||||
|
if (writePCM_OPL4[i]!=NULL && writePCM_OPL4[i]->getSampleMemUsage(0)>0) {
|
||||||
|
w->writeC(0x67);
|
||||||
|
w->writeC(0x66);
|
||||||
|
w->writeC(0x84);
|
||||||
|
w->writeI((writePCM_OPL4[i]->getSampleMemUsage(0)+8)|(i*0x80000000));
|
||||||
|
w->writeI(writePCM_OPL4[i]->getSampleMemCapacity(0));
|
||||||
|
w->writeI(0);
|
||||||
|
w->write(writePCM_OPL4[i]->getSampleMem(0),writePCM_OPL4[i]->getSampleMemUsage(0));
|
||||||
|
}
|
||||||
// ADPCM (Y8950)
|
// ADPCM (Y8950)
|
||||||
if (writeADPCM_Y8950[i]!=NULL && writeADPCM_Y8950[i]->getSampleMemUsage(0)>0) {
|
if (writeADPCM_Y8950[i]!=NULL && writeADPCM_Y8950[i]->getSampleMemUsage(0)>0) {
|
||||||
w->writeC(0x67);
|
w->writeC(0x67);
|
||||||
|
|
|
@ -1260,6 +1260,8 @@ const int availableSystems[]={
|
||||||
DIV_SYSTEM_5E01,
|
DIV_SYSTEM_5E01,
|
||||||
DIV_SYSTEM_BIFURCATOR,
|
DIV_SYSTEM_BIFURCATOR,
|
||||||
DIV_SYSTEM_SID2,
|
DIV_SYSTEM_SID2,
|
||||||
|
DIV_SYSTEM_OPL4,
|
||||||
|
DIV_SYSTEM_OPL4_DRUMS,
|
||||||
0 // don't remove this last one!
|
0 // don't remove this last one!
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1295,6 +1297,8 @@ const int chipsFM[]={
|
||||||
DIV_SYSTEM_OPL3_DRUMS,
|
DIV_SYSTEM_OPL3_DRUMS,
|
||||||
DIV_SYSTEM_OPZ,
|
DIV_SYSTEM_OPZ,
|
||||||
DIV_SYSTEM_ESFM,
|
DIV_SYSTEM_ESFM,
|
||||||
|
DIV_SYSTEM_OPL4,
|
||||||
|
DIV_SYSTEM_OPL4_DRUMS,
|
||||||
0 // don't remove this last one!
|
0 // don't remove this last one!
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1380,6 +1384,8 @@ const int chipsSample[]={
|
||||||
DIV_SYSTEM_NDS,
|
DIV_SYSTEM_NDS,
|
||||||
DIV_SYSTEM_GBA_DMA,
|
DIV_SYSTEM_GBA_DMA,
|
||||||
DIV_SYSTEM_GBA_MINMOD,
|
DIV_SYSTEM_GBA_MINMOD,
|
||||||
|
DIV_SYSTEM_OPL4,
|
||||||
|
DIV_SYSTEM_OPL4_DRUMS,
|
||||||
0 // don't remove this last one!
|
0 // don't remove this last one!
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -519,6 +519,18 @@ void FurnaceGUI::initSystemPresets() {
|
||||||
) // variable rate, Mono DAC
|
) // variable rate, Mono DAC
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
SUB_ENTRY(
|
||||||
|
"MSX + Moonsound", {
|
||||||
|
CH(DIV_SYSTEM_AY8910, 1.0f, 0, "chipType=1"),
|
||||||
|
CH(DIV_SYSTEM_OPL4, 1.0f, 0, "")
|
||||||
|
}
|
||||||
|
);
|
||||||
|
SUB_ENTRY(
|
||||||
|
"MSX + Moonsound (drums mode)", {
|
||||||
|
CH(DIV_SYSTEM_AY8910, 1.0f, 0, "chipType=1"),
|
||||||
|
CH(DIV_SYSTEM_OPL4_DRUMS, 1.0f, 0, "")
|
||||||
|
}
|
||||||
|
);
|
||||||
ENTRY(
|
ENTRY(
|
||||||
"NEC PC-88", {}
|
"NEC PC-88", {}
|
||||||
);
|
);
|
||||||
|
@ -2659,6 +2671,16 @@ void FurnaceGUI::initSystemPresets() {
|
||||||
CH(DIV_SYSTEM_ESFM, 1.0f, 0, "")
|
CH(DIV_SYSTEM_ESFM, 1.0f, 0, "")
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
ENTRY(
|
||||||
|
"Yamaha YMF278B (OPL4)", {
|
||||||
|
CH(DIV_SYSTEM_OPL4, 1.0f, 0, "")
|
||||||
|
}
|
||||||
|
);
|
||||||
|
SUB_ENTRY(
|
||||||
|
"Yamaha YMF278B (drums mode)", {
|
||||||
|
CH(DIV_SYSTEM_OPL4_DRUMS, 1.0f, 0, "")
|
||||||
|
}
|
||||||
|
);
|
||||||
if (settings.hiddenSystems) {
|
if (settings.hiddenSystems) {
|
||||||
ENTRY(
|
ENTRY(
|
||||||
"Yamaha YMU759 (MA-2)", {
|
"Yamaha YMU759 (MA-2)", {
|
||||||
|
@ -2870,6 +2892,16 @@ void FurnaceGUI::initSystemPresets() {
|
||||||
CH(DIV_SYSTEM_NDS, 1.0f, 0, "")
|
CH(DIV_SYSTEM_NDS, 1.0f, 0, "")
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
ENTRY(
|
||||||
|
"Yamaha YMF278B (OPL4)", {
|
||||||
|
CH(DIV_SYSTEM_OPL4, 1.0f, 0, "")
|
||||||
|
}
|
||||||
|
);
|
||||||
|
SUB_ENTRY(
|
||||||
|
"Yamaha YMF278B (drums mode)", {
|
||||||
|
CH(DIV_SYSTEM_OPL4_DRUMS, 1.0f, 0, "")
|
||||||
|
}
|
||||||
|
);
|
||||||
CATEGORY_END;
|
CATEGORY_END;
|
||||||
|
|
||||||
CATEGORY_BEGIN("Wavetable","chips which use user-specified waveforms to generate sound.");
|
CATEGORY_BEGIN("Wavetable","chips which use user-specified waveforms to generate sound.");
|
||||||
|
|
|
@ -2503,6 +2503,59 @@ bool FurnaceGUI::drawSysConf(int chan, int sysPos, DivSystem type, DivConfig& fl
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case DIV_SYSTEM_OPL4:
|
||||||
|
case DIV_SYSTEM_OPL4_DRUMS: {
|
||||||
|
int clockSel=flags.getInt("clockSel",0);
|
||||||
|
int ramSize=flags.getInt("ramSize",0);
|
||||||
|
|
||||||
|
ImGui::Text(_("Clock rate:"));
|
||||||
|
ImGui::Indent();
|
||||||
|
if (ImGui::RadioButton(_("33.8688MHz"),clockSel==0)) {
|
||||||
|
clockSel=0;
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
if (ImGui::RadioButton(_("28.64MHz (NTSC)"),clockSel==1)) {
|
||||||
|
clockSel=1;
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
if (ImGui::RadioButton(_("28.38MHz (PAL)"),clockSel==2)) {
|
||||||
|
clockSel=2;
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
ImGui::Unindent();
|
||||||
|
|
||||||
|
ImGui::Text(_("RAM size:"));
|
||||||
|
ImGui::Indent();
|
||||||
|
if (ImGui::RadioButton(_("4MB"),ramSize==0)) {
|
||||||
|
ramSize=0;
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
if (ImGui::RadioButton(_("2MB"),ramSize==1)) {
|
||||||
|
ramSize=1;
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
if (ImGui::RadioButton(_("1MB"),ramSize==2)) {
|
||||||
|
ramSize=2;
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
if (ImGui::RadioButton(_("512KB"),ramSize==3)) {
|
||||||
|
ramSize=3;
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
if (ImGui::RadioButton(_("128KB"),ramSize==4)) {
|
||||||
|
ramSize=4;
|
||||||
|
altered=true;
|
||||||
|
}
|
||||||
|
ImGui::Unindent();
|
||||||
|
|
||||||
|
if (altered) {
|
||||||
|
e->lockSave([&]() {
|
||||||
|
flags.set("clockSel",clockSel);
|
||||||
|
flags.set("ramSize",ramSize);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case DIV_SYSTEM_SWAN:
|
case DIV_SYSTEM_SWAN:
|
||||||
case DIV_SYSTEM_BUBSYS_WSG:
|
case DIV_SYSTEM_BUBSYS_WSG:
|
||||||
case DIV_SYSTEM_PET:
|
case DIV_SYSTEM_PET:
|
||||||
|
|
Loading…
Reference in a new issue