Add instrument for OPL4 PCM, Macros and Effects

TODO: Phase reset, Keyon/off
This commit is contained in:
cam900 2024-07-12 17:37:27 +09:00
parent 221fa5aa42
commit 65f48cc574
13 changed files with 423 additions and 88 deletions

View file

@ -263,6 +263,22 @@ enum DivDispatchCmds {
DIV_CMD_BIFURCATOR_STATE_LOAD,
DIV_CMD_BIFURCATOR_PARAMETER,
DIV_CMD_OPL4_PCM_MIX_FM, // (value)
DIV_CMD_OPL4_PCM_MIX_PCM, // (value)
DIV_CMD_OPL4_PCM_LFO, // (value)
DIV_CMD_OPL4_PCM_VIB, // (value)
DIV_CMD_OPL4_PCM_AM, // (value)
DIV_CMD_OPL4_PCM_AR, // (value)
DIV_CMD_OPL4_PCM_D1R, // (value)
DIV_CMD_OPL4_PCM_DL, // (value)
DIV_CMD_OPL4_PCM_D2R, // (value)
DIV_CMD_OPL4_PCM_RC, // (value)
DIV_CMD_OPL4_PCM_RR, // (value)
DIV_CMD_OPL4_PCM_DAMP, // (value)
DIV_CMD_OPL4_PCM_PSEUDO_REVERB, // (value)
DIV_CMD_OPL4_PCM_LFO_RESET, // (value)
DIV_CMD_OPL4_PCM_LEVEL_DIRECT, // (value)
DIV_CMD_MAX
};

View file

@ -938,7 +938,8 @@ void DivEngine::delUnusedSamples() {
i->type==DIV_INS_C219 ||
i->type==DIV_INS_NDS ||
i->type==DIV_INS_GBA_DMA ||
i->type==DIV_INS_GBA_MINMOD) {
i->type==DIV_INS_GBA_MINMOD ||
i->type==DIV_INS_OPL4PCM) {
if (i->amiga.initSample>=0 && i->amiga.initSample<song.sampleLen) {
isUsed[i->amiga.initSample]=true;
}

View file

@ -178,6 +178,15 @@ bool DivInstrumentMultiPCM::operator==(const DivInstrumentMultiPCM& other) {
);
}
bool DivInstrumentOPL4PCM::operator==(const DivInstrumentOPL4PCM& other) {
return (
_C(damp) &&
_C(pseudoReverb) &&
_C(lfoReset) &&
_C(levelDirect)
);
}
bool DivInstrumentWaveSynth::operator==(const DivInstrumentWaveSynth& other) {
return (
_C(wave1) &&
@ -848,6 +857,17 @@ void DivInstrument::writeFeatureS2(SafeWriter* w) {
FEATURE_END;
}
void DivInstrument::writeFeatureO4(SafeWriter* w) {
FEATURE_BEGIN("O4");
w->writeC(opl4pcm.damp);
w->writeC(opl4pcm.pseudoReverb);
w->writeC(opl4pcm.lfoReset);
w->writeC(opl4pcm.levelDirect);
FEATURE_END;
}
void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bool insName) {
size_t blockStartSeek=0;
size_t blockEndSeek=0;
@ -894,6 +914,7 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo
bool featureEF=false;
bool featurePN=false;
bool featureS2=false;
bool featureO4=false;
bool checkForWL=false;
@ -1137,6 +1158,12 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo
feature64=true;
featureS2=true;
break;
case DIV_INS_OPL4PCM:
featureSM=true;
featureSL=true;
featureMP=true;
featureO4=true;
break;
case DIV_INS_MAX:
break;
case DIV_INS_NULL:
@ -1193,6 +1220,9 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo
if (sid2!=defaultIns.sid2) {
featureS2=true;
}
if (opl4pcm!=defaultIns.opl4pcm) {
featureO4=true;
}
}
// check ins name
@ -1344,6 +1374,9 @@ void DivInstrument::putInsData2(SafeWriter* w, bool fui, const DivSong* song, bo
if (featureS2) {
writeFeatureS2(w);
}
if (featureO4) {
writeFeatureO4(w);
}
if (fui && (featureSL || featureWL)) {
w->write("EN",2);
@ -2172,6 +2205,17 @@ void DivInstrument::readFeatureS2(SafeReader& reader, short version) {
READ_FEAT_END;
}
void DivInstrument::readFeatureO4(SafeReader& reader, short version) {
READ_FEAT_BEGIN;
opl4pcm.damp=reader.readC();
opl4pcm.pseudoReverb=reader.readC();
opl4pcm.lfoReset=reader.readC();
opl4pcm.levelDirect=reader.readC();
READ_FEAT_END;
}
DivDataErrors DivInstrument::readInsDataNew(SafeReader& reader, short version, bool fui, DivSong* song) {
unsigned char featCode[2];
bool volIsCutoff=false;
@ -2246,6 +2290,8 @@ DivDataErrors DivInstrument::readInsDataNew(SafeReader& reader, short version, b
readFeaturePN(reader,version);
} else if (memcmp(featCode,"S2",2)==0) { // SID2
readFeatureS2(reader,version);
} else if (memcmp(featCode,"O4",2)==0) { // OPL4 PCM
readFeatureO4(reader,version);
} else {
if (song==NULL && (memcmp(featCode,"SL",2)==0 || (memcmp(featCode,"WL",2)==0))) {
// nothing

View file

@ -94,6 +94,7 @@ enum DivInstrumentType: unsigned short {
DIV_INS_GBA_MINMOD=61,
DIV_INS_BIFURCATOR=62,
DIV_INS_SID2=63, // coincidence!
DIV_INS_OPL4PCM=64,
DIV_INS_MAX,
DIV_INS_NULL
};
@ -620,6 +621,22 @@ struct DivInstrumentMultiPCM {
}
};
struct DivInstrumentOPL4PCM {
bool damp, pseudoReverb, lfoReset, levelDirect;
bool operator==(const DivInstrumentOPL4PCM& other);
bool operator!=(const DivInstrumentOPL4PCM& other) {
return !(*this==other);
}
DivInstrumentOPL4PCM():
damp(false),
pseudoReverb(false),
lfoReset(false),
levelDirect(true) {
}
};
enum DivWaveSynthEffects {
DIV_WS_NONE=0,
// one waveform effects
@ -879,6 +896,7 @@ struct DivInstrument {
DivInstrumentESFM esfm;
DivInstrumentPowerNoise powernoise;
DivInstrumentSID2 sid2;
DivInstrumentOPL4PCM opl4pcm;
/**
* these are internal functions.
@ -906,6 +924,7 @@ struct DivInstrument {
void writeFeatureEF(SafeWriter* w);
void writeFeaturePN(SafeWriter* w);
void writeFeatureS2(SafeWriter* w);
void writeFeatureO4(SafeWriter* w);
void readFeatureNA(SafeReader& reader, short version);
void readFeatureFM(SafeReader& reader, short version);
@ -929,6 +948,7 @@ struct DivInstrument {
void readFeatureEF(SafeReader& reader, short version);
void readFeaturePN(SafeReader& reader, short version);
void readFeatureS2(SafeReader& reader, short version);
void readFeatureO4(SafeReader& reader, short version);
DivDataErrors readInsDataOld(SafeReader& reader, short version);
DivDataErrors readInsDataNew(SafeReader& reader, short version, bool fui, DivSong* song);

View file

@ -1002,9 +1002,10 @@ void DivPlatformOPL::tick(bool sysTick) {
chan[i].freqChanged=true;
}
if (chan[i].std.phaseReset.had) {
if (chan[i].std.phaseReset.had) { // TODO: not working
if (chan[i].std.phaseReset.val==1 && chan[i].active) {
chan[i].keyOn=true;
chan[i].writeCtrl=true;
}
}
@ -1014,78 +1015,51 @@ void DivPlatformOPL::tick(bool sysTick) {
chan[i].writeCtrl=true;
}
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
DivSample* s=parent->getSample(chan[i].sample);
unsigned char ctrl=0;
double off=(s->centerRate>=1)?((double)s->centerRate/8363.0):1.0;
chan[i].freq=(int)(off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,(524288*768)));
if (chan[i].freq<0x400) chan[i].freq=0x400;
if (chan[i].freq>0x4000000) chan[i].freq=0x4000000;
if (chan[i].freq>=0x2000000) {
chan[i].freqH=15;
} else if (chan[i].freq>=0x1000000) {
chan[i].freqH=14;
} else if (chan[i].freq>=0x800000) {
chan[i].freqH=13;
} else if (chan[i].freq>=0x400000) {
chan[i].freqH=12;
} else if (chan[i].freq>=0x200000) {
chan[i].freqH=11;
} else if (chan[i].freq>=0x100000) {
chan[i].freqH=10;
} else if (chan[i].freq>=0x80000) {
chan[i].freqH=9;
} else if (chan[i].freq>=0x40000) {
chan[i].freqH=8;
} else if (chan[i].freq>=0x20000) {
chan[i].freqH=7;
} else if (chan[i].freq>=0x10000) {
chan[i].freqH=6;
} else if (chan[i].freq>=0x8000) {
chan[i].freqH=5;
} else if (chan[i].freq>=0x4000) {
chan[i].freqH=4;
} else if (chan[i].freq>=0x2000) {
chan[i].freqH=3;
} else if (chan[i].freq>=0x1000) {
chan[i].freqH=2;
} else if (chan[i].freq>=0x800) {
chan[i].freqH=1;
} else {
chan[i].freqH=0;
}
chan[i].freqL=(chan[i].freq>>chan[i].freqH)&0x3ff;
chan[i].freqH=8^chan[i].freqH;
ctrl|=(chan[i].active?0x80:0)|(chan[i].damp?0x40:0)|(isMuted[i]?8:(chan[i].pan&0xf));
unsigned int waveNum=chan[i].sample;
if (ramSize<=0x200000) {
waveNum=MIN(waveNum,0x7f)|0x180;
}
if (chan[i].keyOn) {
rWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+PCM_REG(i),ctrl&~0x80); // force keyoff first
rWrite(PCM_ADDR_WAVE_H_FN_L+PCM_REG(i),((chan[i].freqL&0x7f)<<1)|((waveNum>>8)&1));
rWrite(PCM_ADDR_WAVE_L+PCM_REG(i),waveNum&0xff);
if (!chan[i].std.vol.had) {
chan[i].outVol=chan[i].vol;
immWrite(PCM_ADDR_TL+(PCM_REG(i)),((0x7f-chan[i].outVol)<<1)|(chan[i].levelDirect?1:0));
}
chan[i].writeCtrl=true;
chan[i].keyOn=false;
}
if (chan[i].keyOff) {
chan[i].writeCtrl=true;
chan[i].keyOff=false;
}
if (chan[i].freqChanged) {
rWrite(PCM_ADDR_WAVE_H_FN_L+PCM_REG(i),((chan[i].freqL&0x7f)<<1)|((waveNum>>8)&1));
rWrite(PCM_ADDR_FN_H_PR_OCT+PCM_REG(i),((chan[i].freqH&0xf)<<4)|(chan[i].pseudoReverb?0x08:0x00)|((chan[i].freqL>>7)&0x7));
chan[i].freqChanged=false;
}
if (chan[i].writeCtrl) {
rWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+PCM_REG(i),ctrl);
chan[i].writeCtrl=false;
}
if (chan[i].std.ex1.had) {
chan[i].lfo=chan[i].std.ex1.val&0x7;
rWrite(PCM_ADDR_LFO_VIB+PCM_REG(i),(chan[i].lfo<<3)|(chan[i].vib));
}
if (chan[i].std.fms.had) {
chan[i].vib=chan[i].std.fms.val&0x7;
rWrite(PCM_ADDR_LFO_VIB+PCM_REG(i),(chan[i].lfo<<3)|(chan[i].vib));
}
if (chan[i].std.ams.had) {
chan[i].am=chan[i].std.ams.val&0x7;
rWrite(PCM_ADDR_AM+PCM_REG(i),chan[i].am);
}
if (chan[i].std.ex2.had) {
chan[i].ar=chan[i].std.ex2.val&0xf;
rWrite(PCM_ADDR_AR_D1R+PCM_REG(i),(chan[i].ar<<4)|(chan[i].d1r));
}
if (chan[i].std.ex3.had) {
chan[i].d1r=chan[i].std.ex3.val&0xf;
rWrite(PCM_ADDR_AR_D1R+PCM_REG(i),(chan[i].ar<<4)|(chan[i].d1r));
}
if (chan[i].std.ex4.had) {
chan[i].dl=chan[i].std.ex4.val&0xf;
rWrite(PCM_ADDR_DL_D2R+PCM_REG(i),(chan[i].dl<<4)|(chan[i].d2r));
}
if (chan[i].std.ex5.had) {
chan[i].d2r=chan[i].std.ex5.val&0xf;
rWrite(PCM_ADDR_DL_D2R+PCM_REG(i),(chan[i].dl<<4)|(chan[i].d2r));
}
if (chan[i].std.ex6.had) {
chan[i].rc=chan[i].std.ex6.val&0xf;
rWrite(PCM_ADDR_RC_RR+PCM_REG(i),(chan[i].rc<<4)|(chan[i].rr));
}
if (chan[i].std.ex7.had) {
chan[i].rr=chan[i].std.ex7.val&0xf;
rWrite(PCM_ADDR_RC_RR+PCM_REG(i),(chan[i].rc<<4)|(chan[i].rr));
}
} else {
int ops=(slots[3][i]!=255 && chan[i].state.ops==4 && oplType==3)?4:2;
chan[i].std.next();
@ -1360,7 +1334,83 @@ void DivPlatformOPL::tick(bool sysTick) {
bool updateDrums=false;
for (int i=0; i<totalChans; i++) {
if (PCM_CHECK(i)) { // OPL4 PCM
if (chan[i].freqChanged || chan[i].keyOn || chan[i].keyOff) {
DivSample* s=parent->getSample(chan[i].sample);
unsigned char ctrl=0;
double off=(s->centerRate>=1)?((double)s->centerRate/8363.0):1.0;
chan[i].freq=(int)(off*parent->calcFreq(chan[i].baseFreq,chan[i].pitch,chan[i].fixedArp?chan[i].baseNoteOverride:chan[i].arpOff,chan[i].fixedArp,false,2,chan[i].pitch2,chipClock,(524288*768)));
if (chan[i].freq<0x400) chan[i].freq=0x400;
if (chan[i].freq>0x4000000) chan[i].freq=0x4000000;
if (chan[i].freq>=0x2000000) {
chan[i].freqH=15;
} else if (chan[i].freq>=0x1000000) {
chan[i].freqH=14;
} else if (chan[i].freq>=0x800000) {
chan[i].freqH=13;
} else if (chan[i].freq>=0x400000) {
chan[i].freqH=12;
} else if (chan[i].freq>=0x200000) {
chan[i].freqH=11;
} else if (chan[i].freq>=0x100000) {
chan[i].freqH=10;
} else if (chan[i].freq>=0x80000) {
chan[i].freqH=9;
} else if (chan[i].freq>=0x40000) {
chan[i].freqH=8;
} else if (chan[i].freq>=0x20000) {
chan[i].freqH=7;
} else if (chan[i].freq>=0x10000) {
chan[i].freqH=6;
} else if (chan[i].freq>=0x8000) {
chan[i].freqH=5;
} else if (chan[i].freq>=0x4000) {
chan[i].freqH=4;
} else if (chan[i].freq>=0x2000) {
chan[i].freqH=3;
} else if (chan[i].freq>=0x1000) {
chan[i].freqH=2;
} else if (chan[i].freq>=0x800) {
chan[i].freqH=1;
} else {
chan[i].freqH=0;
}
chan[i].freqL=(chan[i].freq>>chan[i].freqH)&0x3ff;
chan[i].freqH=8^chan[i].freqH;
ctrl|=(chan[i].active?0x80:0)|(chan[i].damp?0x40:0)|(chan[i].lfoReset?0x20:0)|(chan[i].ch?0x10:0)|(isMuted[i]?8:(chan[i].pan&0xf));
unsigned int waveNum=chan[i].sample;
if (ramSize<=0x200000) {
waveNum=CLAMP(waveNum,0,0x7f)|0x180;
}
if (chan[i].keyOn) {
rWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+PCM_REG(i),ctrl&~0x80); // force keyoff first
rWrite(PCM_ADDR_WAVE_H_FN_L+PCM_REG(i),((chan[i].freqL&0x7f)<<1)|((waveNum>>8)&1));
rWrite(PCM_ADDR_WAVE_L+PCM_REG(i),waveNum&0xff);
rWrite(PCM_ADDR_LFO_VIB+PCM_REG(i),(chan[i].lfo<<3)|(chan[i].vib));
rWrite(PCM_ADDR_AR_D1R+PCM_REG(i),(chan[i].ar<<4)|(chan[i].d1r));
rWrite(PCM_ADDR_DL_D2R+PCM_REG(i),(chan[i].dl<<4)|(chan[i].d2r));
rWrite(PCM_ADDR_RC_RR+PCM_REG(i),(chan[i].rc<<4)|(chan[i].rr));
rWrite(PCM_ADDR_AM+PCM_REG(i),chan[i].am);
if (!chan[i].std.vol.had) {
chan[i].outVol=chan[i].vol;
immWrite(PCM_ADDR_TL+(PCM_REG(i)),((0x7f-chan[i].outVol)<<1)|(chan[i].levelDirect?1:0));
}
chan[i].writeCtrl=true;
chan[i].keyOn=false;
}
if (chan[i].keyOff) {
chan[i].writeCtrl=true;
chan[i].keyOff=false;
}
if (chan[i].freqChanged) {
rWrite(PCM_ADDR_WAVE_H_FN_L+PCM_REG(i),((chan[i].freqL&0x7f)<<1)|((waveNum>>8)&1));
rWrite(PCM_ADDR_FN_H_PR_OCT+PCM_REG(i),((chan[i].freqH&0xf)<<4)|(chan[i].pseudoReverb?0x08:0x00)|((chan[i].freqL>>7)&0x7));
chan[i].freqChanged=false;
}
if (chan[i].writeCtrl) {
rWrite(PCM_ADDR_KEY_DAMP_LFORST_CH_PAN+PCM_REG(i),ctrl);
chan[i].writeCtrl=false;
}
}
} else {
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);
@ -1655,6 +1705,35 @@ int DivPlatformOPL::dispatch(DivCommand c) {
chan[c.chan].freqChanged=true;
chan[c.chan].note=c.value;
}
if (ins->type==DIV_INS_OPL4PCM) {
chan[c.chan].lfo=ins->multipcm.lfo;
chan[c.chan].vib=ins->multipcm.vib;
chan[c.chan].am=ins->multipcm.am;
chan[c.chan].ar=ins->multipcm.ar;
chan[c.chan].d1r=ins->multipcm.d1r;
chan[c.chan].dl=ins->multipcm.dl;
chan[c.chan].d2r=ins->multipcm.d2r;
chan[c.chan].rc=ins->multipcm.rc;
chan[c.chan].rr=ins->multipcm.rr;
chan[c.chan].damp=ins->opl4pcm.damp;
chan[c.chan].pseudoReverb=ins->opl4pcm.pseudoReverb;
chan[c.chan].levelDirect=ins->opl4pcm.levelDirect;
chan[c.chan].lfoReset=ins->opl4pcm.lfoReset;
} else {
chan[c.chan].lfo=0;
chan[c.chan].vib=0;
chan[c.chan].am=0;
chan[c.chan].ar=15;
chan[c.chan].d1r=15;
chan[c.chan].dl=0;
chan[c.chan].d2r=0;
chan[c.chan].rc=15;
chan[c.chan].rr=15;
chan[c.chan].damp=false;
chan[c.chan].pseudoReverb=false;
chan[c.chan].levelDirect=true;
chan[c.chan].lfoReset=false;
}
chan[c.chan].active=true;
chan[c.chan].keyOn=true;
chan[c.chan].macroInit(ins);
@ -1852,6 +1931,7 @@ int DivPlatformOPL::dispatch(DivCommand c) {
break;
case DIV_CMD_PANNING: {
if (PCM_CHECK(c.chan)) {
chan[c.chan].ch=false;
chan[c.chan].pan=8^MIN(parent->convertPanSplitToLinearLR(c.value,c.value2,15)+1,15);
chan[c.chan].freqChanged=true;
chan[c.chan].writeCtrl=true;
@ -1880,6 +1960,12 @@ int DivPlatformOPL::dispatch(DivCommand c) {
break;
}
case DIV_CMD_SURROUND_PANNING: {
if (PCM_CHECK(c.chan)) {
chan[c.chan].ch=true;
chan[c.chan].freqChanged=true;
chan[c.chan].writeCtrl=true;
break;
}
if (oplType!=3) break;
if (c.chan==adpcmChan) break;
@ -2331,9 +2417,99 @@ int DivPlatformOPL::dispatch(DivCommand c) {
break;
}
case DIV_CMD_FM_HARD_RESET:
if (PCM_CHECK(c.chan)) break;
if (c.chan==adpcmChan) break;
chan[c.chan].hardReset=c.value;
break;
case DIV_CMD_OPL4_PCM_MIX_FM:
if (chipType==4) {
rWrite(PCM_ADDR_MIX_FM,(CLAMP((0x70-(c.value&0x70)),0,0x70)>>1)|(CLAMP((7-(c.value&7)),0,7)));
}
break;
case DIV_CMD_OPL4_PCM_MIX_PCM:
if (chipType==4) {
rWrite(PCM_ADDR_MIX_PCM,(CLAMP((0x70-(c.value&0x70)),0,0x70)>>1)|(CLAMP((7-(c.value&7)),0,7)));
}
break;
case DIV_CMD_OPL4_PCM_LFO:
if (PCM_CHECK(c.chan)) {
chan[c.chan].lfo=c.value&7;
rWrite(PCM_ADDR_LFO_VIB+PCM_REG(c.chan),(chan[c.chan].lfo<<3)|(chan[c.chan].vib));
}
break;
case DIV_CMD_OPL4_PCM_VIB:
if (PCM_CHECK(c.chan)) {
chan[c.chan].vib=c.value&7;
rWrite(PCM_ADDR_LFO_VIB+PCM_REG(c.chan),(chan[c.chan].lfo<<3)|(chan[c.chan].vib));
}
break;
case DIV_CMD_OPL4_PCM_AM:
if (PCM_CHECK(c.chan)) {
chan[c.chan].am=c.value&7;
rWrite(PCM_ADDR_AM+PCM_REG(c.chan),chan[c.chan].am);
}
break;
case DIV_CMD_OPL4_PCM_AR:
if (PCM_CHECK(c.chan)) {
chan[c.chan].ar=c.value&0xf;
rWrite(PCM_ADDR_AR_D1R+PCM_REG(c.chan),(chan[c.chan].ar<<4)|(chan[c.chan].d1r));
}
break;
case DIV_CMD_OPL4_PCM_D1R:
if (PCM_CHECK(c.chan)) {
chan[c.chan].d1r=c.value&0xf;
rWrite(PCM_ADDR_AR_D1R+PCM_REG(c.chan),(chan[c.chan].ar<<4)|(chan[c.chan].d1r));
}
break;
case DIV_CMD_OPL4_PCM_DL:
if (PCM_CHECK(c.chan)) {
chan[c.chan].dl=c.value&0xf;
rWrite(PCM_ADDR_DL_D2R+PCM_REG(c.chan),(chan[c.chan].dl<<4)|(chan[c.chan].d2r));
}
break;
case DIV_CMD_OPL4_PCM_D2R:
if (PCM_CHECK(c.chan)) {
chan[c.chan].d2r=c.value&0xf;
rWrite(PCM_ADDR_DL_D2R+PCM_REG(c.chan),(chan[c.chan].dl<<4)|(chan[c.chan].d2r));
}
break;
case DIV_CMD_OPL4_PCM_RC:
if (PCM_CHECK(c.chan)) {
chan[c.chan].rc=c.value&0xf;
rWrite(PCM_ADDR_RC_RR+PCM_REG(c.chan),(chan[c.chan].rc<<4)|(chan[c.chan].rr));
}
break;
case DIV_CMD_OPL4_PCM_RR:
if (PCM_CHECK(c.chan)) {
chan[c.chan].rr=c.value&0xf;
rWrite(PCM_ADDR_RC_RR+PCM_REG(c.chan),(chan[c.chan].rc<<4)|(chan[c.chan].rr));
}
break;
case DIV_CMD_OPL4_PCM_DAMP:
if (PCM_CHECK(c.chan)) {
chan[c.chan].damp=c.value&1;
chan[c.chan].freqChanged=true;
chan[c.chan].writeCtrl=true;
}
break;
case DIV_CMD_OPL4_PCM_PSEUDO_REVERB:
if (PCM_CHECK(c.chan)) {
chan[c.chan].pseudoReverb=c.value&1;
chan[c.chan].freqChanged=true;
}
break;
case DIV_CMD_OPL4_PCM_LFO_RESET:
if (PCM_CHECK(c.chan)) {
chan[c.chan].lfoReset=c.value&1;
chan[c.chan].freqChanged=true;
chan[c.chan].writeCtrl=true;
}
break;
case DIV_CMD_OPL4_PCM_LEVEL_DIRECT:
if (PCM_CHECK(c.chan)) {
immWrite(PCM_ADDR_TL+PCM_REG(c.chan),((0x7f-chan[c.chan].outVol)<<1)|(chan[c.chan].levelDirect?1:0));
}
break;
case DIV_CMD_MACRO_OFF:
chan[c.chan].std.mask(c.value,true);
break;
@ -3019,6 +3195,7 @@ void DivPlatformOPL::renderSamples(int sysID) {
case DIV_SAMPLE_DEPTH_8BIT:
bitDepth=0;
break;
// TODO: 12 bit PCM
case DIV_SAMPLE_DEPTH_16BIT:
bitDepth=2;
break;

View file

@ -61,7 +61,8 @@ class DivPlatformOPL: public DivDispatch {
unsigned int freqH, freqL;
int sample, fixedFreq;
bool furnacePCM, fourOp, hardReset, writeCtrl;
bool levelDirect, damp, pseudoReverb;
bool levelDirect, damp, pseudoReverb, lfoReset, ch;
int lfo, vib, am, ar, d1r, d2r, dl, rc, rr;
int pan;
int macroVolMul;
Channel():
@ -77,6 +78,17 @@ class DivPlatformOPL: public DivDispatch {
levelDirect(true),
damp(false),
pseudoReverb(false),
lfoReset(false),
ch(false),
lfo(0),
vib(0),
am(0),
ar(15),
d1r(15),
d2r(0),
dl(0),
rc(15),
rr(15),
pan(3),
macroVolMul(64) {
state.ops=2;
@ -208,7 +220,6 @@ class DivPlatformOPL: public DivDispatch {
void renderSamples(int chipID);
int init(DivEngine* parent, int channels, int sugRate, const DivConfig& flags);
void quit();
YMF278& getChip();
DivPlatformOPL():
pcmMemory(0x400000),
pcm(pcmMemory) {}

View file

@ -261,7 +261,23 @@ const char* cmdName[]={
"MINMOD_ECHO",
"BIFURCATOR_STATE_LOAD",
"BIFURCATOR_PARAMETER"
"BIFURCATOR_PARAMETER",
"OPL4_MIX_FM",
"OPL4_MIX_PCM",
"OPL4_LFO",
"OPL4_VIB",
"OPL4_AM",
"OPL4_AR",
"OPL4_D1R",
"OPL4_DL",
"OPL4_D2R",
"OPL4_RR",
"OPL4_RC",
"OPL4_DAMP",
"OPL4_PSEUDO_REVERB",
"OPL4_LFO_RESET",
"OPL4_LEVEL_DIRECT"
};
static_assert((sizeof(cmdName)/sizeof(void*))==DIV_CMD_MAX,"update cmdName!");

View file

@ -599,6 +599,25 @@ void DivEngine::registerSystems() {
{0x5b, {DIV_CMD_FM_KSR, _("5Bxy: Set whether key will scale envelope (x: operator from 1 to 4 (0 for all ops); y: enabled)"), effectOpVal<4>, effectValAnd<1>}},
};
EffectHandlerMap fmOPL4PostEffectHandlerMap(fmOPLPostEffectHandlerMap);
fmOPL4PostEffectHandlerMap.insert({
{0x1e, {DIV_CMD_OPL4_PCM_MIX_FM, _("1Exy: FM global level (left, right; 0 to 7)"), effectVal}},
{0x1f, {DIV_CMD_OPL4_PCM_MIX_PCM, _("1Fxy: PCM global level (left, right; 0 to 7)"), effectVal}},
{0x20, {DIV_CMD_OPL4_PCM_LFO, _("20xx: PCM LFO Rate (0 to 7)"), effectValAnd<7>}},
{0x21, {DIV_CMD_OPL4_PCM_VIB, _("21xx: PCM LFO PM Depth (0 to 7)"), effectValAnd<7>}},
{0x22, {DIV_CMD_OPL4_PCM_AM, _("22xx: PCM LFO AM Depth (0 to 7)"), effectValAnd<7>}},
{0x23, {DIV_CMD_OPL4_PCM_AR, _("23xx: PCM Attack Rate (0 to 15)"), effectValAnd<15>}},
{0x24, {DIV_CMD_OPL4_PCM_D1R, _("24xx: PCM Decay 1 Rate (0 to 15)"), effectValAnd<15>}},
{0x25, {DIV_CMD_OPL4_PCM_DL, _("25xx: PCM Decay Level (0 to 15)"), effectValAnd<15>}},
{0x26, {DIV_CMD_OPL4_PCM_D2R, _("26xx: PCM Decay 2 Rate (0 to 15)"), effectValAnd<15>}},
{0x27, {DIV_CMD_OPL4_PCM_RC, _("27xx: PCM Release Rate (0 to 15)"), effectValAnd<15>}},
{0x28, {DIV_CMD_OPL4_PCM_RR, _("28xx: PCM Rate Correction (0 to 15)"), effectValAnd<15>}},
{0x2c, {DIV_CMD_OPL4_PCM_DAMP, _("2Cxx: PCM Damp"), effectValAnd<1>}},
{0x2d, {DIV_CMD_OPL4_PCM_PSEUDO_REVERB, _("2Dxx: PCM Pseudo Reverb"), effectValAnd<1>}},
{0x2e, {DIV_CMD_OPL4_PCM_LFO_RESET, _("2Exx: PCM LFO Reset"), effectValAnd<1>}},
{0x2f, {DIV_CMD_OPL4_PCM_LEVEL_DIRECT, _("2Fxx: PCM Level Direct"), effectValAnd<1>}},
});
EffectHandlerMap c64PostEffectHandlerMap={
{0x10, {DIV_CMD_WAVE, _("10xx: Set waveform (bit 0: triangle; bit 1: saw; bit 2: pulse; bit 3: noise)")}},
{0x11, {DIV_CMD_C64_CUTOFF, _("11xx: Set coarse cutoff (not recommended; use 4xxx instead)")}},
@ -1616,28 +1635,28 @@ void DivEngine::registerSystems() {
// to Grauw: feel free to change this to 24 during development of OPL4's PCM part.
// TODO: add 12-bit and 16-bit big-endian sample formats
sysDefs[DIV_SYSTEM_OPL4]=new DivSysDef(
_("Yamaha YMF278B (OPL4)"), NULL, 0xae, 0, 42, true, true, 0, false, (1U<<DIV_SAMPLE_DEPTH_8BIT)|(1U<<DIV_SAMPLE_DEPTH_16BIT), 0, 0,
_("Yamaha YMF278B (OPL4)"), NULL, 0xae, 0, 42, true, true, 0x151, false, (1U<<DIV_SAMPLE_DEPTH_8BIT)|(1U<<DIV_SAMPLE_DEPTH_16BIT), 0, 0,
_("like OPL3, but this time it also has a 24-channel version of MultiPCM."),
{_("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"},
{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_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM},
{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
fmOPL4PostEffectHandlerMap
);
// TODO: same here
sysDefs[DIV_SYSTEM_OPL4_DRUMS]=new DivSysDef(
_("Yamaha YMF278B (OPL4) with drums"), NULL, 0xaf, 0, 44, true, true, 0, false, (1U<<DIV_SAMPLE_DEPTH_8BIT)|(1U<<DIV_SAMPLE_DEPTH_16BIT), 0, 0,
_("Yamaha YMF278B (OPL4) with drums"), NULL, 0xaf, 0, 44, true, true, 0x151, false, (1U<<DIV_SAMPLE_DEPTH_8BIT)|(1U<<DIV_SAMPLE_DEPTH_16BIT), 0, 0,
_("the OPL4 but with drums mode turned on."),
{_("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"},
{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_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM, DIV_INS_OPL4PCM},
{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
fmOPL4PostEffectHandlerMap
);
EffectHandlerMap es5506PreEffectHandlerMap={

View file

@ -1043,7 +1043,8 @@ void FurnaceGUI::doAction(int what) {
i==DIV_INS_K053260 ||
i==DIV_INS_C140 ||
i==DIV_INS_C219 ||
i==DIV_INS_NDS) {
i==DIV_INS_NDS ||
i==DIV_INS_OPL4PCM) {
makeInsTypeList.push_back(i);
}
}
@ -1572,7 +1573,8 @@ void FurnaceGUI::doAction(int what) {
i==DIV_INS_C219 ||
i==DIV_INS_NDS ||
i==DIV_INS_GBA_DMA ||
i==DIV_INS_GBA_MINMOD) {
i==DIV_INS_GBA_MINMOD ||
i==DIV_INS_OPL4PCM) {
makeInsTypeList.push_back(i);
}
}

View file

@ -351,6 +351,7 @@ enum FurnaceGUIColors {
GUI_COLOR_INSTR_GBA_MINMOD,
GUI_COLOR_INSTR_BIFURCATOR,
GUI_COLOR_INSTR_SID2,
GUI_COLOR_INSTR_OPL4PCM,
GUI_COLOR_INSTR_UNKNOWN,
GUI_COLOR_CHANNEL_BG,

View file

@ -184,6 +184,7 @@ const char* insTypes[DIV_INS_MAX+1][3]={
{"GBA MinMod",ICON_FA_VOLUME_UP,ICON_FUR_INS_GBA_MINMOD},
{"Bifurcator",ICON_FA_LINE_CHART,ICON_FUR_INS_BIFURCATOR},
{"SID2",ICON_FA_KEYBOARD_O,ICON_FUR_INS_SID2},
{"OPL4 PCM",ICON_FA_KEYBOARD_O,ICON_FUR_INS_SID2},
{NULL,ICON_FA_QUESTION,ICON_FA_QUESTION}
};
@ -1012,6 +1013,7 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={
D(GUI_COLOR_INSTR_GBA_MINMOD,"",ImVec4(0.5f,0.45f,0.7f,1.0f)),
D(GUI_COLOR_INSTR_BIFURCATOR,"",ImVec4(0.8925f,0.8925f,0.8925f,1.0f)),
D(GUI_COLOR_INSTR_SID2,"",ImVec4(0.6f,0.75f,1.0f,1.0f)),
D(GUI_COLOR_INSTR_OPL4PCM,"",ImVec4(1.0f,0.8f,0.1f,1.0f)),
D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)),
D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)),

View file

@ -6205,7 +6205,8 @@ void FurnaceGUI::drawInsEdit() {
ins->type==DIV_INS_C219 ||
ins->type==DIV_INS_NDS ||
ins->type==DIV_INS_GBA_DMA ||
ins->type==DIV_INS_GBA_MINMOD) {
ins->type==DIV_INS_GBA_MINMOD ||
ins->type==DIV_INS_OPL4PCM) {
insTabSample(ins);
}
if (ins->type==DIV_INS_N163) if (ImGui::BeginTabItem("Namco 163")) {
@ -6437,8 +6438,8 @@ void FurnaceGUI::drawInsEdit() {
}
ImGui::EndTabItem();
}
if (ins->type==DIV_INS_MULTIPCM) {
if (ImGui::BeginTabItem("MultiPCM")) {
if (ins->type==DIV_INS_MULTIPCM || ins->type==DIV_INS_OPL4PCM) {
if (ImGui::BeginTabItem(ins->type==DIV_INS_OPL4PCM?"OPL4 PCM":"MultiPCM")) {
ImVec2 sliderSize=ImVec2(20.0f*dpiScale,128.0*dpiScale);
if (ImGui::BeginTable("MultiPCMADSRParams",7,ImGuiTableFlags_NoHostExtendX)) {
ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,sliderSize.x);
@ -6519,6 +6520,12 @@ void FurnaceGUI::drawInsEdit() {
P(CWSliderScalar(_("AM Depth"),ImGuiDataType_U8,&ins->multipcm.am,&_ZERO,&_SEVEN)); rightClickable
ImGui::EndTable();
}
if (ins->type==DIV_INS_OPL4PCM) {
P(ImGui::Checkbox(_("Damp"),&ins->opl4pcm.damp));
P(ImGui::Checkbox(_("Pseudo Reverb"),&ins->opl4pcm.pseudoReverb));
P(ImGui::Checkbox(_("Level Direct"),&ins->opl4pcm.levelDirect));
P(ImGui::Checkbox(_("LFO Reset"),&ins->opl4pcm.lfoReset));
}
ImGui::EndTabItem();
}
}
@ -7503,6 +7510,22 @@ void FurnaceGUI::drawInsEdit() {
macroList.push_back(FurnaceGUIMacroDesc(_("Noise Mode"),&ins->std.fmsMacro,0,3,64,uiColors[GUI_COLOR_MACRO_NOISE]));
macroList.push_back(FurnaceGUIMacroDesc(_("Wave Mix"),&ins->std.amsMacro,0,3,64,uiColors[GUI_COLOR_MACRO_OTHER]));
break;
case DIV_INS_OPL4PCM:
macroList.push_back(FurnaceGUIMacroDesc(_("Volume"),&ins->std.volMacro,0,127,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
macroList.push_back(FurnaceGUIMacroDesc(_("Arpeggio"),&ins->std.arpMacro,-120,120,160,uiColors[GUI_COLOR_MACRO_PITCH],true,NULL,macroHoverNote,false,NULL,true,ins->std.arpMacro.val));
macroList.push_back(FurnaceGUIMacroDesc(_("Panning"),&ins->std.panLMacro,-7,7,45,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL));
macroList.push_back(FurnaceGUIMacroDesc(_("Pitch"),&ins->std.pitchMacro,-2048,2047,160,uiColors[GUI_COLOR_MACRO_PITCH],true,macroRelativeMode));
macroList.push_back(FurnaceGUIMacroDesc(_("Phase Reset"),&ins->std.phaseResetMacro,0,1,32,uiColors[GUI_COLOR_MACRO_OTHER],false,NULL,NULL,true));
macroList.push_back(FurnaceGUIMacroDesc(_("LFO speed"),&ins->std.ex1Macro,0,7,160,uiColors[GUI_COLOR_MACRO_OTHER]));
macroList.push_back(FurnaceGUIMacroDesc(_("LFO vibrato depth"),&ins->std.fmsMacro,0,7,160,uiColors[GUI_COLOR_MACRO_PITCH]));
macroList.push_back(FurnaceGUIMacroDesc(_("LFO AM depth"),&ins->std.amsMacro,0,7,160,uiColors[GUI_COLOR_MACRO_VOLUME]));
macroList.push_back(FurnaceGUIMacroDesc(_("AR"),&ins->std.ex2Macro,0,15,160,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
macroList.push_back(FurnaceGUIMacroDesc(_("D1R"),&ins->std.ex3Macro,0,15,160,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
macroList.push_back(FurnaceGUIMacroDesc(_("DL"),&ins->std.ex4Macro,0,15,160,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
macroList.push_back(FurnaceGUIMacroDesc(_("D2R"),&ins->std.ex5Macro,0,15,160,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
macroList.push_back(FurnaceGUIMacroDesc(_("Rate correction"),&ins->std.ex6Macro,0,15,160,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
macroList.push_back(FurnaceGUIMacroDesc(_("RR"),&ins->std.ex7Macro,0,15,160,uiColors[GUI_COLOR_MACRO_ENVELOPE]));
break;
case DIV_INS_MAX:
case DIV_INS_NULL:

View file

@ -4107,6 +4107,7 @@ void FurnaceGUI::drawSettings() {
UI_COLOR_CONFIG(GUI_COLOR_INSTR_GBA_MINMOD,_("GBA MinMod"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_BIFURCATOR,_("Bifurcator"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_SID2,_("SID2"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPL4PCM,_("OPL4 PCM"));
UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,_("Other/Unknown"));
ImGui::TreePop();
}