WIP: adding fixed pitch mode; fix UB in ESFM driver
This commit is contained in:
parent
84e0ec9dae
commit
4a0295fd1f
|
@ -245,6 +245,7 @@ bool DivInstrumentESFM::Operator::operator==(const DivInstrumentESFM::Operator&
|
|||
_C(modIn) &&
|
||||
_C(left) &&
|
||||
_C(right) &&
|
||||
_C(fixed) &&
|
||||
_C(ct) &&
|
||||
_C(dt)
|
||||
);
|
||||
|
@ -764,7 +765,7 @@ void DivInstrument::writeFeatureEF(SafeWriter* w) {
|
|||
DivInstrumentESFM::Operator& op=esfm.op[i];
|
||||
|
||||
w->writeC(((op.delay&7)<<5)|((op.outLvl&7)<<2)|((op.right&1)<<1)|(op.left&1));
|
||||
w->writeC(op.modIn&7);
|
||||
w->writeC((op.fixed&1)<<3|(op.modIn&7));
|
||||
w->writeC(op.ct);
|
||||
w->writeC(op.dt);
|
||||
}
|
||||
|
@ -2644,6 +2645,7 @@ void DivInstrument::readFeatureEF(SafeReader& reader, short version) {
|
|||
|
||||
next=reader.readC();
|
||||
op.modIn=next&7;
|
||||
op.fixed=(next>>3)&1;
|
||||
|
||||
op.ct=reader.readC();
|
||||
op.dt=reader.readC();
|
||||
|
|
|
@ -756,7 +756,7 @@ struct DivInstrumentSNES {
|
|||
|
||||
// ESFM operator structure:
|
||||
// - DELAY, OUT, MOD, L, R, NOISE
|
||||
// - Virtual: CT, DT, DTRAW
|
||||
// - Virtual: CT, DT, FIXED
|
||||
// - In FM struct: AM, DAM, AR, DR, MULT, RR, SL, TL
|
||||
// - In FM struct: KSL, VIB, DVB, WS, SUS, KSR
|
||||
// - Not in struct: FNUML, FNUMH, BLOCK
|
||||
|
@ -770,7 +770,7 @@ struct DivInstrumentESFM {
|
|||
// Only works on OP4, so putting it outside the Operator struct instead
|
||||
unsigned char noise;
|
||||
struct Operator {
|
||||
unsigned char delay, outLvl, modIn, left, right;
|
||||
unsigned char delay, outLvl, modIn, left, right, fixed;
|
||||
signed char ct, dt;
|
||||
|
||||
bool operator==(const Operator& other);
|
||||
|
@ -781,8 +781,9 @@ struct DivInstrumentESFM {
|
|||
delay(0),
|
||||
outLvl(0),
|
||||
modIn(0),
|
||||
left(true),
|
||||
right(true),
|
||||
left(1),
|
||||
right(1),
|
||||
fixed(0),
|
||||
ct(0),
|
||||
dt(0) {}
|
||||
} op[4];
|
||||
|
|
|
@ -218,12 +218,17 @@ void DivPlatformESFM::tick(bool sysTick) {
|
|||
DivInstrumentESFM::Operator& opE=chan[i].state.esfm.op[o];
|
||||
int ct=(int)opE.ct;
|
||||
int dt=(int)opE.dt;
|
||||
if (opE.fixed) {
|
||||
chan[i].freqL[o]=opE.dt;
|
||||
chan[i].freqH[o]=opE.ct&0x1f;
|
||||
} else {
|
||||
int opFreq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride+ct:chan[i].arpOff+ct,chan[i].fixedArp,false,octave(chan[i].baseFreq)*2,chan[i].pitch2+dt,chipClock,CHIP_FREQBASE);
|
||||
if (opFreq<0) opFreq=0;
|
||||
if (opFreq>131071) opFreq=131071;
|
||||
int freqt=toFreq(opFreq);
|
||||
chan[i].freqL[o]=freqt&0xff;
|
||||
chan[i].freqH[o]=freqt>>8;
|
||||
}
|
||||
immWrite(baseAddr+OFFSET_FREQL,chan[i].freqL[o]);
|
||||
immWrite(baseAddr+OFFSET_FREQH_BLOCK_DELAY,chan[i].freqH[o]|(opE.delay<<5));
|
||||
}
|
||||
|
@ -558,7 +563,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
op.rr=c.value2&15;
|
||||
rWrite(baseAddr+OFFSET_SL_RR,(op.sl<<4)|op.rr);
|
||||
rWrite(baseAddr+OFFSET_SL_RR,(op.sl<<4)|(op.rr&0xf));
|
||||
}
|
||||
} else {
|
||||
unsigned int o = c.value;
|
||||
|
@ -566,7 +571,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
op.rr=c.value2&15;
|
||||
rWrite(baseAddr+OFFSET_SL_RR,(op.sl<<4)|op.rr);
|
||||
rWrite(baseAddr+OFFSET_SL_RR,(op.sl<<4)|(op.rr&0xf));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@ class DivPlatformESFM: public DivDispatch {
|
|||
SharedChannel<int>(0),
|
||||
freqL{0, 0, 0, 0},
|
||||
freqH{0, 0, 0, 0},
|
||||
hardReset(false),
|
||||
globalPan(3),
|
||||
macroVolMul(64) {}
|
||||
};
|
||||
|
|
|
@ -44,16 +44,16 @@ const char* fmParamNames[3][32]={
|
|||
{"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", "EGS", "REV", "Fine", "FMS/PMS2", "AMS2"}
|
||||
};
|
||||
|
||||
const char* esfmParamLongNames[8]={
|
||||
"OP4 Noise Mode", "Envelope Delay", "Output Level", "Modulation Input Level", "Left Output", "Right Output", "Coarse Tune (semitones)", "Detune"
|
||||
const char* esfmParamLongNames[9]={
|
||||
"OP4 Noise Mode", "Envelope Delay", "Output Level", "Modulation Input Level", "Left Output", "Right Output", "Coarse Tune (semitones)", "Detune", "Fixed Frequency Mode"
|
||||
};
|
||||
|
||||
const char* esfmParamNames[8]={
|
||||
"OP4 Noise Mode", "Env. Delay", "Output Level", "ModInput", "Left", "Right", "Coarse Tn.", "Detune"
|
||||
const char* esfmParamNames[9]={
|
||||
"OP4 Noise Mode", "Env. Delay", "Output Level", "ModInput", "Left", "Right", "Coarse Tn.", "Detune", "Fixed"
|
||||
};
|
||||
|
||||
const char* esfmParamShortNames[8]={
|
||||
"RHY", "DL", "OL", "MI", "L", "R", "CT", "DT"
|
||||
const char* esfmParamShortNames[9]={
|
||||
"RHY", "DL", "OL", "MI", "L", "R", "CT", "DT", "FIX"
|
||||
};
|
||||
|
||||
const char* fmParamShortNames[3][32]={
|
||||
|
@ -230,7 +230,8 @@ enum ESFMParams {
|
|||
ESFM_LEFT=4,
|
||||
ESFM_RIGHT=5,
|
||||
ESFM_CT=6,
|
||||
ESFM_DT=7
|
||||
ESFM_DT=7,
|
||||
ESFM_FIXED=8
|
||||
};
|
||||
|
||||
#define FM_NAME(x) fmParamNames[settings.fmNames][x]
|
||||
|
@ -3951,7 +3952,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
}
|
||||
|
||||
float sliderHeight=200.0f*dpiScale;
|
||||
float waveWidth=140.0*dpiScale*((ins->type==DIV_INS_ESFM)?0.8f:1.0f);
|
||||
float waveWidth=140.0*dpiScale*((ins->type==DIV_INS_ESFM)?0.85f:1.0f);
|
||||
float waveHeight=sliderHeight-ImGui::GetFrameHeightWithSpacing()*((ins->type==DIV_INS_OPZ || ins->type==DIV_INS_OPL || ins->type==DIV_INS_ESFM)?5.0f:4.5f);
|
||||
|
||||
int maxTl=127;
|
||||
|
@ -4312,6 +4313,36 @@ void FurnaceGUI::drawInsEdit() {
|
|||
snprintf(tempID,1024,"%s: %%d",FM_NAME(FM_MULT));
|
||||
P(CWSliderScalar("##MULT",ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN,tempID)); rightClickable
|
||||
|
||||
if (opE.fixed) {
|
||||
int block=(opE.ct>>2)&7;
|
||||
int freqNum=((opE.ct&3)<<8)|((unsigned char)opE.dt);
|
||||
ImGui::Text("Blk");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Block");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
//ImVec2 cursorAlign=ImGui::GetCursorPos();
|
||||
if (ImGui::InputInt("##Block",&block,1,1)) {
|
||||
if (block<0) block=0;
|
||||
if (block>7) block=7;
|
||||
opE.ct=(opE.ct&(~(7<<2)))|(block<<2);
|
||||
}
|
||||
|
||||
ImGui::Text("F");
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Frequency (F-Num)");
|
||||
}
|
||||
ImGui::SameLine();
|
||||
//ImGui::SetCursorPos(ImVec2(cursorAlign.x,ImGui::GetCursorPosY()));
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::InputInt("##FreqNum",&freqNum,1,16)) {
|
||||
if (freqNum<0) freqNum=0;
|
||||
if (freqNum>1023) freqNum=1023;
|
||||
opE.dt=freqNum&0xff;
|
||||
opE.ct=(opE.ct&(~3))|(freqNum>>8);
|
||||
}
|
||||
} else {
|
||||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
snprintf(tempID,1024,"%s: %%d",ESFM_NAME(ESFM_CT));
|
||||
P(CWSliderScalar("##CT",ImGuiDataType_S8,&opE.ct,&_MINUS_TWENTY_FOUR,&_TWENTY_FOUR,tempID)); rightClickable
|
||||
|
@ -4319,6 +4350,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
snprintf(tempID,1024,"%s: %%d",ESFM_NAME(ESFM_DT));
|
||||
P(CWSliderScalar("##DT",ImGuiDataType_S8,&opE.dt,&_MINUS_ONE_HUNDRED_TWENTY_EIGHT,&_ONE_HUNDRED_TWENTY_SEVEN,tempID)); rightClickable
|
||||
}
|
||||
|
||||
if (ImGui::BeginTable("panCheckboxes",2,ImGuiTableFlags_SizingStretchSame)) {
|
||||
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0f);
|
||||
|
@ -4347,9 +4379,12 @@ void FurnaceGUI::drawInsEdit() {
|
|||
|
||||
ImGui::TableNextColumn();
|
||||
float envHeight=sliderHeight;//-ImGui::GetStyle().ItemSpacing.y*2.0f;
|
||||
if (ins->type==DIV_INS_OPZ || ins->type==DIV_INS_ESFM) {
|
||||
if (ins->type==DIV_INS_OPZ) {
|
||||
envHeight-=ImGui::GetFrameHeightWithSpacing()*2.0f;
|
||||
}
|
||||
if (ins->type==DIV_INS_ESFM) {
|
||||
envHeight-=ImGui::GetFrameHeightWithSpacing()*3.0f;
|
||||
}
|
||||
drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL || ins->type==DIV_INS_ESFM)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,fmOrigin.alg,maxTl,maxArDr,15,ImVec2(ImGui::GetContentRegionAvail().x,envHeight),ins->type);
|
||||
|
||||
if (ins->type==DIV_INS_OPZ) {
|
||||
|
@ -4408,6 +4443,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
} rightClickable
|
||||
|
||||
bool amOn=op.am;
|
||||
bool fixedOn=opE.fixed;
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Checkbox(FM_SHORT_NAME(FM_KSR),&ksrOn)) { PARAMETER
|
||||
op.ksr=ksrOn;
|
||||
|
@ -4430,12 +4466,27 @@ void FurnaceGUI::drawInsEdit() {
|
|||
if (ImGui::Checkbox(FM_SHORT_NAME(FM_AM),&amOn)) { PARAMETER
|
||||
op.am=amOn;
|
||||
}
|
||||
|
||||
bool damOn=op.dam;
|
||||
bool dvbOn=op.dvb;
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Checkbox(FM_SHORT_NAME(FM_DVB),&dvbOn)) { PARAMETER
|
||||
op.dvb=dvbOn;
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Checkbox(FM_SHORT_NAME(FM_DAM),&damOn)) { PARAMETER
|
||||
op.dam=damOn;
|
||||
}
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Checkbox(FM_SHORT_NAME(FM_SUS),&susOn)) { PARAMETER
|
||||
op.sus=susOn;
|
||||
}
|
||||
if (ImGui::Checkbox(ESFM_NAME(ESFM_FIXED),&fixedOn)) { PARAMETER
|
||||
opE.fixed=fixedOn;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue