OPL: some work - still does not work

This commit is contained in:
tildearrow 2022-03-07 17:07:29 -05:00
parent 27758434af
commit 03d2f87804
3 changed files with 114 additions and 72 deletions

View file

@ -211,8 +211,29 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
((DivPlatformOPLL*)dispatch)->setVRC7(sys==DIV_SYSTEM_VRC7); ((DivPlatformOPLL*)dispatch)->setVRC7(sys==DIV_SYSTEM_VRC7);
((DivPlatformOPLL*)dispatch)->setProperDrums(sys==DIV_SYSTEM_OPLL_DRUMS); ((DivPlatformOPLL*)dispatch)->setProperDrums(sys==DIV_SYSTEM_OPLL_DRUMS);
break; break;
case DIV_SYSTEM_OPL:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(1,false);
break;
case DIV_SYSTEM_OPL_DRUMS:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(1,true);
break;
case DIV_SYSTEM_OPL2:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(2,false);
break;
case DIV_SYSTEM_OPL2_DRUMS:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(2,true);
break;
case DIV_SYSTEM_OPL3: case DIV_SYSTEM_OPL3:
dispatch=new DivPlatformOPL; dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(3,false);
break;
case DIV_SYSTEM_OPL3_DRUMS:
dispatch=new DivPlatformOPL;
((DivPlatformOPL*)dispatch)->setOPLType(3,true);
break; break;
case DIV_SYSTEM_SAA1099: { case DIV_SYSTEM_SAA1099: {
int saaCore=eng->getConfInt("saaCore",0); int saaCore=eng->getConfInt("saaCore",0);

View file

@ -44,7 +44,7 @@ const unsigned char slotsOPL2Drums[4][20]={
{N, N, N, N, N, N, N, N, N, N, N} {N, N, N, N, N, N, N, N, N, N, N}
}; };
const unsigned char chanMapOPL2[20]={ const unsigned short chanMapOPL2[20]={
0, 1, 2, 3, 4, 5, 6, 7, 8, N, N, N, N, N, N, N, N, N, N, N 0, 1, 2, 3, 4, 5, 6, 7, 8, N, N, N, N, N, N, N, N, N, N, N
}; };
@ -62,12 +62,51 @@ const unsigned char slotsOPL3Drums[4][20]={
{9, N, 10, N, 11, N, 27, N, 28, N, 29, N, N, N, N, N, N, N, N, N} // OP4 {9, N, 10, N, 11, N, 27, N, 28, N, 29, N, N, N, N, N, N, N, N, N} // OP4
}; };
const unsigned char chanMapOPL3[20]={ const unsigned short chanMapOPL3[20]={
0, 3, 1, 4, 2, 5, 9, 12, 10, 13, 11, 14, 15, 16, 17, 6, 7, 8, N, N 0, 3, 1, 4, 2, 5, 0x100, 0x103, 0x101, 0x104, 0x102, 0x105, 0x106, 0x107, 0x108, 6, 7, 8, N, N
};
const unsigned int slotMap[36]={
0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
0x100, 0x101, 0x102, 0x103, 0x104, 0x105,
0x108, 0x109, 0x10a, 0x10b, 0x10c, 0x10d,
0x110, 0x111, 0x112, 0x113, 0x114, 0x115,
};
const bool isOutputL[2][4][4]={
{ // 2-op
{false, true, false, false}, // 1 > 2
{ true, true, false, false}, // 1 + 2
{false, true, false, false}, // ditto, 0
{ true, true, false, false}, // ditto, 1
},
{ // 4-op
{false, false, false, true}, // 1 > 2 > 3 > 4
{ true, false, false, true}, // 1 + (2 > 3 > 4)
{false, true, false, true}, // (1 > 2) + (3 > 4)
{ true, false, true, true} // 1 + (2 > 3) + 4
}
}; };
#undef N #undef N
const int orderedOpsL[4]={
0,2,1,3
};
#define ADDR_AM_VIB_SUS_KSR_MULT 0x20
#define ADDR_KSL_TL 0x40
#define ADDR_AR_DR 0x60
#define ADDR_SL_RR 0x80
#define ADDR_WS 0xe0
#define ADDR_FREQ 0xa0
#define ADDR_FREQH 0xb0
#define ADDR_LR_FB_ALG 0xc0
const char* DivPlatformOPL::getEffectName(unsigned char effect) { const char* DivPlatformOPL::getEffectName(unsigned char effect) {
switch (effect) { switch (effect) {
case 0x10: case 0x10:
@ -409,38 +448,43 @@ int DivPlatformOPL::dispatch(DivCommand c) {
if (!chan[c.chan].std.willVol) { if (!chan[c.chan].std.willVol) {
chan[c.chan].outVol=chan[c.chan].vol; chan[c.chan].outVol=chan[c.chan].vol;
} }
if (chan[c.chan].insChanged) {
int ops=(slots[3][c.chan]!=255 && ins->fm.ops==4)?4:2;
for (int i=0; i<ops; i++) {
unsigned short baseAddr=slotMap[slots[c.chan][i]];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
/* if (isMuted[c.chan]) {
for (int i=0; i<4; i++) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
if (isMuted[c.chan]) {
rWrite(baseAddr+ADDR_TL,127);
} else {
if (isOutput[chan[c.chan].state.alg][i]) {
if (!chan[c.chan].active || chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
}
} else { } else {
if (chan[c.chan].insChanged) { if (isOutputL[ops==4][chan[c.chan].state.alg][i]) {
rWrite(baseAddr+ADDR_TL,op.tl); rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
} else {
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
} }
} }
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
if (oplType>1) {
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
}
} }
if (chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4)); if (isMuted[c.chan]) {
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6)); rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1));
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7)); if (ops==4) {
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31); rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1));
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4)); }
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15); } else {
rWrite(chanMap[c.chan]+ADDR_LR_FB_ALG,(chan[c.chan].state.alg&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
if (ops==4) {
rWrite(chanMap[c.chan+1]+ADDR_LR_FB_ALG,((chan[c.chan].state.alg>>1)&1)|(chan[c.chan].state.fb<<1)|((chan[c.chan].pan&3)<<4));
}
} }
} }
if (chan[c.chan].insChanged) {
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3));
rWrite(chanOffs[c.chan]+ADDR_LRAF,(isMuted[c.chan]?0:(chan[c.chan].pan<<6))|(chan[c.chan].state.fms&7)|((chan[c.chan].state.ams&3)<<4));
}
*/
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
@ -453,19 +497,11 @@ int DivPlatformOPL::dispatch(DivCommand c) {
break; break;
} }
case DIV_CMD_NOTE_OFF: case DIV_CMD_NOTE_OFF:
if (c.chan==5) {
dacSample=-1;
if (dumpWrites) addWrite(0xffff0002,0);
}
chan[c.chan].keyOff=true; chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false; chan[c.chan].keyOn=false;
chan[c.chan].active=false; chan[c.chan].active=false;
break; break;
case DIV_CMD_NOTE_OFF_ENV: case DIV_CMD_NOTE_OFF_ENV:
if (c.chan==5) {
dacSample=-1;
if (dumpWrites) addWrite(0xffff0002,0);
}
chan[c.chan].keyOff=true; chan[c.chan].keyOff=true;
chan[c.chan].keyOn=false; chan[c.chan].keyOn=false;
chan[c.chan].active=false; chan[c.chan].active=false;
@ -558,17 +594,6 @@ int DivPlatformOPL::dispatch(DivCommand c) {
} }
break; break;
} }
case DIV_CMD_SAMPLE_MODE: {
dacMode=c.value;
rWrite(0x2b,c.value<<7);
break;
}
case DIV_CMD_SAMPLE_BANK:
sampleBank=c.value;
if (sampleBank>(parent->song.sample.size()/12)) {
sampleBank=parent->song.sample.size()/12;
}
break;
case DIV_CMD_LEGATO: { case DIV_CMD_LEGATO: {
chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value); chan[c.chan].baseFreq=NOTE_FREQUENCY(c.value);
chan[c.chan].note=c.value; chan[c.chan].note=c.value;
@ -724,18 +749,12 @@ void DivPlatformOPL::reset() {
} }
lastBusy=60; lastBusy=60;
dacMode=0;
dacPeriod=0;
dacPos=0;
dacRate=0;
dacSample=-1;
sampleBank=0;
lfoValue=8; lfoValue=8;
properDrums=properDrumsSys;
extMode=false; if (oplType==3) { // enable OPL3 features
immWrite(0x105,1);
// LFO }
immWrite(0x22,lfoValue);
delay=0; delay=0;
} }
@ -779,20 +798,23 @@ void DivPlatformOPL::setYMFM(bool use) {
useYMFM=use; useYMFM=use;
} }
void DivPlatformOPL::setOPLType(int type) { void DivPlatformOPL::setOPLType(int type, bool drums) {
switch (type) { switch (type) {
case 1: case 2: case 1: case 2:
slotsNonDrums=(const unsigned char**)slotsOPL2; slotsNonDrums=(const unsigned char**)slotsOPL2;
slotsDrums=(const unsigned char**)slotsOPL2Drums; slotsDrums=(const unsigned char**)slotsOPL2Drums;
slots=drums?slotsDrums:slotsNonDrums;
chanMap=chanMapOPL2; chanMap=chanMapOPL2;
break; break;
case 3: case 3:
slotsNonDrums=(const unsigned char**)slotsOPL3; slotsNonDrums=(const unsigned char**)slotsOPL3;
slotsDrums=(const unsigned char**)slotsOPL3Drums; slotsDrums=(const unsigned char**)slotsOPL3Drums;
slots=drums?slotsDrums:slotsNonDrums;
chanMap=chanMapOPL3; chanMap=chanMapOPL3;
break; break;
} }
oplType=type; oplType=type;
properDrumsSys=drums;
} }
void DivPlatformOPL::setFlags(unsigned int flags) { void DivPlatformOPL::setFlags(unsigned int flags) {
@ -820,14 +842,18 @@ void DivPlatformOPL::setFlags(unsigned int flags) {
rate=chipClock/36; rate=chipClock/36;
}*/ }*/
chipClock=COLOR_NTSC*4.0; if (oplType==3) {
rate=chipClock/32; chipClock=COLOR_NTSC*4.0;
rate=chipClock/36;
} else {
chipClock=COLOR_NTSC;
rate=chipClock/9;
}
} }
int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { int DivPlatformOPL::init(DivEngine* p, int channels, int sugRate, unsigned int flags) {
parent=p; parent=p;
dumpWrites=false; dumpWrites=false;
ladder=false;
skipRegisterWrites=false; skipRegisterWrites=false;
for (int i=0; i<20; i++) { for (int i=0; i<20; i++) {
isMuted[i]=false; isMuted[i]=false;

View file

@ -67,22 +67,17 @@ class DivPlatformOPL: public DivDispatch {
const unsigned char** slotsNonDrums; const unsigned char** slotsNonDrums;
const unsigned char** slotsDrums; const unsigned char** slotsDrums;
const unsigned char** slots; const unsigned char** slots;
const unsigned char* chanMap; const unsigned short* chanMap;
int delay, oplType; int delay, oplType;
unsigned char lastBusy; unsigned char lastBusy;
unsigned char regPool[512]; unsigned char regPool[512];
bool dacMode; bool properDrums, properDrumsSys;
int dacPeriod;
int dacRate;
unsigned int dacPos;
int dacSample;
unsigned char sampleBank;
unsigned char lfoValue; unsigned char lfoValue;
bool extMode, useYMFM; bool useYMFM;
bool ladder;
short oldWrites[512]; short oldWrites[512];
short pendingWrites[512]; short pendingWrites[512];
@ -107,7 +102,7 @@ class DivPlatformOPL: public DivDispatch {
void muteChannel(int ch, bool mute); void muteChannel(int ch, bool mute);
bool isStereo(); bool isStereo();
void setYMFM(bool use); void setYMFM(bool use);
void setOPLType(int type); void setOPLType(int type, bool drums);
bool keyOffAffectsArp(int ch); bool keyOffAffectsArp(int ch);
bool keyOffAffectsPorta(int ch); bool keyOffAffectsPorta(int ch);
void toggleRegisterDump(bool enable); void toggleRegisterDump(bool enable);