OPLL: 80%

accuracy fixes pending though
then macros and then drum mode
This commit is contained in:
tildearrow 2022-02-26 03:27:37 -05:00
parent c52258f943
commit 271b3fb0fe
5 changed files with 255 additions and 156 deletions

View file

@ -196,6 +196,7 @@ void DivDispatchContainer::init(DivSystem sys, DivEngine* eng, int chanCount, do
break; break;
case DIV_SYSTEM_OPLL: case DIV_SYSTEM_OPLL:
case DIV_SYSTEM_OPLL_DRUMS: case DIV_SYSTEM_OPLL_DRUMS:
case DIV_SYSTEM_VRC7:
dispatch=new DivPlatformOPLL; dispatch=new DivPlatformOPLL;
break; break;
case DIV_SYSTEM_SAA1099: { case DIV_SYSTEM_SAA1099: {

View file

@ -299,10 +299,16 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) {
for (int j=0; j<ins->fm.ops; j++) { for (int j=0; j<ins->fm.ops; j++) {
ins->fm.op[j].am=reader.readC(); ins->fm.op[j].am=reader.readC();
ins->fm.op[j].ar=reader.readC(); ins->fm.op[j].ar=reader.readC();
if (ds.system[0]==DIV_SYSTEM_SMS_OPLL || ds.system[0]==DIV_SYSTEM_NES_VRC7) {
ins->fm.op[j].ar&=15;
}
if (ds.version<0x13) { if (ds.version<0x13) {
ins->fm.op[j].dam=reader.readC(); ins->fm.op[j].dam=reader.readC();
} }
ins->fm.op[j].dr=reader.readC(); ins->fm.op[j].dr=reader.readC();
if (ds.system[0]==DIV_SYSTEM_SMS_OPLL || ds.system[0]==DIV_SYSTEM_NES_VRC7) {
ins->fm.op[j].dr&=15;
}
if (ds.version<0x13) { if (ds.version<0x13) {
ins->fm.op[j].dvb=reader.readC(); ins->fm.op[j].dvb=reader.readC();
ins->fm.op[j].egt=reader.readC(); ins->fm.op[j].egt=reader.readC();

View file

@ -54,7 +54,7 @@ struct DivInstrumentFM {
unsigned char alg, fb, fms, ams, ops, opllPreset; unsigned char alg, fb, fms, ams, ops, opllPreset;
struct Operator { struct Operator {
unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv;
unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759 unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL
Operator(): Operator():
am(0), am(0),
ar(0), ar(0),

View file

@ -85,13 +85,12 @@ void DivPlatformOPLL::acquire_nuked(short* bufL, short* bufR, size_t start, size
QueuedWrite& w=writes.front(); QueuedWrite& w=writes.front();
if (w.addrOrVal) { if (w.addrOrVal) {
OPLL_Write(&fm,1,w.val); OPLL_Write(&fm,1,w.val);
printf("write: %x = %.2x\n",w.addr,w.val); //printf("write: %x = %.2x\n",w.addr,w.val);
regPool[w.addr&0xff]=w.val; regPool[w.addr&0xff]=w.val;
writes.pop(); writes.pop();
delay=21; delay=21;
} else { } else {
//printf("busycounter: %d\n",lastBusy); //printf("busycounter: %d\n",lastBusy);
//w.addr=rand()&0x3f;
OPLL_Write(&fm,0,w.addr); OPLL_Write(&fm,0,w.addr);
w.addrOrVal=true; w.addrOrVal=true;
delay=3; delay=3;
@ -240,8 +239,7 @@ void DivPlatformOPLL::tick() {
}*/ }*/
if (chan[i].keyOn || chan[i].keyOff) { if (chan[i].keyOn || chan[i].keyOff) {
// TODO: FIX immWrite(0x20+i,(chan[i].freqH)|(chan[i].state.alg?0x20:0));
immWrite(0x20+i,0x00);
//chan[i].keyOn=false; //chan[i].keyOn=false;
chan[i].keyOff=false; chan[i].keyOff=false;
} }
@ -262,31 +260,32 @@ void DivPlatformOPLL::tick() {
chan[i].freqH=freqt>>8; chan[i].freqH=freqt>>8;
chan[i].freqL=freqt&0xff; chan[i].freqL=freqt&0xff;
immWrite(0x10+i,freqt&0xff); immWrite(0x10+i,freqt&0xff);
chan[i].freqChanged=false;
} }
if (chan[i].keyOn) { if (chan[i].keyOn || chan[i].freqChanged) {
//immWrite(0x28,0xf0|konOffs[i]); //immWrite(0x28,0xf0|konOffs[i]);
immWrite(0x20+i,(chan[i].freqH)|(chan[i].active<<4)|0x20); immWrite(0x20+i,(chan[i].freqH)|(chan[i].active<<4)|(chan[i].state.alg?0x20:0));
chan[i].keyOn=false; chan[i].keyOn=false;
} }
chan[i].freqChanged=false;
} }
} }
#define OPLL_C_NUM 343
int DivPlatformOPLL::octave(int freq) { int DivPlatformOPLL::octave(int freq) {
if (freq>=32768) { if (freq>=OPLL_C_NUM*64) {
return 128; return 128;
} else if (freq>=16384) { } else if (freq>=OPLL_C_NUM*32) {
return 64; return 64;
} else if (freq>=8192) { } else if (freq>=OPLL_C_NUM*16) {
return 32; return 32;
} else if (freq>=4096) { } else if (freq>=OPLL_C_NUM*8) {
return 16; return 16;
} else if (freq>=2048) { } else if (freq>=OPLL_C_NUM*4) {
return 8; return 8;
} else if (freq>=1024) { } else if (freq>=OPLL_C_NUM*2) {
return 4; return 4;
} else if (freq>=512) { } else if (freq>=OPLL_C_NUM) {
return 2; return 2;
} else { } else {
return 1; return 1;
@ -295,19 +294,19 @@ int DivPlatformOPLL::octave(int freq) {
} }
int DivPlatformOPLL::toFreq(int freq) { int DivPlatformOPLL::toFreq(int freq) {
if (freq>=32768) { if (freq>=OPLL_C_NUM*64) {
return 0xe00|((freq>>7)&0x1ff); return 0xe00|((freq>>7)&0x1ff);
} else if (freq>=16384) { } else if (freq>=OPLL_C_NUM*32) {
return 0xc00|((freq>>6)&0x1ff); return 0xc00|((freq>>6)&0x1ff);
} else if (freq>=8192) { } else if (freq>=OPLL_C_NUM*16) {
return 0xa00|((freq>>5)&0x1ff); return 0xa00|((freq>>5)&0x1ff);
} else if (freq>=4096) { } else if (freq>=OPLL_C_NUM*8) {
return 0x800|((freq>>4)&0x1ff); return 0x800|((freq>>4)&0x1ff);
} else if (freq>=2048) { } else if (freq>=OPLL_C_NUM*4) {
return 0x600|((freq>>3)&0x1ff); return 0x600|((freq>>3)&0x1ff);
} else if (freq>=1024) { } else if (freq>=OPLL_C_NUM*2) {
return 0x400|((freq>>2)&0x1ff); return 0x400|((freq>>2)&0x1ff);
} else if (freq>=512) { } else if (freq>=OPLL_C_NUM) {
return 0x200|((freq>>1)&0x1ff); return 0x200|((freq>>1)&0x1ff);
} else { } else {
return freq&0x1ff; return freq&0x1ff;
@ -346,39 +345,23 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
chan[c.chan].outVol=chan[c.chan].vol; chan[c.chan].outVol=chan[c.chan].vol;
} }
/*
for (int i=0; i<2; i++) {
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 {
if (chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_TL,op.tl);
}
}
}
if (chan[c.chan].insChanged) {
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
}
}
if (chan[c.chan].insChanged) { if (chan[c.chan].insChanged) {
rWrite(chanOffs[c.chan]+ADDR_FB_ALG,(chan[c.chan].state.alg&7)|(chan[c.chan].state.fb<<3)); // update custom preset
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)); if (chan[c.chan].state.opllPreset==0) {
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
rWrite(0x00,(mod.am<<7)|(mod.vib<<6)|((mod.ssgEnv&8)<<2)|(mod.ksr<<4)|(mod.mult));
rWrite(0x01,(car.am<<7)|(car.vib<<6)|((car.ssgEnv&8)<<2)|(car.ksr<<4)|(car.mult));
rWrite(0x02,(car.ksl<<6)|(mod.tl&63));
rWrite(0x03,(mod.ksl<<6)|((chan[c.chan].state.fms&1)<<4)|((chan[c.chan].state.ams&1)<<3)|chan[c.chan].state.fb);
rWrite(0x04,(mod.ar<<4)|(mod.dr));
rWrite(0x05,(car.ar<<4)|(car.dr));
rWrite(0x06,(mod.sl<<4)|(mod.rr));
rWrite(0x07,(car.sl<<4)|(car.rr));
}
rWrite(0x30+c.chan,(15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)|(chan[c.chan].state.opllPreset<<4));
} }
*/
// for now
rWrite(0x30+c.chan,0x0|(ins->fm.opllPreset<<4));
chan[c.chan].insChanged=false; chan[c.chan].insChanged=false;
if (c.value!=DIV_NOTE_NULL) { if (c.value!=DIV_NOTE_NULL) {
@ -409,20 +392,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
if (!chan[c.chan].std.hasVol) { if (!chan[c.chan].std.hasVol) {
chan[c.chan].outVol=c.value; chan[c.chan].outVol=c.value;
} }
/* rWrite(0x30+c.chan,(15-(chan[c.chan].outVol*(15-chan[c.chan].state.op[1].tl))/15)|(chan[c.chan].state.opllPreset<<4));
for (int i=0; i<4; i++) {
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]) {
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[c.chan].outVol&0x7f))/127));
} else {
rWrite(baseAddr+ADDR_TL,op.tl);
}
}
}*/
break; break;
} }
case DIV_CMD_GET_VOLUME: { case DIV_CMD_GET_VOLUME: {
@ -457,12 +427,12 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
return2=true; return2=true;
} }
} }
if (!chan[c.chan].portaPause) { /*if (!chan[c.chan].portaPause) {
if (octave(chan[c.chan].baseFreq)!=octave(newFreq)) { if (octave(chan[c.chan].baseFreq)!=octave(newFreq)) {
chan[c.chan].portaPause=true; chan[c.chan].portaPause=true;
break; break;
} }
} }*/
chan[c.chan].baseFreq=newFreq; chan[c.chan].baseFreq=newFreq;
chan[c.chan].portaPause=false; chan[c.chan].portaPause=false;
chan[c.chan].freqChanged=true; chan[c.chan].freqChanged=true;
@ -528,7 +498,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
return 0; return 0;
break; break;
case DIV_CMD_GET_VOLMAX: case DIV_CMD_GET_VOLMAX:
return 127; return 15;
break; break;
case DIV_CMD_PRE_PORTA: case DIV_CMD_PRE_PORTA:
chan[c.chan].inPorta=c.value; chan[c.chan].inPorta=c.value;
@ -543,38 +513,26 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
} }
void DivPlatformOPLL::forceIns() { void DivPlatformOPLL::forceIns() {
/* for (int i=0; i<9; i++) {
for (int i=0; i<6; i++) { // update custom preset
for (int j=0; j<4; j++) { if (chan[i].state.opllPreset==0) {
unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& mod=chan[i].state.op[0];
DivInstrumentFM::Operator& op=chan[i].state.op[j]; DivInstrumentFM::Operator& car=chan[i].state.op[1];
if (isMuted[i]) { rWrite(0x00,(mod.am<<7)|(mod.vib<<6)|((mod.ssgEnv&8)<<2)|(mod.ksr<<4)|(mod.mult));
rWrite(baseAddr+ADDR_TL,127); rWrite(0x01,(car.am<<7)|(car.vib<<6)|((car.ssgEnv&8)<<2)|(car.ksr<<4)|(car.mult));
} else { rWrite(0x02,(car.ksl<<6)|(mod.tl&63));
if (isOutput[chan[i].state.alg][j]) { rWrite(0x03,(mod.ksl<<6)|((chan[i].state.fms&1)<<4)|((chan[i].state.ams&1)<<3)|chan[i].state.fb);
rWrite(baseAddr+ADDR_TL,127-(((127-op.tl)*(chan[i].outVol&0x7f))/127)); rWrite(0x04,(mod.ar<<4)|(mod.dr));
} else { rWrite(0x05,(car.ar<<4)|(car.dr));
rWrite(baseAddr+ADDR_TL,op.tl); rWrite(0x06,(mod.sl<<4)|(mod.rr));
} rWrite(0x07,(car.sl<<4)|(car.rr));
}
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
} }
rWrite(chanOffs[i]+ADDR_FB_ALG,(chan[i].state.alg&7)|(chan[i].state.fb<<3)); rWrite(0x30+i,(15-(chan[i].outVol*(15-chan[i].state.op[1].tl))/15)|(chan[i].state.opllPreset<<4));
rWrite(chanOffs[i]+ADDR_LRAF,(isMuted[i]?0:(chan[i].pan<<6))|(chan[i].state.fms&7)|((chan[i].state.ams&3)<<4));
if (chan[i].active) { if (chan[i].active) {
chan[i].keyOn=true; chan[i].keyOn=true;
chan[i].freqChanged=true; chan[i].freqChanged=true;
} }
} }
if (dacMode) {
rWrite(0x2b,0x80);
}
immWrite(0x22,lfoValue);*/
} }
void DivPlatformOPLL::toggleRegisterDump(bool enable) { void DivPlatformOPLL::toggleRegisterDump(bool enable) {
@ -590,7 +548,7 @@ unsigned char* DivPlatformOPLL::getRegisterPool() {
} }
int DivPlatformOPLL::getRegisterPoolSize() { int DivPlatformOPLL::getRegisterPoolSize() {
return 256; return 64;
} }
void DivPlatformOPLL::reset() { void DivPlatformOPLL::reset() {

View file

@ -58,13 +58,13 @@ const char* ssgEnvTypes[8]={
"Down Down Down", "Down.", "Down Up Down Up", "Down UP", "Up Up Up", "Up.", "Up Down Up Down", "Up DOWN" "Down Down Down", "Down.", "Down Up Down Up", "Down UP", "Up Up Up", "Up.", "Up Down Up Down", "Up DOWN"
}; };
const char* fmParamNames[3][16]={ const char* fmParamNames[3][27]={
{"Algorithm", "Feedback", "LFO > Freq", "LFO > Amp", "Attack", "Decay", "Decay 2", "Release", "Sustain", "Level", "EnvScale", "Multiplier", "Detune", "Detune 2", "SSG-EG", "AM"}, {"Algorithm", "Feedback", "LFO > Freq", "LFO > Amp", "Attack", "Decay", "Decay 2", "Release", "Sustain", "Level", "EnvScale", "Multiplier", "Detune", "Detune 2", "SSG-EG", "AM", "AM Depth", "Vibrato Depth", "EnvAlternate", "EnvAlternate", "LevelScale/key", "Sustain", "Vibrato", "Waveform", "EnvScale/key", "OP2 HalfSine", "OP1 HalfSine"},
{"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "SR", "RR", "SL", "TL", "KS", "MULT", "DT", "DT2", "SSG-EG", "AM"}, {"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "SR", "RR", "SL", "TL", "KS", "MULT", "DT", "DT2", "SSG-EG", "AM", "AMD", "FMD", "EGT", "EGT", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM"},
{"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "D2R", "RR", "SL", "TL", "RS", "MULT", "DT", "DT2", "SSG-EG", "AM"} {"ALG", "FB", "FMS/PMS", "AMS", "AR", "DR", "D2R", "RR", "SL", "TL", "RS", "MULT", "DT", "DT2", "SSG-EG", "AM", "DAM", "DVB", "EGT", "EGS", "KSL", "SUS", "VIB", "WS", "KSR", "DC", "DM"}
}; };
const char* opllInsNames[18]={ const char* opllInsNames[17]={
"User", "User",
"Violin", "Violin",
"Guitar", "Guitar",
@ -100,7 +100,18 @@ enum FMParams {
FM_DT=12, FM_DT=12,
FM_DT2=13, FM_DT2=13,
FM_SSG=14, FM_SSG=14,
FM_AM=15 FM_AM=15,
FM_DAM=16,
FM_DVB=17,
FM_EGT=18,
FM_EGS=19,
FM_KSL=20,
FM_SUS=21,
FM_VIB=22,
FM_WS=23,
FM_KSR=24,
FM_DC=25,
FM_DM=26
}; };
#define FM_NAME(x) fmParamNames[settings.fmNames][x] #define FM_NAME(x) fmParamNames[settings.fmNames][x]
@ -429,6 +440,41 @@ void FurnaceGUI::drawAlgorithm(unsigned char alg, FurnaceGUIFMAlgs algType, cons
} }
} }
break; break;
case FM_ALGS_2OP_OPL:
switch (alg) {
case 0: { // 1 > 2
ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.33,0.5));
ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.67,0.5));
dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,color);
dl->AddCircle(pos1,6.0f*dpiScale+1.0f,color);
dl->AddLine(pos1,pos2,colorL);
dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,color);
pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
pos2.x+=circleRadius+3.0*dpiScale;
pos1.y-=ImGui::CalcTextSize("1").y*0.5;
pos2.y-=ImGui::CalcTextSize("2").y*0.5;
dl->AddText(pos1,color,"1");
dl->AddText(pos2,color,"2");
break;
}
case 1: { // 1 + 2
ImVec2 pos1=ImLerp(rect.Min,rect.Max,ImVec2(0.33,0.5));
ImVec2 pos2=ImLerp(rect.Min,rect.Max,ImVec2(0.67,0.5));
dl->AddCircleFilled(pos1,4.0f*dpiScale+1.0f,color);
dl->AddCircle(pos1,6.0f*dpiScale+1.0f,color);
dl->AddCircleFilled(pos2,4.0f*dpiScale+1.0f,color);
pos1.x-=ImGui::CalcTextSize("2").x+circleRadius+3.0*dpiScale;
pos2.x+=circleRadius+3.0*dpiScale;
pos1.y-=ImGui::CalcTextSize("1").y*0.5;
pos2.y-=ImGui::CalcTextSize("2").y*0.5;
dl->AddText(pos1,color,"1");
dl->AddText(pos2,color,"2");
break;
}
}
break;
default: default:
break; break;
} }
@ -735,7 +781,7 @@ void FurnaceGUI::drawInsEdit() {
} }
if (ImGui::BeginTabBar("insEditTab")) { if (ImGui::BeginTabBar("insEditTab")) {
if (ins->type==DIV_INS_FM) { if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPZ) {
char label[32]; char label[32];
float asFloat[256]; float asFloat[256];
int asInt[256]; int asInt[256];
@ -746,19 +792,72 @@ void FurnaceGUI::drawInsEdit() {
ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0);
ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0);
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); switch (ins->type) {
P(ImGui::SliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN)); case DIV_INS_FM:
P(ImGui::SliderScalar(FM_NAME(FM_FMS),ImGuiDataType_U8,&ins->fm.fms,&_ZERO,&_SEVEN)); case DIV_INS_OPZ:
ImGui::TableNextColumn(); ImGui::TableNextColumn();
P(ImGui::SliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&_SEVEN)); P(ImGui::SliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN));
P(ImGui::SliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); P(ImGui::SliderScalar(FM_NAME(FM_FMS),ImGuiDataType_U8,&ins->fm.fms,&_ZERO,&_SEVEN));
ImGui::TableNextColumn(); ImGui::TableNextColumn();
drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); P(ImGui::SliderScalar(FM_NAME(FM_ALG),ImGuiDataType_U8,&ins->fm.alg,&_ZERO,&_SEVEN));
P(ImGui::SliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE));
ImGui::TableNextColumn();
drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale));
break;
case DIV_INS_OPL:
case DIV_INS_OPLL: {
bool dc=ins->fm.fms;
bool dm=ins->fm.ams;
bool sus=ins->fm.alg;
ImGui::TableNextColumn();
ImGui::BeginDisabled(ins->fm.opllPreset!=0);
P(ImGui::SliderScalar(FM_NAME(FM_FB),ImGuiDataType_U8,&ins->fm.fb,&_ZERO,&_SEVEN));
if (ImGui::Checkbox(FM_NAME(FM_DC),&dc)) { PARAMETER
ins->fm.fms=dc;
}
ImGui::EndDisabled();
ImGui::TableNextColumn();
if (ImGui::Checkbox(FM_NAME(FM_SUS),&sus)) { PARAMETER
ins->fm.alg=sus;
}
ImGui::BeginDisabled(ins->fm.opllPreset!=0);
if (ImGui::Checkbox(FM_NAME(FM_DM),&dm)) { PARAMETER
ins->fm.ams=dm;
}
ImGui::EndDisabled();
ImGui::TableNextColumn();
drawAlgorithm(0,FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale));
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::BeginCombo("##LLPreset",opllInsNames[ins->fm.opllPreset])) {
for (int i=0; i<17; i++) {
if (ImGui::Selectable(opllInsNames[i])) {
ins->fm.opllPreset=i;
}
}
ImGui::EndCombo();
}
break;
}
default:
break;
}
ImGui::EndTable(); ImGui::EndTable();
} }
if (ImGui::BeginTable("FMOperators",2,ImGuiTableFlags_SizingStretchSame)) {
for (int i=0; i<4; i++) { if (ins->type==DIV_INS_OPLL && ins->fm.opllPreset==16) {
DivInstrumentFM::Operator& op=ins->fm.op[opOrder[i]]; ImGui::Text("the Drums patch is only there for compatibility.\nit is highly encouraged you use the OPLL (drums) system instead!");
}
bool willDisplayOps=true;
int opCount=4;
if (ins->type==DIV_INS_OPLL && ins->fm.opllPreset!=0) willDisplayOps=false;
if (ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL) opCount=2;
if (!willDisplayOps && ins->type==DIV_INS_OPLL) {
P(ImGui::SliderScalar("Volume##TL",ImGuiDataType_U8,&ins->fm.op[1].tl,&_FIFTEEN,&_ZERO));
}
if (willDisplayOps) if (ImGui::BeginTable("FMOperators",2,ImGuiTableFlags_SizingStretchSame)) {
for (int i=0; i<opCount; i++) {
DivInstrumentFM::Operator& op=ins->fm.op[(opCount==4)?opOrder[i]:i];
if ((i+1)&1) ImGui::TableNextRow(); if ((i+1)&1) ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Separator(); ImGui::Separator();
@ -775,13 +874,27 @@ void FurnaceGUI::drawInsEdit() {
ImGui::SameLine(); ImGui::SameLine();
int maxTl=127;
if (ins->type==DIV_INS_OPLL) {
if (i==1) {
maxTl=15;
} else {
maxTl=63;
}
}
bool ssgOn=op.ssgEnv&8; bool ssgOn=op.ssgEnv&8;
bool ksrOn=op.ksr;
bool vibOn=op.vib;
unsigned char ssgEnv=op.ssgEnv&7; unsigned char ssgEnv=op.ssgEnv&7;
if (ImGui::Checkbox("SSG On",&ssgOn)) { PARAMETER int maxArDr=(ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ)?31:15;
if (ImGui::Checkbox((ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPLL)?FM_NAME(FM_EGS):"SSG On",&ssgOn)) { PARAMETER
op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3); op.ssgEnv=(op.ssgEnv&7)|(ssgOn<<3);
} }
if (ImGui::IsItemHovered()) { if (ins->type==DIV_INS_FM) {
ImGui::SetTooltip("Only for Genesis and Neo Geo systems"); if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Only for Genesis and Neo Geo systems");
}
} }
//52.0 controls vert scaling; default 96 //52.0 controls vert scaling; default 96
@ -794,14 +907,14 @@ void FurnaceGUI::drawInsEdit() {
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##AR",ImGuiDataType_U8,&op.ar,&_THIRTY_ONE,&_ZERO)); P(ImGui::SliderScalar("##AR",ImGuiDataType_U8,&op.ar,&maxArDr,&_ZERO));
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_AR)); ImGui::Text("%s",FM_NAME(FM_AR));
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##DR",ImGuiDataType_U8,&op.dr,&_THIRTY_ONE,&_ZERO)); P(ImGui::SliderScalar("##DR",ImGuiDataType_U8,&op.dr,&maxArDr,&_ZERO));
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_DR)); ImGui::Text("%s",FM_NAME(FM_DR));
@ -812,12 +925,14 @@ void FurnaceGUI::drawInsEdit() {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_SL)); ImGui::Text("%s",FM_NAME(FM_SL));
ImGui::TableNextRow(); if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) {
ImGui::TableNextColumn(); ImGui::TableNextRow();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::TableNextColumn();
P(ImGui::SliderScalar("##D2R",ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO)); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::TableNextColumn(); P(ImGui::SliderScalar("##D2R",ImGuiDataType_U8,&op.d2r,&_THIRTY_ONE,&_ZERO));
ImGui::Text("%s",FM_NAME(FM_D2R)); ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_D2R));
}
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
@ -829,7 +944,7 @@ void FurnaceGUI::drawInsEdit() {
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##TL",ImGuiDataType_U8,&op.tl,&_ONE_HUNDRED_TWENTY_SEVEN,&_ZERO)); P(ImGui::SliderScalar("##TL",ImGuiDataType_U8,&op.tl,&maxTl,&_ZERO));
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_TL)); ImGui::Text("%s",FM_NAME(FM_TL));
@ -842,9 +957,15 @@ void FurnaceGUI::drawInsEdit() {
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE)); if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) {
ImGui::TableNextColumn(); P(ImGui::SliderScalar("##RS",ImGuiDataType_U8,&op.rs,&_ZERO,&_THREE));
ImGui::Text("%s",FM_NAME(FM_RS)); ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_RS));
} else {
P(ImGui::SliderScalar("##KSL",ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE));
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_KSL));
}
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
@ -853,37 +974,50 @@ void FurnaceGUI::drawInsEdit() {
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_MULT)); ImGui::Text("%s",FM_NAME(FM_MULT));
int detune=(op.dt&7)-3; if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) {
ImGui::TableNextRow(); int detune=(op.dt&7)-3;
ImGui::TableNextColumn(); ImGui::TableNextRow();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::TableNextColumn();
if (ImGui::SliderInt("##DT",&detune,-3,3)) { PARAMETER ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
op.dt=detune+3; if (ImGui::SliderInt("##DT",&detune,-3,3)) { PARAMETER
} op.dt=detune+3;
ImGui::TableNextColumn(); }
ImGui::Text("%s",FM_NAME(FM_DT)); ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_DT));
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
P(ImGui::SliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE)); P(ImGui::SliderScalar("##DT2",ImGuiDataType_U8,&op.dt2,&_ZERO,&_THREE));
if (ImGui::IsItemHovered()) { if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Only for Arcade system"); ImGui::SetTooltip("Only for Arcade system");
} }
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_DT2)); ImGui::Text("%s",FM_NAME(FM_DT2));
ImGui::TableNextRow(); ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::TableNextColumn();
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
if (ImGui::SliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER if (ImGui::SliderScalar("##SSG",ImGuiDataType_U8,&ssgEnv,&_ZERO,&_SEVEN,ssgEnvTypes[ssgEnv])) { PARAMETER
op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7); op.ssgEnv=(op.ssgEnv&8)|(ssgEnv&7);
}
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_SSG));
} }
ImGui::TableNextColumn();
ImGui::Text("%s",FM_NAME(FM_SSG));
ImGui::EndTable(); ImGui::EndTable();
} }
if (ins->type==DIV_INS_OPLL || ins->type==DIV_INS_OPL) {
if (ImGui::Checkbox(FM_NAME(FM_VIB),&vibOn)) { PARAMETER
op.vib=vibOn;
}
ImGui::SameLine();
if (ImGui::Checkbox(FM_NAME(FM_KSR),&ksrOn)) { PARAMETER
op.ksr=ksrOn;
}
}
ImGui::PopID(); ImGui::PopID();
} }
ImGui::EndTable(); ImGui::EndTable();