Merge branch 'master' of https://github.com/tildearrow/furnace into ay_divider
* 'master' of https://github.com/tildearrow/furnace: dev92 - GUI: customizable channel collapsing! GUI: more improvements to instrument loading GUI: implement instrument load replace NES: fix duty effect not working at all GUI: part 2 of previous commit GUI: only use edit color when pat view is focused GUI: fix more issues here's the new OPLL default instrument OPL: fix channel muting - PLEASE READ! OPLL: fix compatible drum mode the final part of extra FM effects implement extra FM effects (OPLL and OPL) update to-do list prepare for possible .ftm import implement extra FM effects (OPN, OPM and OPZ) # Conflicts: # src/engine/engine.h
This commit is contained in:
commit
9109d2c64f
38 changed files with 4244 additions and 97 deletions
|
|
@ -45,8 +45,8 @@
|
|||
#define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock();
|
||||
#define BUSY_END isBusy.unlock(); softLocked=false;
|
||||
|
||||
#define DIV_VERSION "devff" // it breaks compatiblity
|
||||
#define DIV_ENGINE_VERSION 0xff
|
||||
#define DIV_VERSION "dev92" // it breaks compatiblity
|
||||
#define DIV_ENGINE_VERSION 92
|
||||
|
||||
// for imports
|
||||
#define DIV_VERSION_MOD 0xff01
|
||||
|
|
@ -383,6 +383,7 @@ class DivEngine {
|
|||
bool loadDMF(unsigned char* file, size_t len);
|
||||
bool loadFur(unsigned char* file, size_t len);
|
||||
bool loadMod(unsigned char* file, size_t len);
|
||||
bool loadFTM(unsigned char* file, size_t len);
|
||||
|
||||
void loadDMP(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
|
||||
void loadTFI(SafeReader& reader, std::vector<DivInstrument*>& ret, String& stripPath);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#define DIV_READ_SIZE 131072
|
||||
#define DIV_DMF_MAGIC ".DelekDefleMask."
|
||||
#define DIV_FUR_MAGIC "-Furnace module-"
|
||||
#define DIV_FTM_MAGIC "FamiTracker Module"
|
||||
|
||||
struct InflateBlock {
|
||||
unsigned char* buf;
|
||||
|
|
@ -1314,6 +1315,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
ds.chanCollapse[i]=reader.readC();
|
||||
}
|
||||
|
||||
if (ds.version<92) {
|
||||
for (int i=0; i<tchans; i++) {
|
||||
if (ds.chanCollapse[i]>0) ds.chanCollapse[i]=3;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0; i<tchans; i++) {
|
||||
ds.chanName[i]=reader.readString();
|
||||
}
|
||||
|
|
@ -1617,8 +1624,6 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
||||
struct InvalidHeaderException {};
|
||||
bool success=false;
|
||||
|
|
@ -2029,10 +2034,43 @@ bool DivEngine::loadMod(unsigned char* file, size_t len) {
|
|||
return success;
|
||||
}
|
||||
|
||||
bool DivEngine::loadFTM(unsigned char* file, size_t len) {
|
||||
SafeReader reader=SafeReader(file,len);
|
||||
warnings="";
|
||||
try {
|
||||
DivSong ds;
|
||||
|
||||
if (!reader.seek(18,SEEK_SET)) {
|
||||
logE("premature end of file!");
|
||||
lastError="incomplete file";
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
ds.version=(unsigned short)reader.readS();
|
||||
logI("module version %d (0x%.4x)",ds.version,ds.version);
|
||||
|
||||
if (ds.version>0x0440) {
|
||||
logE("incompatible version %x!",ds.version);
|
||||
lastError="incompatible version";
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} catch (EndOfFileException& e) {
|
||||
logE("premature end of file!");
|
||||
lastError="incomplete file";
|
||||
delete[] file;
|
||||
return false;
|
||||
}
|
||||
delete[] file;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DivEngine::load(unsigned char* f, size_t slen) {
|
||||
unsigned char* file;
|
||||
size_t len;
|
||||
if (slen<16) {
|
||||
if (slen<18) {
|
||||
logE("too small!");
|
||||
lastError="file is too small";
|
||||
delete[] f;
|
||||
|
|
@ -2137,6 +2175,8 @@ bool DivEngine::load(unsigned char* f, size_t slen) {
|
|||
// step 2: try loading as .fur or .dmf
|
||||
if (memcmp(file,DIV_DMF_MAGIC,16)==0) {
|
||||
return loadDMF(file,len);
|
||||
} else if (memcmp(file,DIV_FTM_MAGIC,18)==0) {
|
||||
return loadFTM(file,len);
|
||||
} else if (memcmp(file,DIV_FUR_MAGIC,16)==0) {
|
||||
return loadFur(file,len);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,6 +135,54 @@ const char* DivPlatformArcade::getEffectName(unsigned char effect) {
|
|||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set detune 2 (x: operator from 1 to 4 (0 for all ops); y: detune from 0 to 3)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxx: Set decay 2 of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x5c:
|
||||
return "5Cxx: Set decay 2 of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x5d:
|
||||
return "5Dxx: Set decay 2 of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x5e:
|
||||
return "5Exx: Set decay 2 of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -650,6 +698,134 @@ int DivPlatformArcade::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DT2: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.dt2=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.dt2=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_D2R: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DT: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.dt=c.value&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.dt=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM_DEPTH: {
|
||||
amDepth=c.value;
|
||||
immWrite(0x19,amDepth);
|
||||
|
|
|
|||
|
|
@ -77,6 +77,54 @@ const char* DivPlatformGenesis::getEffectName(unsigned char effect) {
|
|||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxx: Set decay 2 of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x5c:
|
||||
return "5Cxx: Set decay 2 of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x5d:
|
||||
return "5Dxx: Set decay 2 of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x5e:
|
||||
return "5Exx: Set decay 2 of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -780,7 +828,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else {
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.ar=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
|
|
@ -788,6 +836,134 @@ int DivPlatformGenesis::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_D2R: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DT: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.dt=c.value&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.dt=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SSG: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
chan[c.chan].hardReset=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -235,6 +235,134 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_D2R: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DT: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.dt=c.value&7;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.dt=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SSG: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_GET_VOLMAX:
|
||||
return 127;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -304,6 +304,7 @@ int DivPlatformMMC5::dispatch(DivCommand c) {
|
|||
}
|
||||
case DIV_CMD_STD_NOISE_MODE:
|
||||
chan[c.chan].duty=c.value;
|
||||
rWrite(0x5000+c.chan*4,0x30|chan[c.chan].outVol|((chan[c.chan].duty&3)<<6));
|
||||
break;
|
||||
case DIV_CMD_SAMPLE_BANK:
|
||||
sampleBank=c.value;
|
||||
|
|
|
|||
|
|
@ -520,6 +520,8 @@ int DivPlatformNES::dispatch(DivCommand c) {
|
|||
chan[c.chan].duty=c.value;
|
||||
if (c.chan==3) { // noise
|
||||
chan[c.chan].freqChanged=true;
|
||||
} else if (c.chan<2) {
|
||||
rWrite(0x4000+c.chan*4,0x30|chan[c.chan].outVol|((chan[c.chan].duty&3)<<6));
|
||||
}
|
||||
break;
|
||||
case DIV_CMD_NES_SWEEP:
|
||||
|
|
|
|||
|
|
@ -197,6 +197,48 @@ const char* DivPlatformOPL::getEffectName(unsigned char effect) {
|
|||
case 0x1d:
|
||||
return "1Dxx: Set attack of operator 4 (0 to F; 4-op only)";
|
||||
break;
|
||||
case 0x2a:
|
||||
return "2Axy: Set waveform (x: operator from 1 to 4 (0 for all ops); y: waveform from 0 to 3 in OPL2 and 0 to 7 in OPL3)";
|
||||
break;
|
||||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set vibrato (x: operator from 1 to 4 (0 for all ops); y: enabled)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set key scale level (x: operator from 1 to 4 (0 for all ops); y: level from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set envelope sustain (x: operator from 1 to 4 (0 for all ops); y: enabled)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to F; 4-op only)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to F; 4-op only)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxy: Set whether key will scale envelope (x: operator from 1 to 4 (0 for all ops); y: enabled)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -522,6 +564,9 @@ int DivPlatformOPL::toFreq(int freq) {
|
|||
|
||||
void DivPlatformOPL::muteChannel(int ch, bool mute) {
|
||||
isMuted[ch]=mute;
|
||||
if (ch<melodicChans) {
|
||||
fm.channel[outChanMap[ch]].muted=mute;
|
||||
}
|
||||
int ops=(slots[3][ch]!=255 && chan[ch].state.ops==4 && oplType==3)?4:2;
|
||||
chan[ch].fourOp=(ops==4);
|
||||
update4OpMask=true;
|
||||
|
|
@ -841,6 +886,222 @@ int DivPlatformOPL::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][c.chan];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
op.dr=c.value2&15;
|
||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||
}
|
||||
} else {
|
||||
if (c.value>=ops) break;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
||||
op.dr=c.value2&15;
|
||||
unsigned char slot=slots[c.value][c.chan];
|
||||
if (slot==255) break;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
rWrite(baseAddr+ADDR_AR_DR,(op.ar<<4)|op.dr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][c.chan];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
op.sl=c.value2&15;
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
}
|
||||
} else {
|
||||
if (c.value>=ops) break;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
||||
op.sl=c.value2&15;
|
||||
unsigned char slot=slots[c.value][c.chan];
|
||||
if (slot==255) break;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][c.chan];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
op.rr=c.value2&15;
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
}
|
||||
} else {
|
||||
if (c.value>=ops) break;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
||||
op.rr=c.value2&15;
|
||||
unsigned char slot=slots[c.value][c.chan];
|
||||
if (slot==255) break;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.sl<<4)|op.rr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][c.chan];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
op.am=c.value2&1;
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
} else {
|
||||
if (c.value>=ops) break;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
||||
op.am=c.value2&1;
|
||||
unsigned char slot=slots[c.value][c.chan];
|
||||
if (slot==255) break;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_VIB: {
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][c.chan];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
op.vib=c.value2&1;
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
} else {
|
||||
if (c.value>=ops) break;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
||||
op.vib=c.value2&1;
|
||||
unsigned char slot=slots[c.value][c.chan];
|
||||
if (slot==255) break;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SUS: {
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][c.chan];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
op.sus=c.value2&1;
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
} else {
|
||||
if (c.value>=ops) break;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
||||
op.sus=c.value2&1;
|
||||
unsigned char slot=slots[c.value][c.chan];
|
||||
if (slot==255) break;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_KSR: {
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][c.chan];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
op.ksr=c.value2&1;
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
} else {
|
||||
if (c.value>=ops) break;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
||||
op.ksr=c.value2&1;
|
||||
unsigned char slot=slots[c.value][c.chan];
|
||||
if (slot==255) break;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
rWrite(baseAddr+ADDR_AM_VIB_SUS_KSR_MULT,(op.am<<7)|(op.vib<<6)|(op.sus<<5)|(op.ksr<<4)|op.mult);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_WS: {
|
||||
if (oplType<2) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][c.chan];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
op.ws=c.value2&7;
|
||||
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
||||
}
|
||||
} else {
|
||||
if (c.value>=ops) break;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
||||
op.ws=c.value2&7;
|
||||
unsigned char slot=slots[c.value][c.chan];
|
||||
if (slot==255) break;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
rWrite(baseAddr+ADDR_WS,op.ws&((oplType==3)?7:3));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (oplType<2) break;
|
||||
int ops=(slots[3][c.chan]!=255 && chan[c.chan].state.ops==4 && oplType==3)?4:2;
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<ops; i++) {
|
||||
unsigned char slot=slots[i][c.chan];
|
||||
if (slot==255) continue;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[i]:i];
|
||||
op.ksl=c.value2&3;
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (isOutputL[ops==4][chan[c.chan].state.alg][i]) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (c.value>=ops) break;
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[(ops==4)?orderedOpsL[c.value]:c.value];
|
||||
op.ksl=c.value2&3;
|
||||
unsigned char slot=slots[c.value][c.chan];
|
||||
if (slot==255) break;
|
||||
unsigned short baseAddr=slotMap[slot];
|
||||
if (isMuted[c.chan]) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6));
|
||||
} else {
|
||||
if (isOutputL[ops==4][chan[c.chan].state.alg][c.value]) {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,(63-(((63-op.tl)*(chan[c.chan].outVol&0x3f))/63))|(op.ksl<<6));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_EXTCH: {
|
||||
if (!properDrumsSys) break;
|
||||
properDrums=c.value;
|
||||
|
|
@ -968,10 +1229,12 @@ void DivPlatformOPL::reset() {
|
|||
properDrums=properDrumsSys;
|
||||
if (oplType==3) {
|
||||
chanMap=properDrums?chanMapOPL3Drums:chanMapOPL3;
|
||||
outChanMap=outChanMapOPL3;
|
||||
melodicChans=properDrums?15:18;
|
||||
totalChans=properDrums?20:18;
|
||||
} else {
|
||||
chanMap=properDrums?chanMapOPL2Drums:chanMapOPL2;
|
||||
outChanMap=outChanMapOPL2;
|
||||
melodicChans=properDrums?6:9;
|
||||
totalChans=properDrums?11:9;
|
||||
}
|
||||
|
|
@ -982,6 +1245,10 @@ void DivPlatformOPL::reset() {
|
|||
chan[i].vol=0x3f;
|
||||
chan[i].outVol=0x3f;
|
||||
}
|
||||
|
||||
for (int i=0; i<melodicChans; i++) {
|
||||
fm.channel[outChanMap[i]].muted=isMuted[i];
|
||||
}
|
||||
|
||||
for (int i=0; i<512; i++) {
|
||||
oldWrites[i]=-1;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
#include "../dispatch.h"
|
||||
#include "../macroInt.h"
|
||||
#include <queue>
|
||||
#include "../../../extern/Nuked-OPL3/opl3.h"
|
||||
#include "../../../extern/opl/opl3.h"
|
||||
|
||||
class DivPlatformOPL: public DivDispatch {
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -55,6 +55,36 @@ const char* DivPlatformOPLL::getEffectName(unsigned char effect) {
|
|||
case 0x1b:
|
||||
return "1Bxx: Set attack of operator 2 (0 to F)";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 2 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 2 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 2 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set vibrato (x: operator from 1 to 2 (0 for all ops); y: enabled)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set key scale level (x: operator from 1 to 2 (0 for all ops); y: level from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set envelope sustain (x: operator from 1 to 2 (0 for all ops); y: enabled)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxy: Set whether key will scale envelope (x: operator from 1 to 2 (0 for all ops); y: enabled)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -447,6 +477,7 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
if (drums) {
|
||||
drums=false;
|
||||
immWrite(0x0e,0);
|
||||
drumState=0;
|
||||
}
|
||||
}
|
||||
if (c.chan<9) {
|
||||
|
|
@ -637,6 +668,150 @@ int DivPlatformOPLL::dispatch(DivCommand c) {
|
|||
rWrite(0x05,(car.ar<<4)|(car.dr));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
if (c.value<0) {
|
||||
mod.dr=c.value2&15;
|
||||
car.dr=c.value2&15;
|
||||
} else {
|
||||
if (c.value==0) {
|
||||
mod.dr=c.value2&15;
|
||||
} else {
|
||||
car.dr=c.value2&15;
|
||||
}
|
||||
}
|
||||
rWrite(0x04,(mod.ar<<4)|(mod.dr));
|
||||
rWrite(0x05,(car.ar<<4)|(car.dr));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
if (c.value<0) {
|
||||
mod.sl=c.value2&15;
|
||||
car.sl=c.value2&15;
|
||||
} else {
|
||||
if (c.value==0) {
|
||||
mod.sl=c.value2&15;
|
||||
} else {
|
||||
car.sl=c.value2&15;
|
||||
}
|
||||
}
|
||||
rWrite(0x06,(mod.sl<<4)|(mod.rr));
|
||||
rWrite(0x07,(car.sl<<4)|(car.rr));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
if (c.value<0) {
|
||||
mod.rr=c.value2&15;
|
||||
car.rr=c.value2&15;
|
||||
} else {
|
||||
if (c.value==0) {
|
||||
mod.rr=c.value2&15;
|
||||
} else {
|
||||
car.rr=c.value2&15;
|
||||
}
|
||||
}
|
||||
rWrite(0x06,(mod.sl<<4)|(mod.rr));
|
||||
rWrite(0x07,(car.sl<<4)|(car.rr));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
if (c.value<0) {
|
||||
mod.am=c.value2&1;
|
||||
car.am=c.value2&1;
|
||||
} else {
|
||||
if (c.value==0) {
|
||||
mod.am=c.value2&1;
|
||||
} else {
|
||||
car.am=c.value2&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));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_VIB: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
if (c.value<0) {
|
||||
mod.vib=c.value2&1;
|
||||
car.vib=c.value2&1;
|
||||
} else {
|
||||
if (c.value==0) {
|
||||
mod.vib=c.value2&1;
|
||||
} else {
|
||||
car.vib=c.value2&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));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_KSR: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
if (c.value<0) {
|
||||
mod.ksr=c.value2&1;
|
||||
car.ksr=c.value2&1;
|
||||
} else {
|
||||
if (c.value==0) {
|
||||
mod.ksr=c.value2&1;
|
||||
} else {
|
||||
car.ksr=c.value2&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));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SUS: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
if (c.value<0) {
|
||||
mod.ssgEnv=c.value2?8:0;
|
||||
car.ssgEnv=c.value2?8:0;
|
||||
} else {
|
||||
if (c.value==0) {
|
||||
mod.ssgEnv=c.value2?8:0;
|
||||
} else {
|
||||
car.ssgEnv=c.value2?8:0;
|
||||
}
|
||||
}
|
||||
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));
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.chan>=9 && !properDrums) return 0;
|
||||
DivInstrumentFM::Operator& mod=chan[c.chan].state.op[0];
|
||||
DivInstrumentFM::Operator& car=chan[c.chan].state.op[1];
|
||||
if (c.value<0) {
|
||||
mod.ksl=c.value2&3;
|
||||
car.ksl=c.value2&3;
|
||||
} else {
|
||||
if (c.value==0) {
|
||||
mod.ksl=c.value2&3;
|
||||
} else {
|
||||
car.ksl=c.value2&3;
|
||||
}
|
||||
}
|
||||
rWrite(0x02,(mod.ksl<<6)|(mod.tl&63));
|
||||
rWrite(0x03,(car.ksl<<6)|((chan[c.chan].state.fms&1)<<4)|((chan[c.chan].state.ams&1)<<3)|chan[c.chan].state.fb);
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_EXTCH:
|
||||
if (!properDrumsSys) break;
|
||||
if ((int)properDrums==c.value) break;
|
||||
|
|
|
|||
|
|
@ -137,8 +137,84 @@ const char* DivPlatformTX81Z::getEffectName(unsigned char effect) {
|
|||
case 0x1f:
|
||||
return "1Fxx: Set PM depth (0 to 7F)";
|
||||
break;
|
||||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
case 0x28:
|
||||
return "28xy: Set reverb (x: operator from 1 to 4 (0 for all ops); y: reverb from 0 to 7)";
|
||||
break;
|
||||
case 0x2a:
|
||||
return "2Axy: Set waveform (x: operator from 1 to 4 (0 for all ops); y: waveform from 0 to 7)";
|
||||
break;
|
||||
case 0x2b:
|
||||
return "2Bxy: Set envelope generator shift (x: operator from 1 to 4 (0 for all ops); y: shift from 0 to 3)";
|
||||
break;
|
||||
case 0x2c:
|
||||
return "2Cxy: Set fine multiplier (x: operator from 1 to 4 (0 for all ops); y: fine)";
|
||||
break;
|
||||
case 0x2f:
|
||||
return "2Fxx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x30: case 0x31: case 0x32: case 0x33:
|
||||
case 0x34: case 0x35: case 0x36: case 0x37:
|
||||
return "3xyy: Set fixed frequency of operator 1 (x: octave from 0 to 7; y: frequency)";
|
||||
break;
|
||||
case 0x38: case 0x39: case 0x3a: case 0x3b:
|
||||
case 0x3c: case 0x3d: case 0x3e: case 0x3f:
|
||||
return "3xyy: Set fixed frequency of operator 2 (x: octave from 8 to F; y: frequency)";
|
||||
break;
|
||||
case 0x40: case 0x41: case 0x42: case 0x43:
|
||||
case 0x44: case 0x45: case 0x46: case 0x47:
|
||||
return "4xyy: Set fixed frequency of operator 3 (x: octave from 0 to 7; y: frequency)";
|
||||
break;
|
||||
case 0x48: case 0x49: case 0x4a: case 0x4b:
|
||||
case 0x4c: case 0x4d: case 0x4e: case 0x4f:
|
||||
return "4xyy: Set fixed frequency of operator 4 (x: octave from 8 to F; y: frequency)";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set detune 2 (x: operator from 1 to 4 (0 for all ops); y: detune from 0 to 3)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxx: Set decay 2 of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x5c:
|
||||
return "5Cxx: Set decay 2 of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x5d:
|
||||
return "5Dxx: Set decay 2 of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x5e:
|
||||
return "5Exx: Set decay 2 of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
|
|
@ -604,8 +680,10 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
|
|||
case DIV_CMD_FM_MULT: {
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.mult=c.value2&15;
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|((op.egt?(op.dt&7):dtTable[op.dt&7])<<4));
|
||||
if (!op.egt) {
|
||||
op.mult=c.value2&15;
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|((op.egt?(op.dt&7):dtTable[op.dt&7])<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_TL: {
|
||||
|
|
@ -639,6 +717,221 @@ int DivPlatformTX81Z::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(op.rs<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DT2: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.dt2=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.dt2=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_D2R: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,(op.d2r&31)|(op.dt2<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DT: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
if (!op.egt) {
|
||||
op.dt=c.value&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|((op.egt?(op.dt&7):dtTable[op.dt&7])<<4));
|
||||
}
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
if (!op.egt) {
|
||||
op.dt=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|((op.egt?(op.dt&7):dtTable[op.dt&7])<<4));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_EG_SHIFT: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.ksl=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_EGS_REV,(op.dam&7)|(op.ksl<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.ksl=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_EGS_REV,(op.dam&7)|(op.ksl<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_REV: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.dam=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_EGS_REV,(op.dam&7)|(op.ksl<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.dam=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_EGS_REV,(op.dam&7)|(op.ksl<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_WS: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.ws=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_WS_FINE,(op.dvb&15)|(op.ws<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.ws=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_WS_FINE,(op.dvb&15)|(op.ws<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FINE: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
if (!op.egt) {
|
||||
op.dvb=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_WS_FINE,(op.dvb&15)|(op.ws<<4));
|
||||
}
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
if (!op.egt) {
|
||||
op.dvb=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_WS_FINE,(op.dvb&15)|(op.ws<<4));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_FIXFREQ: {
|
||||
if (c.value<0 || c.value>3) break;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.egt=(c.value2>0);
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.egt<<5)|(op.rs<<6));
|
||||
if (op.egt) {
|
||||
rWrite(baseAddr+ADDR_MULT_DT,((c.value2>>4)&15)|((c.value2>>8)&7));
|
||||
rWrite(baseAddr+ADDR_WS_FINE,(c.value2&15)|(op.ws<<4));
|
||||
} else {
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|((op.egt?(op.dt&7):dtTable[op.dt&7])<<4));
|
||||
rWrite(baseAddr+ADDR_WS_FINE,(op.dvb&15)|(op.ws<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM_DEPTH: {
|
||||
amDepth=c.value;
|
||||
immWrite(0x19,amDepth);
|
||||
|
|
|
|||
|
|
@ -397,6 +397,54 @@ const char* DivPlatformYM2610::getEffectName(unsigned char effect) {
|
|||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxx: Set decay 2 of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x5c:
|
||||
return "5Cxx: Set decay 2 of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x5d:
|
||||
return "5Dxx: Set decay 2 of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x5e:
|
||||
return "5Exx: Set decay 2 of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1088,6 +1136,134 @@ int DivPlatformYM2610::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_D2R: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DT: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.dt=c.value&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.dt=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SSG: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
chan[c.chan].hardReset=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -377,6 +377,54 @@ const char* DivPlatformYM2610B::getEffectName(unsigned char effect) {
|
|||
case 0x30:
|
||||
return "30xx: Toggle hard envelope reset on new notes";
|
||||
break;
|
||||
case 0x50:
|
||||
return "50xy: Set AM (x: operator from 1 to 4 (0 for all ops); y: AM)";
|
||||
break;
|
||||
case 0x51:
|
||||
return "51xy: Set sustain level (x: operator from 1 to 4 (0 for all ops); y: sustain)";
|
||||
break;
|
||||
case 0x52:
|
||||
return "52xy: Set release (x: operator from 1 to 4 (0 for all ops); y: release)";
|
||||
break;
|
||||
case 0x53:
|
||||
return "53xy: Set detune (x: operator from 1 to 4 (0 for all ops); y: detune where 3 is center)";
|
||||
break;
|
||||
case 0x54:
|
||||
return "54xy: Set envelope scale (x: operator from 1 to 4 (0 for all ops); y: scale from 0 to 3)";
|
||||
break;
|
||||
case 0x55:
|
||||
return "55xy: Set SSG envelope (x: operator from 1 to 4 (0 for all ops); y: 0-7 on, 8 off)";
|
||||
break;
|
||||
case 0x56:
|
||||
return "56xx: Set decay of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x57:
|
||||
return "57xx: Set decay of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x58:
|
||||
return "58xx: Set decay of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x59:
|
||||
return "59xx: Set decay of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5a:
|
||||
return "5Axx: Set decay of operator 4 (0 to 1F)";
|
||||
break;
|
||||
case 0x5b:
|
||||
return "5Bxx: Set decay 2 of all operators (0 to 1F)";
|
||||
break;
|
||||
case 0x5c:
|
||||
return "5Cxx: Set decay 2 of operator 1 (0 to 1F)";
|
||||
break;
|
||||
case 0x5d:
|
||||
return "5Dxx: Set decay 2 of operator 2 (0 to 1F)";
|
||||
break;
|
||||
case 0x5e:
|
||||
return "5Exx: Set decay 2 of operator 3 (0 to 1F)";
|
||||
break;
|
||||
case 0x5f:
|
||||
return "5Fxx: Set decay 2 of operator 4 (0 to 1F)";
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1066,6 +1114,134 @@ int DivPlatformYM2610B::dispatch(DivCommand c) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_D2R: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DT: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.dt=c.value&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.dt=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SSG: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[i];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_HARD_RESET:
|
||||
chan[c.chan].hardReset=c.value;
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -175,17 +175,146 @@ int DivPlatformYM2610BExt::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator op=ins->fm.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.ar=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+0x50,(c.value2&31)|(op.rs<<6));
|
||||
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else {
|
||||
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.ar=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+0x50,(c.value2&31)|(op.rs<<6));
|
||||
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_D2R: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DT: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.dt=c.value&7;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.dt=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SSG: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[i];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[2].state.op[orderedOps[c.value]];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[2]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -175,17 +175,146 @@ int DivPlatformYM2610Ext::dispatch(DivCommand c) {
|
|||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AR: {
|
||||
DivInstrument* ins=parent->getIns(opChan[ch].ins,DIV_INS_FM);
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator op=ins->fm.op[i];
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
op.ar=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
rWrite(baseAddr+0x50,(c.value2&31)|(op.rs<<6));
|
||||
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else {
|
||||
DivInstrumentFM::Operator op=ins->fm.op[orderedOps[c.value]];
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
op.ar=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+0x50,(c.value2&31)|(op.rs<<6));
|
||||
rWrite(baseAddr+0x50,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RS: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
op.rs=c.value2&3;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_RS_AR,(op.ar&31)|(op.rs<<6));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_AM: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
op.am=c.value2&1;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
op.dr=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_AM_DR,(op.dr&31)|(op.am<<7));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SL: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
op.sl=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_RR: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
op.rr=c.value2&15;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SL_RR,(op.rr&15)|(op.sl<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_D2R: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
op.d2r=c.value2&31;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_DT2_D2R,op.d2r&31);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_DT: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
op.dt=c.value&7;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
op.dt=c.value2&7;
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_MULT_DT,(op.mult&15)|(dtTable[op.dt&7]<<4));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DIV_CMD_FM_SSG: {
|
||||
if (c.value<0) {
|
||||
for (int i=0; i<4; i++) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[i];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[i];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
} else if (c.value<4) {
|
||||
DivInstrumentFM::Operator& op=chan[1].state.op[orderedOps[c.value]];
|
||||
op.ssgEnv=8^(c.value2&15);
|
||||
unsigned short baseAddr=chanOffs[1]|opOffs[orderedOps[c.value]];
|
||||
rWrite(baseAddr+ADDR_SSG,op.ssgEnv&15);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -351,7 +351,7 @@ struct DivSong {
|
|||
std::vector<DivSample*> sample;
|
||||
|
||||
bool chanShow[DIV_MAX_CHANS];
|
||||
bool chanCollapse[DIV_MAX_CHANS];
|
||||
unsigned char chanCollapse[DIV_MAX_CHANS];
|
||||
|
||||
DivInstrument nullIns, nullInsOPLL, nullInsOPL, nullInsQSound;
|
||||
DivWavetable nullWave;
|
||||
|
|
@ -458,13 +458,39 @@ struct DivSong {
|
|||
}
|
||||
for (int i=0; i<DIV_MAX_CHANS; i++) {
|
||||
chanShow[i]=true;
|
||||
chanCollapse[i]=false;
|
||||
chanCollapse[i]=0;
|
||||
}
|
||||
system[0]=DIV_SYSTEM_YM2612;
|
||||
system[1]=DIV_SYSTEM_SMS;
|
||||
|
||||
// OPLL default instrument contest winner - piano_guitar_idk by Weeppiko
|
||||
nullInsOPLL.fm.opllPreset=0;
|
||||
nullInsOPLL.fm.alg=0;
|
||||
nullInsOPLL.fm.fb=7;
|
||||
nullInsOPLL.fm.fms=1;
|
||||
nullInsOPLL.fm.ams=0;
|
||||
nullInsOPLL.fm.op[0].ar=15;
|
||||
nullInsOPLL.fm.op[0].dr=5;
|
||||
nullInsOPLL.fm.op[0].sl=3;
|
||||
nullInsOPLL.fm.op[0].rr=3;
|
||||
nullInsOPLL.fm.op[0].tl=40;
|
||||
nullInsOPLL.fm.op[0].ksl=0;
|
||||
nullInsOPLL.fm.op[0].mult=5;
|
||||
nullInsOPLL.fm.op[0].am=0;
|
||||
nullInsOPLL.fm.op[0].vib=1;
|
||||
nullInsOPLL.fm.op[0].ksr=0;
|
||||
nullInsOPLL.fm.op[0].ssgEnv=8;
|
||||
nullInsOPLL.fm.op[1].ar=15;
|
||||
nullInsOPLL.fm.op[1].dr=1;
|
||||
nullInsOPLL.fm.op[1].sl=11;
|
||||
nullInsOPLL.fm.op[1].rr=6;
|
||||
nullInsOPLL.fm.op[1].tl=0;
|
||||
nullInsOPLL.fm.op[1].ksl=0;
|
||||
nullInsOPLL.fm.op[1].mult=1;
|
||||
nullInsOPLL.fm.op[1].am=0;
|
||||
nullInsOPLL.fm.op[1].vib=0;
|
||||
nullInsOPLL.fm.op[1].ksr=0;
|
||||
nullInsOPLL.fm.op[1].ssgEnv=8;
|
||||
nullInsOPLL.name="This is a bug! Report!";
|
||||
|
||||
nullInsOPL.fm.alg=0;
|
||||
|
|
|
|||
|
|
@ -496,6 +496,7 @@ void DivEngine::registerSystems() {
|
|||
OP_EFFECT_SINGLE(0x28,DIV_CMD_FM_REV,4,7);
|
||||
OP_EFFECT_SINGLE(0x2a,DIV_CMD_FM_WS,4,7);
|
||||
OP_EFFECT_SINGLE(0x2b,DIV_CMD_FM_EG_SHIFT,4,3);
|
||||
OP_EFFECT_SINGLE(0x2c,DIV_CMD_FM_FINE,4,15);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -541,7 +542,6 @@ void DivEngine::registerSystems() {
|
|||
OP_EFFECT_MULTI(0x58,DIV_CMD_FM_DR,1,15);
|
||||
|
||||
OP_EFFECT_SINGLE(0x5b,DIV_CMD_FM_KSR,2,1);
|
||||
OP_EFFECT_SINGLE(0x2a,DIV_CMD_FM_WS,4,7);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
@ -607,6 +607,7 @@ void DivEngine::registerSystems() {
|
|||
OP_EFFECT_MULTI(0x5a,DIV_CMD_FM_DR,3,15);
|
||||
|
||||
OP_EFFECT_SINGLE(0x5b,DIV_CMD_FM_KSR,4,1);
|
||||
OP_EFFECT_SINGLE(0x2a,DIV_CMD_FM_WS,4,7);
|
||||
|
||||
default:
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -83,10 +83,10 @@ void FurnaceGUI::finishSelection() {
|
|||
if (cursor.y<0) cursor.y=0;
|
||||
if (cursor.y>=e->song.patLen) cursor.y=e->song.patLen-1;
|
||||
|
||||
if (e->song.chanCollapse[selEnd.xCoarse]) {
|
||||
if (e->song.chanCollapse[selStart.xCoarse]==3) {
|
||||
selStart.xFine=0;
|
||||
}
|
||||
if (e->song.chanCollapse[selEnd.xCoarse]) {
|
||||
if (e->song.chanCollapse[selEnd.xCoarse] && selEnd.xFine>=(3-e->song.chanCollapse[selEnd.xCoarse])) {
|
||||
selEnd.xFine=2+e->song.pat[cursor.xCoarse].effectCols*2;
|
||||
}
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ void FurnaceGUI::moveCursor(int x, int y, bool select) {
|
|||
demandScrollX=true;
|
||||
if (x>0) {
|
||||
for (int i=0; i<x; i++) {
|
||||
if (++cursor.xFine>=(e->song.chanCollapse[cursor.xCoarse]?1:(3+e->song.pat[cursor.xCoarse].effectCols*2))) {
|
||||
if (++cursor.xFine>=(e->song.chanCollapse[cursor.xCoarse]?(4-e->song.chanCollapse[cursor.xCoarse]):(3+e->song.pat[cursor.xCoarse].effectCols*2))) {
|
||||
cursor.xFine=0;
|
||||
if (++cursor.xCoarse>=lastChannel) {
|
||||
if (settings.wrapHorizontal!=0 && !select) {
|
||||
|
|
@ -113,7 +113,7 @@ void FurnaceGUI::moveCursor(int x, int y, bool select) {
|
|||
if (settings.wrapHorizontal==2) y++;
|
||||
} else {
|
||||
cursor.xCoarse=lastChannel-1;
|
||||
cursor.xFine=e->song.chanCollapse[cursor.xCoarse]?0:(2+e->song.pat[cursor.xCoarse].effectCols*2);
|
||||
cursor.xFine=e->song.chanCollapse[cursor.xCoarse]?(3-e->song.chanCollapse[cursor.xCoarse]):(2+e->song.pat[cursor.xCoarse].effectCols*2);
|
||||
}
|
||||
} else {
|
||||
while (!e->song.chanShow[cursor.xCoarse]) {
|
||||
|
|
@ -141,7 +141,7 @@ void FurnaceGUI::moveCursor(int x, int y, bool select) {
|
|||
if (cursor.xCoarse<0) break;
|
||||
}
|
||||
if (e->song.chanCollapse[cursor.xCoarse]) {
|
||||
cursor.xFine=0;
|
||||
cursor.xFine=3-e->song.chanCollapse[cursor.xCoarse];
|
||||
} else {
|
||||
cursor.xFine=2+e->song.pat[cursor.xCoarse].effectCols*2;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ void FurnaceGUI::drawInsList() {
|
|||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_FA_FOLDER_OPEN "##InsLoad")) {
|
||||
doAction(GUI_ACTION_INS_LIST_OPEN);
|
||||
doAction((settings.insLoadAlwaysReplace && curIns>=0 && curIns<=(int)e->song.ins.size())?GUI_ACTION_INS_LIST_OPEN_REPLACE:GUI_ACTION_INS_LIST_OPEN);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_FA_FLOPPY_O "##InsSave")) {
|
||||
|
|
|
|||
|
|
@ -518,6 +518,9 @@ void FurnaceGUI::doAction(int what) {
|
|||
case GUI_ACTION_INS_LIST_OPEN:
|
||||
openFileDialog(GUI_FILE_INS_OPEN);
|
||||
break;
|
||||
case GUI_ACTION_INS_LIST_OPEN_REPLACE:
|
||||
openFileDialog(GUI_FILE_INS_OPEN_REPLACE);
|
||||
break;
|
||||
case GUI_ACTION_INS_LIST_SAVE:
|
||||
if (curIns>=0 && curIns<(int)e->song.ins.size()) openFileDialog(GUI_FILE_INS_SAVE);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -1259,9 +1259,9 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
if (!dirExists(workingDirSong)) workingDirSong=getHomeDir();
|
||||
hasOpened=fileDialog->openLoad(
|
||||
"Open File",
|
||||
{"compatible files", "*.fur *.dmf *.mod",
|
||||
{"compatible files", "*.fur *.dmf *.mod *.ftm",
|
||||
"all files", ".*"},
|
||||
"compatible files{.fur,.dmf,.mod},.*",
|
||||
"compatible files{.fur,.dmf,.mod,.ftm},.*",
|
||||
workingDirSong,
|
||||
dpiScale
|
||||
);
|
||||
|
|
@ -1288,7 +1288,14 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
);
|
||||
break;
|
||||
case GUI_FILE_INS_OPEN:
|
||||
case GUI_FILE_INS_OPEN_REPLACE:
|
||||
prevIns=-3;
|
||||
if (prevInsData!=NULL) {
|
||||
delete prevInsData;
|
||||
prevInsData=NULL;
|
||||
}
|
||||
prevInsData=new DivInstrument;
|
||||
*prevInsData=*e->getIns(curIns);
|
||||
if (!dirExists(workingDirIns)) workingDirIns=getHomeDir();
|
||||
hasOpened=fileDialog->openLoad(
|
||||
"Load Instrument",
|
||||
|
|
@ -1300,11 +1307,20 @@ void FurnaceGUI::openFileDialog(FurnaceGUIFileDialogs type) {
|
|||
[this](const char* path) {
|
||||
std::vector<DivInstrument*> instruments=e->instrumentFromFile(path);
|
||||
if (!instruments.empty()) {
|
||||
e->loadTempIns(instruments[0]);
|
||||
if (curIns!=-2) {
|
||||
prevIns=curIns;
|
||||
if (curFileDialog==GUI_FILE_INS_OPEN_REPLACE) {
|
||||
if (prevIns==-3) {
|
||||
prevIns=curIns;
|
||||
}
|
||||
if (prevIns>=0 && prevIns<=(int)e->song.ins.size()) {
|
||||
*e->song.ins[prevIns]=*instruments[0];
|
||||
}
|
||||
} else {
|
||||
e->loadTempIns(instruments[0]);
|
||||
if (curIns!=-2) {
|
||||
prevIns=curIns;
|
||||
}
|
||||
curIns=-2;
|
||||
}
|
||||
curIns=-2;
|
||||
}
|
||||
for (DivInstrument* i: instruments) delete i;
|
||||
}
|
||||
|
|
@ -1750,8 +1766,11 @@ void FurnaceGUI::processDrags(int dragX, int dragY) {
|
|||
if (macroLoopDragLen>0) {
|
||||
int x=(dragX-macroLoopDragStart.x)*macroLoopDragLen/MAX(1,macroLoopDragAreaSize.x);
|
||||
if (x<0) x=0;
|
||||
if (x>=macroLoopDragLen) x=-1;
|
||||
x+=macroDragScroll;
|
||||
if (x>=macroLoopDragLen) {
|
||||
x=-1;
|
||||
} else {
|
||||
x+=macroDragScroll;
|
||||
}
|
||||
*macroLoopDragTarget=x;
|
||||
}
|
||||
}
|
||||
|
|
@ -2416,6 +2435,13 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
|
||||
wantCaptureKeyboard=ImGui::GetIO().WantTextInput;
|
||||
|
||||
if (wantCaptureKeyboard) {
|
||||
WAKE_UP;
|
||||
}
|
||||
if (ImGui::GetIO().MouseDown[0] || ImGui::GetIO().MouseDown[1] || ImGui::GetIO().MouseDown[2] || ImGui::GetIO().MouseDown[3] || ImGui::GetIO().MouseDown[4]) {
|
||||
WAKE_UP;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
midiLock.lock();
|
||||
|
|
@ -2559,6 +2585,7 @@ bool FurnaceGUI::loop() {
|
|||
ImGui_ImplSDL2_NewFrame(sdlWin);
|
||||
ImGui::NewFrame();
|
||||
|
||||
curWindowLast=curWindow;
|
||||
curWindow=GUI_WINDOW_NOTHING;
|
||||
editOptsVisible=false;
|
||||
|
||||
|
|
@ -2900,8 +2927,16 @@ bool FurnaceGUI::loop() {
|
|||
if (fileDialog->render(ImVec2(600.0f*dpiScale,400.0f*dpiScale),ImVec2(scrW*dpiScale,scrH*dpiScale))) {
|
||||
bool openOpen=false;
|
||||
//ImGui::GetIO().ConfigFlags&=~ImGuiConfigFlags_NavEnableKeyboard;
|
||||
if (curFileDialog==GUI_FILE_INS_OPEN && prevIns!=-3) {
|
||||
curIns=prevIns;
|
||||
if ((curFileDialog==GUI_FILE_INS_OPEN || curFileDialog==GUI_FILE_INS_OPEN_REPLACE) && prevIns!=-3) {
|
||||
if (curFileDialog==GUI_FILE_INS_OPEN_REPLACE) {
|
||||
if (prevInsData!=NULL) {
|
||||
if (prevIns>=0 && prevIns<(int)e->song.ins.size()) {
|
||||
*e->song.ins[prevIns]=*prevInsData;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
curIns=prevIns;
|
||||
}
|
||||
prevIns=-3;
|
||||
}
|
||||
switch (curFileDialog) {
|
||||
|
|
@ -2911,6 +2946,7 @@ bool FurnaceGUI::loop() {
|
|||
workingDirSong=fileDialog->getPath()+DIR_SEPARATOR_STR;
|
||||
break;
|
||||
case GUI_FILE_INS_OPEN:
|
||||
case GUI_FILE_INS_OPEN_REPLACE:
|
||||
case GUI_FILE_INS_SAVE:
|
||||
workingDirIns=fileDialog->getPath()+DIR_SEPARATOR_STR;
|
||||
break;
|
||||
|
|
@ -3090,6 +3126,25 @@ bool FurnaceGUI::loop() {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case GUI_FILE_INS_OPEN_REPLACE: {
|
||||
std::vector<DivInstrument*> instruments=e->instrumentFromFile(copyOfName.c_str());
|
||||
if (!instruments.empty()) {
|
||||
if (!e->getWarnings().empty()) {
|
||||
showWarning(e->getWarnings(),GUI_WARN_GENERIC);
|
||||
}
|
||||
if (curIns>=0 && curIns<(int)e->song.ins.size()) {
|
||||
*e->song.ins[curIns]=*instruments[curIns];
|
||||
} else {
|
||||
showError("...but you haven't selected an instrument!");
|
||||
}
|
||||
for (DivInstrument* i: instruments) {
|
||||
delete i;
|
||||
}
|
||||
} else {
|
||||
showError("cannot load instrument! ("+e->getLastError()+")");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GUI_FILE_WAVE_OPEN:
|
||||
e->addWaveFromFile(copyOfName.c_str());
|
||||
MARK_MODIFIED;
|
||||
|
|
@ -3805,6 +3860,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
patFont(NULL),
|
||||
bigFont(NULL),
|
||||
fontRange(NULL),
|
||||
prevInsData(NULL),
|
||||
curIns(0),
|
||||
curWave(0),
|
||||
curSample(0),
|
||||
|
|
@ -3903,6 +3959,7 @@ FurnaceGUI::FurnaceGUI():
|
|||
nonLatchNibble(false),
|
||||
curWindow(GUI_WINDOW_NOTHING),
|
||||
nextWindow(GUI_WINDOW_NOTHING),
|
||||
curWindowLast(GUI_WINDOW_NOTHING),
|
||||
nextDesc(NULL),
|
||||
latchNote(-1),
|
||||
latchIns(-2),
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ enum FurnaceGUIFileDialogs {
|
|||
GUI_FILE_SAVE,
|
||||
GUI_FILE_SAVE_DMF_LEGACY,
|
||||
GUI_FILE_INS_OPEN,
|
||||
GUI_FILE_INS_OPEN_REPLACE,
|
||||
GUI_FILE_INS_SAVE,
|
||||
GUI_FILE_WAVE_OPEN,
|
||||
GUI_FILE_WAVE_SAVE,
|
||||
|
|
@ -406,6 +407,7 @@ enum FurnaceGUIActions {
|
|||
GUI_ACTION_INS_LIST_ADD,
|
||||
GUI_ACTION_INS_LIST_DUPLICATE,
|
||||
GUI_ACTION_INS_LIST_OPEN,
|
||||
GUI_ACTION_INS_LIST_OPEN_REPLACE,
|
||||
GUI_ACTION_INS_LIST_SAVE,
|
||||
GUI_ACTION_INS_LIST_MOVE_UP,
|
||||
GUI_ACTION_INS_LIST_MOVE_DOWN,
|
||||
|
|
@ -855,6 +857,7 @@ class FurnaceGUI {
|
|||
int eventDelay;
|
||||
int moveWindowTitle;
|
||||
int hiddenSystems;
|
||||
int insLoadAlwaysReplace;
|
||||
unsigned int maxUndoSteps;
|
||||
String mainFontPath;
|
||||
String patFontPath;
|
||||
|
|
@ -937,6 +940,7 @@ class FurnaceGUI {
|
|||
eventDelay(0),
|
||||
moveWindowTitle(0),
|
||||
hiddenSystems(0),
|
||||
insLoadAlwaysReplace(1),
|
||||
maxUndoSteps(100),
|
||||
mainFontPath(""),
|
||||
patFontPath(""),
|
||||
|
|
@ -947,6 +951,8 @@ class FurnaceGUI {
|
|||
|
||||
char finalLayoutPath[4096];
|
||||
|
||||
DivInstrument* prevInsData;
|
||||
|
||||
int curIns, curWave, curSample, curOctave, curOrder, prevIns, oldRow, oldOrder, oldOrder1, editStep, exportLoops, soloChan, soloTimeout, orderEditMode, orderCursor;
|
||||
int loopOrder, loopRow, loopEnd, isClipping, extraChannelButtons, patNameTarget, newSongCategory, latchTarget;
|
||||
int wheelX, wheelY;
|
||||
|
|
@ -966,7 +972,7 @@ class FurnaceGUI {
|
|||
SelectionPoint selStart, selEnd, cursor;
|
||||
bool selecting, curNibble, orderNibble, followOrders, followPattern, changeAllOrders;
|
||||
bool collapseWindow, demandScrollX, fancyPattern, wantPatName, firstFrame, tempoView, waveHex, lockLayout, editOptsVisible, latchNibble, nonLatchNibble;
|
||||
FurnaceGUIWindows curWindow, nextWindow;
|
||||
FurnaceGUIWindows curWindow, nextWindow, curWindowLast;
|
||||
float peak[2];
|
||||
float patChanX[DIV_MAX_CHANS+1];
|
||||
float patChanSlideY[DIV_MAX_CHANS+1];
|
||||
|
|
|
|||
|
|
@ -233,22 +233,22 @@ const FurnaceGUIColors fxColors[256]={
|
|||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
|
||||
// 50-5F
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,
|
||||
|
||||
// 60-6F
|
||||
GUI_COLOR_PATTERN_EFFECT_INVALID,
|
||||
|
|
@ -560,6 +560,7 @@ const FurnaceGUIActionDef guiActions[GUI_ACTION_MAX]={
|
|||
D("INS_LIST_ADD", "Add", SDLK_INSERT),
|
||||
D("INS_LIST_DUPLICATE", "Duplicate", FURKMOD_CMD|SDLK_d),
|
||||
D("INS_LIST_OPEN", "Open", 0),
|
||||
D("INS_LIST_OPEN_REPLACE", "Open (replace current)", 0),
|
||||
D("INS_LIST_SAVE", "Save", 0),
|
||||
D("INS_LIST_MOVE_UP", "Move up", FURKMOD_SHIFT|SDLK_UP),
|
||||
D("INS_LIST_MOVE_DOWN", "Move down", FURKMOD_SHIFT|SDLK_DOWN),
|
||||
|
|
|
|||
|
|
@ -1078,7 +1078,7 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s
|
|||
if (displayLoop) { \
|
||||
ImGui::SetNextItemWidth(lenAvail); \
|
||||
if (ImGui::InputScalar("##IMacroLen_" macroName,ImGuiDataType_U8,¯o.len,&_ONE,&_THREE)) { MARK_MODIFIED \
|
||||
if (macro.len>127) macro.len=127; \
|
||||
if (macro.len>128) macro.len=128; \
|
||||
} \
|
||||
if (macroMode) { \
|
||||
bool modeVal=macro.mode; \
|
||||
|
|
@ -1178,7 +1178,7 @@ void FurnaceGUI::drawGBEnv(unsigned char vol, unsigned char len, unsigned char s
|
|||
if (displayLoop) { \
|
||||
ImGui::SetNextItemWidth(lenAvail); \
|
||||
if (ImGui::InputScalar("##IOPMacroLen_" #op macroName,ImGuiDataType_U8,¯o.len,&_ONE,&_THREE)) { MARK_MODIFIED \
|
||||
if (macro.len>127) macro.len=127; \
|
||||
if (macro.len>128) macro.len=128; \
|
||||
} \
|
||||
if (macroMode) { \
|
||||
bool modeVal=macro.mode; \
|
||||
|
|
@ -1267,14 +1267,14 @@ if (ImGui::BeginTable("MacroSpace",2)) { \
|
|||
ImGui::Dummy(ImVec2(120.0f*dpiScale,dpiScale)); \
|
||||
ImGui::TableNextColumn(); \
|
||||
float availableWidth=ImGui::GetContentRegionAvail().x-reservedSpace; \
|
||||
int totalFit=MIN(127,availableWidth/MAX(1,macroPointSize*dpiScale)); \
|
||||
if (macroDragScroll>127-totalFit) { \
|
||||
macroDragScroll=127-totalFit; \
|
||||
int totalFit=MIN(128,availableWidth/MAX(1,macroPointSize*dpiScale)); \
|
||||
if (macroDragScroll>128-totalFit) { \
|
||||
macroDragScroll=128-totalFit; \
|
||||
} \
|
||||
ImGui::SetNextItemWidth(availableWidth); \
|
||||
if (CWSliderInt("##MacroScroll",¯oDragScroll,0,127-totalFit,"")) { \
|
||||
if (CWSliderInt("##MacroScroll",¯oDragScroll,0,128-totalFit,"")) { \
|
||||
if (macroDragScroll<0) macroDragScroll=0; \
|
||||
if (macroDragScroll>127-totalFit) macroDragScroll=127-totalFit; \
|
||||
if (macroDragScroll>128-totalFit) macroDragScroll=128-totalFit; \
|
||||
}
|
||||
|
||||
#define MACRO_END \
|
||||
|
|
@ -1282,9 +1282,9 @@ if (ImGui::BeginTable("MacroSpace",2)) { \
|
|||
ImGui::TableNextColumn(); \
|
||||
ImGui::TableNextColumn(); \
|
||||
ImGui::SetNextItemWidth(availableWidth); \
|
||||
if (CWSliderInt("##MacroScroll",¯oDragScroll,0,127-totalFit,"")) { \
|
||||
if (CWSliderInt("##MacroScroll",¯oDragScroll,0,128-totalFit,"")) { \
|
||||
if (macroDragScroll<0) macroDragScroll=0; \
|
||||
if (macroDragScroll>127-totalFit) macroDragScroll=127-totalFit; \
|
||||
if (macroDragScroll>128-totalFit) macroDragScroll=128-totalFit; \
|
||||
} \
|
||||
ImGui::EndTable(); \
|
||||
}
|
||||
|
|
@ -1378,7 +1378,7 @@ void FurnaceGUI::drawInsEdit() {
|
|||
ImGui::TableNextColumn();
|
||||
// TODO: load replace
|
||||
if (ImGui::Button(ICON_FA_FOLDER_OPEN "##IELoad")) {
|
||||
doAction(GUI_ACTION_INS_LIST_OPEN);
|
||||
doAction(GUI_ACTION_INS_LIST_OPEN_REPLACE);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_FA_FLOPPY_O "##IESave")) {
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
}
|
||||
// check overflow highlight
|
||||
if (settings.overflowHighlight) {
|
||||
if (edit && cursor.y==i) {
|
||||
if (edit && cursor.y==i && curWindowLast==GUI_WINDOW_PATTERN) {
|
||||
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_EDITING]));
|
||||
} else if (isPlaying && oldRow==i && ord==e->getOrder()) {
|
||||
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_PLAY_HEAD]));
|
||||
|
|
@ -75,7 +75,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
}
|
||||
} else {
|
||||
isPushing=true;
|
||||
if (edit && cursor.y==i) {
|
||||
if (edit && cursor.y==i && curWindowLast==GUI_WINDOW_PATTERN) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_EDITING]));
|
||||
} else if (isPlaying && oldRow==i && ord==e->getOrder()) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Header,ImGui::GetColorU32(uiColors[GUI_COLOR_PATTERN_PLAY_HEAD]));
|
||||
|
|
@ -113,9 +113,9 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
bool selectedNote=selectedRow && (j32>=sel1XSum && j32<=sel2XSum);
|
||||
bool selectedIns=selectedRow && (j32+1>=sel1XSum && j32+1<=sel2XSum);
|
||||
bool selectedVol=selectedRow && (j32+2>=sel1XSum && j32+2<=sel2XSum);
|
||||
bool cursorNote=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==0);
|
||||
bool cursorIns=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==1);
|
||||
bool cursorVol=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==2);
|
||||
bool cursorNote=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==0 && curWindowLast==GUI_WINDOW_PATTERN);
|
||||
bool cursorIns=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==1 && curWindowLast==GUI_WINDOW_PATTERN);
|
||||
bool cursorVol=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==2 && curWindowLast==GUI_WINDOW_PATTERN);
|
||||
|
||||
// note
|
||||
sprintf(id,"%s##PN_%d_%d",noteName(pat->data[i][0],pat->data[i][1]),i,j);
|
||||
|
|
@ -145,7 +145,7 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
ImGui::PopStyleColor();
|
||||
|
||||
// the following is only visible when the channel is not collapsed
|
||||
if (!e->song.chanCollapse[j]) {
|
||||
if (e->song.chanCollapse[j]<3) {
|
||||
// instrument
|
||||
if (pat->data[i][2]==-1) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text,inactiveColor);
|
||||
|
|
@ -183,7 +183,9 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
updateSelection(j,1,i);
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
if (e->song.chanCollapse[j]<2) {
|
||||
// volume
|
||||
if (pat->data[i][3]==-1) {
|
||||
sprintf(id,"..##PV_%d_%d",i,j);
|
||||
|
|
@ -215,14 +217,16 @@ inline void FurnaceGUI::patternRow(int i, bool isPlaying, float lineHeight, int
|
|||
updateSelection(j,2,i);
|
||||
}
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
if (e->song.chanCollapse[j]<1) {
|
||||
// effects
|
||||
for (int k=0; k<e->song.pat[j].effectCols; k++) {
|
||||
int index=4+(k<<1);
|
||||
bool selectedEffect=selectedRow && (j32+index-1>=sel1XSum && j32+index-1<=sel2XSum);
|
||||
bool selectedEffectVal=selectedRow && (j32+index>=sel1XSum && j32+index<=sel2XSum);
|
||||
bool cursorEffect=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==index-1);
|
||||
bool cursorEffectVal=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==index);
|
||||
bool cursorEffect=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==index-1 && curWindowLast==GUI_WINDOW_PATTERN);
|
||||
bool cursorEffectVal=(cursor.y==i && cursor.xCoarse==j && cursor.xFine==index && curWindowLast==GUI_WINDOW_PATTERN);
|
||||
|
||||
// effect
|
||||
if (pat->data[i][index]==-1) {
|
||||
|
|
@ -499,7 +503,11 @@ void FurnaceGUI::drawPattern() {
|
|||
snprintf(chanID,2048,"%c##_HCH%d",e->song.chanCollapse[i]?'+':'-',i);
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX()+4.0f*dpiScale);
|
||||
if (ImGui::SmallButton(chanID)) {
|
||||
e->song.chanCollapse[i]=!e->song.chanCollapse[i];
|
||||
if (e->song.chanCollapse[i]==0) {
|
||||
e->song.chanCollapse[i]=3;
|
||||
} else if (e->song.chanCollapse[i]>0) {
|
||||
e->song.chanCollapse[i]--;
|
||||
}
|
||||
}
|
||||
if (!e->song.chanCollapse[i]) {
|
||||
ImGui::SameLine();
|
||||
|
|
|
|||
|
|
@ -419,6 +419,11 @@ void FurnaceGUI::drawSettings() {
|
|||
settings.restartOnFlagChange=restartOnFlagChangeB;
|
||||
}
|
||||
|
||||
bool insLoadAlwaysReplaceB=settings.insLoadAlwaysReplace;
|
||||
if (ImGui::Checkbox("Always replace currently selected instrument when loading from instrument list",&insLoadAlwaysReplaceB)) {
|
||||
settings.insLoadAlwaysReplace=insLoadAlwaysReplaceB;
|
||||
}
|
||||
|
||||
bool sysFileDialogB=settings.sysFileDialog;
|
||||
if (ImGui::Checkbox("Use system file picker",&sysFileDialogB)) {
|
||||
settings.sysFileDialog=sysFileDialogB;
|
||||
|
|
@ -1616,6 +1621,7 @@ void FurnaceGUI::drawSettings() {
|
|||
UI_KEYBIND_CONFIG(GUI_ACTION_INS_LIST_ADD);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_INS_LIST_DUPLICATE);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_INS_LIST_OPEN);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_INS_LIST_OPEN_REPLACE);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_INS_LIST_SAVE);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_INS_LIST_MOVE_UP);
|
||||
UI_KEYBIND_CONFIG(GUI_ACTION_INS_LIST_MOVE_DOWN);
|
||||
|
|
@ -1830,6 +1836,7 @@ void FurnaceGUI::syncSettings() {
|
|||
settings.eventDelay=e->getConfInt("eventDelay",0);
|
||||
settings.moveWindowTitle=e->getConfInt("moveWindowTitle",0);
|
||||
settings.hiddenSystems=e->getConfInt("hiddenSystems",0);
|
||||
settings.insLoadAlwaysReplace=e->getConfInt("insLoadAlwaysReplace",1);
|
||||
|
||||
clampSetting(settings.mainFontSize,2,96);
|
||||
clampSetting(settings.patFontSize,2,96);
|
||||
|
|
@ -1900,6 +1907,7 @@ void FurnaceGUI::syncSettings() {
|
|||
clampSetting(settings.eventDelay,0,1);
|
||||
clampSetting(settings.moveWindowTitle,0,1);
|
||||
clampSetting(settings.hiddenSystems,0,1);
|
||||
clampSetting(settings.insLoadAlwaysReplace,0,1);
|
||||
|
||||
settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys",""));
|
||||
if (settings.initialSys.size()<4) {
|
||||
|
|
@ -2011,6 +2019,7 @@ void FurnaceGUI::commitSettings() {
|
|||
e->setConf("moveWindowTitle",settings.moveWindowTitle);
|
||||
e->setConf("hiddenSystems",settings.hiddenSystems);
|
||||
e->setConf("initialSys",e->encodeSysDesc(settings.initialSys));
|
||||
e->setConf("insLoadAlwaysReplace",settings.insLoadAlwaysReplace);
|
||||
|
||||
// colors
|
||||
for (int i=0; i<GUI_COLOR_MAX; i++) {
|
||||
|
|
@ -2630,6 +2639,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) {
|
|||
if ((iconFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(iconFont_compressed_data,iconFont_compressed_size,e->getConfInt("iconSize",16)*dpiScale,&fc,fontRangeIcon))==NULL) {
|
||||
logE("could not load icon font!");
|
||||
}
|
||||
|
||||
if (settings.mainFontSize==settings.patFontSize && settings.patFont<5 && builtinFontM[settings.patFont]==builtinFont[settings.mainFont]) {
|
||||
logD("using main font for pat font.");
|
||||
patFont=mainFont;
|
||||
|
|
@ -2661,8 +2671,9 @@ void FurnaceGUI::applyUISettings(bool updateFonts) {
|
|||
logE("could not load pattern font!");
|
||||
patFont=ImGui::GetIO().Fonts->AddFontDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((bigFont=ImGui::GetIO().Fonts->AddFontFromMemoryCompressedTTF(font_plexSans_compressed_data,font_plexSans_compressed_size,40*dpiScale))==NULL) {
|
||||
logE("could not load big UI font!");
|
||||
}
|
||||
|
|
@ -2688,6 +2699,7 @@ void FurnaceGUI::applyUISettings(bool updateFonts) {
|
|||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ttc",uiColors[GUI_COLOR_FILE_FONT],ICON_FA_FONT);
|
||||
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".mod",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".ftm",uiColors[GUI_COLOR_FILE_SONG_IMPORT],ICON_FA_FILE);
|
||||
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".tfi",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
ImGuiFileDialog::Instance()->SetFileStyle(IGFD_FileStyleByExtension,".vgi",uiColors[GUI_COLOR_FILE_INSTR],ICON_FA_FILE);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue