Implementing pattern effects, detune on FM preview, default instrument
This commit is contained in:
parent
821b567b8c
commit
a1b7e52467
|
@ -240,6 +240,11 @@ enum DivDispatchCmds {
|
|||
|
||||
DIV_ALWAYS_SET_VOLUME, // () -> alwaysSetVol
|
||||
|
||||
DIV_CMD_ESFM_OP_PANNING, // (op, value)
|
||||
DIV_CMD_ESFM_OUTLVL, // (op, value)
|
||||
DIV_CMD_ESFM_MODIN, // (op, value)
|
||||
DIV_CMD_ESFM_ENV_DELAY, // (op, value)
|
||||
|
||||
DIV_CMD_MAX
|
||||
};
|
||||
|
||||
|
|
|
@ -85,7 +85,6 @@ enum DivInstrumentType: unsigned short {
|
|||
DIV_INS_TED=52,
|
||||
DIV_INS_C140=53,
|
||||
DIV_INS_C219=54,
|
||||
// TODO: Ask tilde to standardize this!!!
|
||||
DIV_INS_ESFM=55,
|
||||
DIV_INS_MAX,
|
||||
DIV_INS_NULL
|
||||
|
|
|
@ -230,6 +230,7 @@ void DivPlatformESFM::tick(bool sysTick) {
|
|||
}
|
||||
}
|
||||
|
||||
// detune/fixed pitch
|
||||
if (opE.fixed) {
|
||||
if (m.ssg.had) {
|
||||
opE.ct=(opE.ct&(~(7<<2)))|((m.ssg.val&7)<<2);
|
||||
|
@ -351,44 +352,21 @@ void DivPlatformESFM::tick(bool sysTick) {
|
|||
}
|
||||
|
||||
int DivPlatformESFM::octave(int freq) {
|
||||
if (freq>=0x3ff<<6) {
|
||||
return 1<<7;
|
||||
} else if (freq>=0x3ff<<5) {
|
||||
return 1<<6;
|
||||
} else if (freq>=0x3ff<<4) {
|
||||
return 1<<5;
|
||||
} else if (freq>=0x3ff<<3) {
|
||||
return 1<<4;
|
||||
} else if (freq>=0x3ff<<2) {
|
||||
return 1<<3;
|
||||
} else if (freq>=0x3ff<<1) {
|
||||
return 1<<2;
|
||||
} else if (freq>=0x3ff) {
|
||||
return 1<<1;
|
||||
} else {
|
||||
return 1<<0;
|
||||
int result=1;
|
||||
while (freq>0x3ff) {
|
||||
freq>>=1;
|
||||
result<<=1;
|
||||
}
|
||||
return 1<<0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int DivPlatformESFM::toFreq(int freq) {
|
||||
if (freq>=0x3ff<<6) {
|
||||
return 0x1c00|((freq>>7)&0x3ff);
|
||||
} else if (freq>=0x3ff<<5) {
|
||||
return 0x1800|((freq>>6)&0x3ff);
|
||||
} else if (freq>=0x3ff<<4) {
|
||||
return 0x1400|((freq>>5)&0x3ff);
|
||||
} else if (freq>=0x3ff<<3) {
|
||||
return 0x1000|((freq>>4)&0x3ff);
|
||||
} else if (freq>=0x3ff<<2) {
|
||||
return 0xc00|((freq>>3)&0x3ff);
|
||||
} else if (freq>=0x3ff<<1) {
|
||||
return 0x800|((freq>>2)&0x3ff);
|
||||
} else if (freq>=0x3ff<<0) {
|
||||
return 0x400|((freq>>1)&0x3ff);
|
||||
} else {
|
||||
return freq&0x3ff;
|
||||
int block=0;
|
||||
while (freq>0x3ff) {
|
||||
freq>>=1;
|
||||
block++;
|
||||
}
|
||||
return ((block&7)<<10)|(freq&0x3ff);
|
||||
}
|
||||
|
||||
void DivPlatformESFM::muteChannel(int ch, bool mute) {
|
||||
|
@ -510,7 +488,6 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
DivInstrumentESFM::Operator& opE=chan[c.chan].state.esfm.op[o];
|
||||
|
||||
rWrite(baseAddr+OFFSET_DAM_DVB_LEFT_RIGHT_MODIN,((opE.modIn&7)<<1)|(((opE.left&chan[c.chan].globalPan)&1)<<4)|(((opE.right&(chan[c.chan].globalPan>>1))&1)<<5)|((op.dvb&1)<<6)|(op.dam<<7));
|
||||
}
|
||||
break;
|
||||
|
@ -585,7 +562,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
if (c.value<0) {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
|
@ -603,7 +580,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.value<0) {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
|
@ -621,7 +598,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.value<0) {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
|
@ -639,7 +616,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.value<0) {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
|
@ -657,7 +634,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.value<0) {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
|
@ -675,7 +652,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_VIB: {
|
||||
if (c.value<0) {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
|
@ -693,7 +670,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SUS: {
|
||||
if (c.value<0) {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
|
@ -711,7 +688,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_KSR: {
|
||||
if (c.value<0) {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
|
@ -729,7 +706,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_WS: {
|
||||
if (c.value<0) {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
|
@ -760,7 +737,7 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
}
|
||||
// KSL
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.value<0) {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
|
@ -785,6 +762,134 @@ int DivPlatformESFM::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM_DEPTH: {
|
||||
unsigned int o = c.value;
|
||||
if (o >= 4) break;
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
DivInstrumentESFM::Operator& opE=chan[c.chan].state.esfm.op[o];
|
||||
op.dam=c.value2&1;
|
||||
rWrite(baseAddr+OFFSET_DAM_DVB_LEFT_RIGHT_MODIN,((opE.modIn&7)<<1)|(((opE.left&chan[c.chan].globalPan)&1)<<4)|(((opE.right&(chan[c.chan].globalPan>>1))&1)<<5)|((op.dvb&1)<<6)|(op.dam<<7));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_PM_DEPTH: {
|
||||
unsigned int o = c.value;
|
||||
if (o >= 4) break;
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
DivInstrumentESFM::Operator& opE=chan[c.chan].state.esfm.op[o];
|
||||
op.dvb=c.value2&1;
|
||||
rWrite(baseAddr+OFFSET_DAM_DVB_LEFT_RIGHT_MODIN,((opE.modIn&7)<<1)|(((opE.left&chan[c.chan].globalPan)&1)<<4)|(((opE.right&(chan[c.chan].globalPan>>1))&1)<<5)|((op.dvb&1)<<6)|(op.dam<<7));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FIXFREQ: {
|
||||
unsigned int o=c.value&3;
|
||||
bool isFNum=c.value&4;
|
||||
DivInstrumentESFM::Operator& opE=chan[c.chan].state.esfm.op[o];
|
||||
if (!opE.fixed) break;
|
||||
if (isFNum) {
|
||||
opE.dt=(c.value2)&0xff;
|
||||
opE.ct=(opE.ct&(~3))|((c.value2>>8)&3);
|
||||
chan[c.chan].freqChanged=true;
|
||||
} else {
|
||||
opE.ct=(opE.ct&(~(7<<2)))|((c.value2&7)<<2);
|
||||
chan[c.chan].freqChanged=true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_ESFM_OP_PANNING: {
|
||||
unsigned int o=c.value;
|
||||
if (o >= 4) break;
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
DivInstrumentESFM::Operator& opE=chan[c.chan].state.esfm.op[o];
|
||||
opE.left=c.value2&1;
|
||||
opE.right=(c.value2&2)>>1;
|
||||
rWrite(baseAddr+OFFSET_DAM_DVB_LEFT_RIGHT_MODIN,((opE.modIn&7)<<1)|(((opE.left&chan[c.chan].globalPan)&1)<<4)|(((opE.right&(chan[c.chan].globalPan>>1))&1)<<5)|((op.dvb&1)<<6)|(op.dam<<7));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_ESFM_OUTLVL: {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
DivInstrumentESFM::Operator& opE=chan[c.chan].state.esfm.op[o];
|
||||
unsigned char noise=chan[c.chan].state.esfm.noise&3;
|
||||
opE.outLvl=c.value2&7;
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(baseAddr+OFFSET_OUTLVL_NOISE_WS,(op.ws&7)|((o==3?noise:0)<<3)|0);
|
||||
} else {
|
||||
rWrite(baseAddr+OFFSET_OUTLVL_NOISE_WS,(op.ws&7)|((o==3?noise:0)<<3)|((opE.outLvl&7)<<5));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsigned int o = c.value;
|
||||
if (o >= 4) break;
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
DivInstrumentESFM::Operator& opE=chan[c.chan].state.esfm.op[o];
|
||||
unsigned char noise=chan[c.chan].state.esfm.noise&3;
|
||||
opE.outLvl=c.value2&7;
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(baseAddr+OFFSET_OUTLVL_NOISE_WS,(op.ws&7)|((o==3?noise:0)<<3)|0);
|
||||
} else {
|
||||
rWrite(baseAddr+OFFSET_OUTLVL_NOISE_WS,(op.ws&7)|((o==3?noise:0)<<3)|((opE.outLvl&7)<<5));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_ESFM_MODIN: {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
DivInstrumentESFM::Operator& opE=chan[c.chan].state.esfm.op[o];
|
||||
opE.modIn=c.value2&7;
|
||||
rWrite(baseAddr+OFFSET_DAM_DVB_LEFT_RIGHT_MODIN,((opE.modIn&7)<<1)|(((opE.left&chan[c.chan].globalPan)&1)<<4)|(((opE.right&(chan[c.chan].globalPan>>1))&1)<<5)|((op.dvb&1)<<6)|(op.dam<<7));
|
||||
}
|
||||
} else {
|
||||
unsigned int o = c.value;
|
||||
if (o >= 4) break;
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
DivInstrumentESFM::Operator& opE=chan[c.chan].state.esfm.op[o];
|
||||
opE.modIn=c.value2&7;
|
||||
rWrite(baseAddr+OFFSET_DAM_DVB_LEFT_RIGHT_MODIN,((opE.modIn&7)<<1)|(((opE.left&chan[c.chan].globalPan)&1)<<4)|(((opE.right&(chan[c.chan].globalPan>>1))&1)<<5)|((op.dvb&1)<<6)|(op.dam<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_ESFM_ENV_DELAY: {
|
||||
if (c.value<0) {
|
||||
for (int o=0; o<4; o++) {
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentESFM::Operator& opE=chan[c.chan].state.esfm.op[o];
|
||||
opE.delay=c.value2&7;
|
||||
rWrite(baseAddr+OFFSET_FREQH_BLOCK_DELAY,chan[c.chan].freqH[o]|(opE.delay<<5));
|
||||
}
|
||||
} else {
|
||||
unsigned int o = c.value;
|
||||
if (o >= 4) break;
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentESFM::Operator& opE=chan[c.chan].state.esfm.op[o];
|
||||
opE.delay=c.value2&7;
|
||||
rWrite(baseAddr+OFFSET_FREQH_BLOCK_DELAY,chan[c.chan].freqH[o]|(opE.delay<<5));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_STD_NOISE_MODE: {
|
||||
unsigned int o=3;
|
||||
unsigned short baseAddr=c.chan*32 + o*8;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.fm.op[o];
|
||||
DivInstrumentESFM::Operator& opE=chan[c.chan].state.esfm.op[o];
|
||||
DivInstrumentESFM insE=chan[c.chan].state.esfm;
|
||||
insE.noise=c.value&3;
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(baseAddr+OFFSET_OUTLVL_NOISE_WS,(op.ws&7)|(insE.noise<<3)|0);
|
||||
} else {
|
||||
rWrite(baseAddr+OFFSET_OUTLVL_NOISE_WS,(op.ws&7)|(insE.noise<<3)|((opE.outLvl&7)<<5));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
chan[c.chan].hardReset=c.value;
|
||||
break;
|
||||
|
@ -843,10 +948,10 @@ DivDispatchOscBuffer* DivPlatformESFM::getOscBuffer(int ch) {
|
|||
}
|
||||
|
||||
unsigned char* DivPlatformESFM::getRegisterPool() {
|
||||
// TODO: DEBUG, remove this, it impacts performance
|
||||
for (int i=0; i<ESFM_REG_POOL_SIZE; i++) {
|
||||
regPool[i] = ESFM_readback_reg(&chip, i);
|
||||
}
|
||||
// // Uncomment this for debugging weird behavior
|
||||
// for (int i=0; i<ESFM_REG_POOL_SIZE; i++) {
|
||||
// regPool[i]=ESFM_readback_reg(&chip, i);
|
||||
// }
|
||||
return regPool;
|
||||
}
|
||||
|
||||
|
|
|
@ -239,7 +239,12 @@ const char* cmdName[]={
|
|||
|
||||
"EXTERNAL",
|
||||
|
||||
"ALWAYS_SET_VOLUME"
|
||||
"ALWAYS_SET_VOLUME",
|
||||
|
||||
"DIV_CMD_ESFM_OP_PANNING",
|
||||
"DIV_CMD_ESFM_OUTLVL",
|
||||
"DIV_CMD_ESFM_MODIN",
|
||||
"DIV_CMD_ESFM_ENV_DELAY"
|
||||
};
|
||||
|
||||
static_assert((sizeof(cmdName)/sizeof(void*))==DIV_CMD_MAX,"update cmdName!");
|
||||
|
|
|
@ -132,8 +132,7 @@ enum DivSystem {
|
|||
DIV_SYSTEM_TED,
|
||||
DIV_SYSTEM_C140,
|
||||
DIV_SYSTEM_C219,
|
||||
// TODO: Ask Tilde to standardize!
|
||||
DIV_SYSTEM_ESFM,
|
||||
DIV_SYSTEM_ESFM
|
||||
};
|
||||
|
||||
enum DivEffectType: unsigned short {
|
||||
|
@ -606,38 +605,42 @@ struct DivSong {
|
|||
|
||||
nullInsQSound.std.panLMacro.mode=true;
|
||||
|
||||
// ESFM default instrument - port of OPM default instrument?
|
||||
// TODO: adjust these values so they actually match
|
||||
// ESFM default instrument - port of OPN default instrument
|
||||
nullInsESFM.esfm.noise=0;
|
||||
nullInsESFM.esfm.op[0].outLvl=0;
|
||||
nullInsESFM.esfm.op[0].modIn=4;
|
||||
nullInsESFM.fm.op[0].tl=21;
|
||||
nullInsESFM.esfm.op[0].dt=2;
|
||||
nullInsESFM.fm.op[0].tl=42;
|
||||
nullInsESFM.fm.op[0].ar=15;
|
||||
nullInsESFM.fm.op[0].dr=9;
|
||||
nullInsESFM.fm.op[0].sl=7;
|
||||
nullInsESFM.fm.op[0].dr=3;
|
||||
nullInsESFM.fm.op[0].sl=15;
|
||||
nullInsESFM.fm.op[0].rr=3;
|
||||
nullInsESFM.fm.op[0].mult=7;
|
||||
nullInsESFM.fm.op[0].mult=5;
|
||||
|
||||
nullInsESFM.esfm.op[1].outLvl=0;
|
||||
nullInsESFM.esfm.op[1].modIn=7;
|
||||
nullInsESFM.fm.op[1].tl=24;
|
||||
nullInsESFM.esfm.op[1].dt=-3;
|
||||
nullInsESFM.fm.op[1].tl=18;
|
||||
nullInsESFM.fm.op[1].ar=15;
|
||||
nullInsESFM.fm.op[1].dr=2;
|
||||
nullInsESFM.fm.op[1].sl=11;
|
||||
nullInsESFM.fm.op[1].rr=2;
|
||||
nullInsESFM.fm.op[1].dr=3;
|
||||
nullInsESFM.fm.op[1].sl=15;
|
||||
nullInsESFM.fm.op[1].rr=4;
|
||||
nullInsESFM.fm.op[1].mult=1;
|
||||
|
||||
nullInsESFM.esfm.op[2].outLvl=0;
|
||||
nullInsESFM.esfm.op[2].modIn=7;
|
||||
nullInsESFM.fm.op[2].tl=17;
|
||||
nullInsESFM.esfm.op[2].dt=2;
|
||||
nullInsESFM.fm.op[2].tl=48;
|
||||
nullInsESFM.fm.op[2].ar=15;
|
||||
nullInsESFM.fm.op[2].dr=4;
|
||||
nullInsESFM.fm.op[2].sl=15;
|
||||
nullInsESFM.fm.op[2].rr=3;
|
||||
nullInsESFM.fm.op[2].mult=2;
|
||||
nullInsESFM.fm.op[2].dr=2;
|
||||
nullInsESFM.fm.op[2].sl=11;
|
||||
nullInsESFM.fm.op[2].rr=1;
|
||||
nullInsESFM.fm.op[2].mult=1;
|
||||
nullInsESFM.fm.op[2].sus=1;
|
||||
|
||||
nullInsESFM.esfm.op[3].outLvl=7;
|
||||
nullInsESFM.esfm.op[3].modIn=7;
|
||||
nullInsESFM.esfm.op[3].dt=-3;
|
||||
nullInsESFM.fm.op[3].tl=0;
|
||||
nullInsESFM.fm.op[3].ar=15;
|
||||
nullInsESFM.fm.op[3].dr=3;
|
||||
|
|
|
@ -392,6 +392,10 @@ int negEffectVal(unsigned char, unsigned char val) {
|
|||
return -(int)val;
|
||||
};
|
||||
|
||||
int effectValNibbleFlagPackReversed(unsigned char, unsigned char val) {
|
||||
return (((val&0x0f)!=0)<<1)|((val&0xf0)!=0);
|
||||
}
|
||||
|
||||
template<const int mask> int effectValAnd(unsigned char, unsigned char val) {
|
||||
return val&mask;
|
||||
};
|
||||
|
@ -612,6 +616,52 @@ void DivEngine::registerSystems() {
|
|||
{0x20, {DIV_CMD_SAMPLE_FREQ, "20xx: Set PCM frequency"}}
|
||||
};
|
||||
|
||||
EffectHandlerMap fmESFMPostEffectHandlerMap={
|
||||
{0x12, {DIV_CMD_FM_TL, "12xx: Set level of operator 1 (0 highest, 3F lowest)", constVal<0>, effectVal}},
|
||||
{0x13, {DIV_CMD_FM_TL, "13xx: Set level of operator 2 (0 highest, 3F lowest)", constVal<1>, effectVal}},
|
||||
{0x14, {DIV_CMD_FM_TL, "14xx: Set level of operator 3 (0 highest, 3F lowest)", constVal<2>, effectVal}},
|
||||
{0x15, {DIV_CMD_FM_TL, "15xx: Set level of operator 4 (0 highest, 3F lowest)", constVal<3>, effectVal}},
|
||||
{0x16, {DIV_CMD_FM_MULT, "16xy: Set operator multiplier (x: operator from 1 to 4; y: multiplier)", effectOpValNoZero<4>, effectValAnd<15>}},
|
||||
{0x19, {DIV_CMD_FM_AR, "19xx: Set attack of all operators (0 to F)", constVal<-1>, effectValAnd<15>}},
|
||||
{0x1a, {DIV_CMD_FM_AR, "1Axx: Set attack of operator 1 (0 to F)", constVal<0>, effectValAnd<15>}},
|
||||
{0x1b, {DIV_CMD_FM_AR, "1Bxx: Set attack of operator 2 (0 to F)", constVal<1>, effectValAnd<15>}},
|
||||
{0x1c, {DIV_CMD_FM_AR, "1Cxx: Set attack of operator 3 (0 to F)", constVal<2>, effectValAnd<15>}},
|
||||
{0x1d, {DIV_CMD_FM_AR, "1Dxx: Set attack of operator 4 (0 to F)", constVal<3>, effectValAnd<15>}},
|
||||
{0x1e, {DIV_CMD_FM_AM_DEPTH, "1Exy: Set AM depth (x: operator from 1 to 4 (0 for all ops); y: depth (0: 1dB, 1: 4.8dB))", effectOpVal<4>, effectValAnd<1>}},
|
||||
{0x1f, {DIV_CMD_FM_PM_DEPTH, "1Fxy: Set vibrato depth (x: operator from 1 to 4 (0 for all ops); y: depth (0: normal, 1: double))", effectOpVal<4>, effectValAnd<1>}},
|
||||
{0x20, {DIV_CMD_ESFM_OP_PANNING, "20xy: Set panning of operator 1 (x: left; y: right)", constVal<0>, effectValNibbleFlagPackReversed}},
|
||||
{0x21, {DIV_CMD_ESFM_OP_PANNING, "21xy: Set panning of operator 2 (x: left; y: right)", constVal<1>, effectValNibbleFlagPackReversed}},
|
||||
{0x22, {DIV_CMD_ESFM_OP_PANNING, "22xy: Set panning of operator 3 (x: left; y: right)", constVal<2>, effectValNibbleFlagPackReversed}},
|
||||
{0x23, {DIV_CMD_ESFM_OP_PANNING, "23xy: Set panning of operator 4 (x: left; y: right)", constVal<3>, effectValNibbleFlagPackReversed}},
|
||||
{0x24, {DIV_CMD_ESFM_OUTLVL, "24xy: Set output level register (x: operator from 1 to 4 (0 for all ops); y: level from 0 to 7)", effectOpVal<4>, effectValAnd<7>}},
|
||||
{0x25, {DIV_CMD_ESFM_MODIN, "25xy: Set modulation input level (x: operator from 1 to 4 (0 for all ops); y: level from 0 to 7)", effectOpVal<4>, effectValAnd<7>}},
|
||||
{0x26, {DIV_CMD_ESFM_ENV_DELAY, "26xy: Set envelope delay (x: operator from 1 to 4 (0 for all ops); y: delay from 0 to 7)", effectOpVal<4>, effectValAnd<7>}},
|
||||
{0x27, {DIV_CMD_STD_NOISE_MODE, "27xx: Set noise mode for operator 4 (x: mode from 0 to 3)", effectValAnd<3>}},
|
||||
{0x2a, {DIV_CMD_FM_WS, "2Axy: Set waveform (x: operator from 1 to 4 (0 for all ops); y: waveform from 0 to 7)", effectOpVal<4>, effectValAnd<7>}},
|
||||
{0x2f, {DIV_CMD_FM_FIXFREQ, "2Fxy: Set fixed frequency block (x: operator from 1 to 4; y: octave from 0 to 7)", effectOpValNoZero<4>, effectValAnd<7>}},
|
||||
{0x50, {DIV_CMD_FM_AM, "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)", effectOpVal<4>, effectValAnd<1>}},
|
||||
{0x51, {DIV_CMD_FM_SL, "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)", effectOpVal<4>, effectValAnd<15>}},
|
||||
{0x52, {DIV_CMD_FM_RR, "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)", effectOpVal<4>, effectValAnd<15>}},
|
||||
{0x53, {DIV_CMD_FM_VIB, "53xy: Set vibrato (x: operator from 1 to 4 (0 for all ops); y: enabled)", effectOpVal<4>, effectValAnd<1>}},
|
||||
{0x54, {DIV_CMD_FM_RS, "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)", effectOpVal<4>, effectValAnd<3>}},
|
||||
{0x55, {DIV_CMD_FM_SUS, "55xy: Set envelope sustain (x: operator from 1 to 4 (0 for all ops); y: enabled)", effectOpVal<4>, effectValAnd<1>}},
|
||||
{0x56, {DIV_CMD_FM_DR, "56xx: Set decay of all operators (0 to F)", constVal<-1>, effectValAnd<15>}},
|
||||
{0x57, {DIV_CMD_FM_DR, "57xx: Set decay of operator 1 (0 to F)", constVal<0>, effectValAnd<15>}},
|
||||
{0x58, {DIV_CMD_FM_DR, "58xx: Set decay of operator 2 (0 to F)", constVal<1>, effectValAnd<15>}},
|
||||
{0x59, {DIV_CMD_FM_DR, "59xx: Set decay of operator 3 (0 to F)", constVal<2>, effectValAnd<15>}},
|
||||
{0x5a, {DIV_CMD_FM_DR, "5Axx: Set decay of operator 4 (0 to F)", constVal<3>, effectValAnd<15>}},
|
||||
{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>}}
|
||||
};
|
||||
const EffectHandler fmESFMFixFreqFNumHandler[4]={
|
||||
{DIV_CMD_FM_FIXFREQ, "3xyy: Set fixed frequency F-num of operator 1 (x: high 2 bits from 0 to 3; y: low 8 bits of F-num)", constVal<4>, effectValLong<10>},
|
||||
{DIV_CMD_FM_FIXFREQ, "3xyy: Set fixed frequency F-num of operator 2 (x: high 2 bits from 4 to 7; y: low 8 bits of F-num)", constVal<5>, effectValLong<10>},
|
||||
{DIV_CMD_FM_FIXFREQ, "3xyy: Set fixed frequency F-num of operator 3 (x: high 2 bits from 8 to B; y: low 8 bits of F-num)", constVal<6>, effectValLong<10>},
|
||||
{DIV_CMD_FM_FIXFREQ, "3xyy: Set fixed frequency F-num of operator 4 (x: high 2 bits from C to F; y: low 8 bits of F-num)", constVal<7>, effectValLong<10>},
|
||||
};
|
||||
for (int i=0; i<16; i++) {
|
||||
fmESFMPostEffectHandlerMap.emplace(0x30+i,fmESFMFixFreqFNumHandler[i/4]);
|
||||
}
|
||||
|
||||
// SysDefs
|
||||
|
||||
// this chip uses YMZ ADPCM, but the emulator uses ADPCM-B because I got it wrong back then.
|
||||
|
@ -1917,8 +1967,7 @@ void DivEngine::registerSystems() {
|
|||
{0x12, {DIV_CMD_SNES_INVERT, "12xy: Set invert mode (x: surround; y: invert)"}},
|
||||
}
|
||||
);
|
||||
|
||||
// TODO: ask Tilde to standardize!
|
||||
|
||||
sysDefs[DIV_SYSTEM_ESFM]=new DivSysDef(
|
||||
"ESS ES1xxx-series (ESFM)", NULL, 0xd0, 0, 18, true, false, 0, false, 0,
|
||||
"A unique FM synth featured in PC sound cards.\nBased on the OPL3 design, but with lots of its features extended.",
|
||||
|
@ -1927,7 +1976,10 @@ void DivEngine::registerSystems() {
|
|||
{DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM},
|
||||
{DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM, DIV_INS_ESFM},
|
||||
{},
|
||||
{}
|
||||
{
|
||||
{0x2e, {DIV_CMD_FM_HARD_RESET, "2Exx: Toggle hard envelope reset on new notes"}},
|
||||
},
|
||||
fmESFMPostEffectHandlerMap
|
||||
);
|
||||
|
||||
sysDefs[DIV_SYSTEM_DUMMY]=new DivSysDef(
|
||||
|
|
|
@ -366,15 +366,31 @@ void FurnaceGUI::renderFMPreviewESFM(const DivInstrumentFM& params, const DivIns
|
|||
const DivInstrumentFM::Operator& op=params.op[i];
|
||||
const DivInstrumentESFM::Operator& opE=esfmParams.op[i];
|
||||
unsigned short baseAddr=i*8;
|
||||
unsigned char freqL, freqH;
|
||||
if (opE.fixed) {
|
||||
freqL=opE.dt;
|
||||
freqH=opE.ct&0x1f;
|
||||
} else {
|
||||
// perform detune calculation
|
||||
int offset=(opE.ct<<7)+opE.dt;
|
||||
double fbase=(mult0?2048.0:1024.0)*pow(2.0,(float)offset/(128.0*12.0));
|
||||
int bf=round(fbase);
|
||||
int block=0;
|
||||
while (bf>0x3ff) {
|
||||
bf>>=1;
|
||||
block++;
|
||||
}
|
||||
freqL=bf&0xff;
|
||||
freqH=((block&7)<<2)|((bf>>8)&3);
|
||||
}
|
||||
|
||||
ESFM_WRITE(baseAddr+0,(op.am<<7)|((op.vib&1)<<6)|((op.sus&1)<<5)|((op.ksr&1)<<4)|(op.mult&0x0f));
|
||||
ESFM_WRITE(baseAddr+1,(op.ksl<<6)|(op.tl&0x3f));
|
||||
ESFM_WRITE(baseAddr+2,(op.ar<<4)|(op.dr&0x0f));
|
||||
ESFM_WRITE(baseAddr+3,(op.sl<<4)|(op.rr&0x0f));
|
||||
|
||||
// TODO: implement ct/dt detune... how will we do that?
|
||||
ESFM_WRITE(baseAddr+4,0);
|
||||
ESFM_WRITE(baseAddr+5,(opE.delay<<5)|(mult0?0x0a:0x06));
|
||||
ESFM_WRITE(baseAddr+4,freqL);
|
||||
ESFM_WRITE(baseAddr+5,(opE.delay<<5)|freqH);
|
||||
|
||||
ESFM_WRITE(baseAddr+6,(op.dam<<7)|((op.dvb&1)<<6)|((opE.right&1)<<5)|((opE.left&1)<<4)|((opE.modIn&7)<<1));
|
||||
ESFM_WRITE(baseAddr+7,(opE.outLvl<<5)|((i==3?esfmParams.noise:0)<<3)|(op.ws&7));
|
||||
|
|
Loading…
Reference in a new issue