diff --git a/TODO.md b/TODO.md index cb3f80db8..fc31cad66 100644 --- a/TODO.md +++ b/TODO.md @@ -26,8 +26,6 @@ - unified data view - volume commands should work on Game Boy - macro editor menu -- refactor sysDef.cpp - - effect/postEffect refactor - add another FM editor layout - try to find out why does VSlider not accept keyboard input - finish lock layout @@ -36,7 +34,5 @@ - store edit/followOrders/followPattern state in config - add ability to select a column by double clicking - add ability to move selection by dragging -- settings: OK/Cancel buttons should be always visible - Apply button in settings -- better FM chip names (number and codename) - find and replace \ No newline at end of file diff --git a/papers/doc/7-systems/opl.md b/papers/doc/7-systems/opl.md index 056591a6d..683be51e6 100644 --- a/papers/doc/7-systems/opl.md +++ b/papers/doc/7-systems/opl.md @@ -71,9 +71,9 @@ afterwards everyone moved to Windows and software mixed PCM streaming... - `56xx`: set DR of all operators. - `57xx`: set DR of operator 1. - `58xx`: set DR of operator 2. -- `58xx`: set DR of operator 3. +- `59xx`: set DR of operator 3. - only in 4-op mode (OPL3). -- `58xx`: set DR of operator 4. +- `5Axx`: set DR of operator 4. - only in 4-op mode (OPL3). - `5Bxy`: set KSR of operator. - `x` is the operator (1-4; last 2 operators only in 4-op mode). a value of 0 means "all operators". diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index b28d880ad..9b906220d 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -233,15 +233,19 @@ struct DivRegWrite { }; struct DivDispatchOscBuffer { + bool follow; unsigned int rate; unsigned short needle; unsigned short readNeedle; + unsigned short followNeedle; short data[65536]; DivDispatchOscBuffer(): + follow(true), rate(65536), needle(0), - readNeedle(0) { + readNeedle(0), + followNeedle(0) { memset(data,0,65536*sizeof(short)); } }; diff --git a/src/engine/engine.h b/src/engine/engine.h index 4b2467be8..2669dddbe 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -26,6 +26,7 @@ #include "safeWriter.h" #include "../audio/taAudio.h" #include "blip_buf.h" +#include #include #include #include @@ -208,8 +209,8 @@ struct DivSysDef { std::initializer_list chTypes, std::initializer_list chInsType1, std::initializer_list chInsType2={}, - EffectProcess fxHandler=NULL, - EffectProcess postFxHandler=NULL): + EffectProcess fxHandler=[](int,unsigned char,unsigned char) -> bool {return false;}, + EffectProcess postFxHandler=[](int,unsigned char,unsigned char) -> bool {return false;}): name(sysName), nameJ(sysNameJ), id(fileID), @@ -418,6 +419,7 @@ class DivEngine { float oscSize; int oscReadPos, oscWritePos; int tickMult; + std::atomic processTime; void runExportThread(); void nextBuf(float** in, float** out, int inChans, int outChans, unsigned int size); @@ -925,7 +927,8 @@ class DivEngine { oscSize(1), oscReadPos(0), oscWritePos(0), - tickMult(1) { + tickMult(1), + processTime(0) { memset(isMuted,0,DIV_MAX_CHANS*sizeof(bool)); memset(keyHit,0,DIV_MAX_CHANS*sizeof(bool)); memset(dispatchChanOfChan,0,DIV_MAX_CHANS*sizeof(int)); diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 13308698c..5b823606b 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -25,7 +25,7 @@ #include #define rWrite(a,v) if (!skipRegisterWrites) {pendingWrites[a]=v;} -#define immWrite(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } +#define immWrite2(a,v) if (!skipRegisterWrites) {writes.emplace(a,v); if (dumpWrites) {addWrite(a,v);} } #define CHIP_DIVIDER 8 @@ -61,6 +61,18 @@ const char* regCheatSheetAY8930[]={ NULL }; +void DivPlatformAY8930::immWrite(unsigned char a, unsigned char v) { + if ((int)bank!=(a>>4)) { + bank=a>>4; + immWrite2(0x0d, 0xa0|(bank<<4)|ayEnvMode[0]); + } + if (a==0x0d) { + immWrite2(0x0d,0xa0|(bank<<4)|(v&15)); + } else { + immWrite2(a&15,v); + } +} + const char** DivPlatformAY8930::getRegisterSheet() { return regCheatSheetAY8930; } @@ -123,18 +135,13 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l } while (!writes.empty()) { QueuedWrite w=writes.front(); - if ((int)bank!=(w.addr>>4)) { - bank=w.addr>>4; - ay->address_w(0x0d); - ay->data_w(0xa0|(bank<<4)|ayEnvMode[0]); - } - ay->address_w(w.addr&15); - if (w.addr==0x0d) { - ay->data_w(0xa0|(bank<<4)|(w.val&15)); + ay->address_w(w.addr); + ay->data_w(w.val); + if (w.addr!=0x0d && (regPool[0x0d]&0xf0)==0xb0) { + regPool[(w.addr&0x0f)|0x10]=w.val; } else { - ay->data_w(w.val); + regPool[w.addr&0x0f]=w.val; } - regPool[w.addr&0x1f]=w.val; writes.pop(); } ay->sound_stream_update(ayBuf,len); diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index ff992bb5e..5f477e123 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -73,6 +73,7 @@ class DivPlatformAY8930: public DivDispatch { size_t ayBufLen; void updateOutSel(bool immediate=false); + void immWrite(unsigned char a, unsigned char v); friend void putDispatchChan(void*,int,int); diff --git a/src/engine/platform/es5506.cpp b/src/engine/platform/es5506.cpp index b0b53b094..a85a806ae 100644 --- a/src/engine/platform/es5506.cpp +++ b/src/engine/platform/es5506.cpp @@ -269,7 +269,7 @@ void DivPlatformES5506::tick(bool sysTick) { signed int k1=chan[i].k1Prev,k2=chan[i].k2Prev; // volume/panning macros if (chan[i].std.vol.had) { - const unsigned int nextVol=((chan[i].vol&0xff)*MIN(0xffff,chan[i].std.vol.val))/0xff; + const unsigned int nextVol=((chan[i].vol&0xff)*MIN(0xffff,(0xffff*chan[i].std.vol.val)/chan[i].volMacroMax))/0xff; if (chan[i].outVol!=nextVol) { chan[i].outVol=nextVol; if (!isMuted[i]) { @@ -278,7 +278,7 @@ void DivPlatformES5506::tick(bool sysTick) { } } if (chan[i].std.panL.had) { - const unsigned int nextLVol=(((ins->es5506.lVol*(chan[i].lVol&0xff))/0xff)*MIN(0xffff,chan[i].std.panL.val))/0xffff; + const unsigned int nextLVol=(((ins->es5506.lVol*(chan[i].lVol&0xff))/0xff)*MIN(0xffff,(0xffff*chan[i].std.panL.val)/chan[i].panMacroMax))/0xffff; if (chan[i].outLVol!=nextLVol) { chan[i].outLVol=nextLVol; if (!isMuted[i]) { @@ -287,7 +287,7 @@ void DivPlatformES5506::tick(bool sysTick) { } } if (chan[i].std.panR.had) { - const unsigned int nextRVol=(((ins->es5506.rVol*(chan[i].rVol&0xff))/0xff)*MIN(0xffff,chan[i].std.panR.val))/0xffff; + const unsigned int nextRVol=(((ins->es5506.rVol*(chan[i].rVol&0xff))/0xff)*MIN(0xffff,(0xffff*chan[i].std.panR.val)/chan[i].panMacroMax))/0xffff; if (chan[i].outRVol!=nextRVol) { chan[i].outRVol=nextRVol; if (!isMuted[i]) { @@ -644,11 +644,22 @@ int DivPlatformES5506::dispatch(DivCommand c) { chan[c.chan].pcm.length=length; chan[c.chan].pcm.loopStart=(start+(s->loopStart<<11))&0xfffff800; chan[c.chan].pcm.loopEnd=(start+((s->loopEnd-1)<<11))&0xffffff80; - chan[c.chan].filter=ins->es5506.filter; - chan[c.chan].envelope=ins->es5506.envelope; + if (ins->type==DIV_INS_ES5506) { // Native format + chan[c.chan].volMacroMax=0xffff; + chan[c.chan].panMacroMax=0xffff; + chan[c.chan].filter=ins->es5506.filter; + chan[c.chan].envelope=ins->es5506.envelope; + } else { // Amiga format + chan[c.chan].volMacroMax=64; + chan[c.chan].panMacroMax=127; + chan[c.chan].filter=DivInstrumentES5506::Filter(); + chan[c.chan].envelope=DivInstrumentES5506::Envelope(); + } } else { chan[c.chan].sample=-1; chan[c.chan].pcm.index=-1; + chan[c.chan].volMacroMax=0xffff; + chan[c.chan].panMacroMax=0xffff; chan[c.chan].filter=DivInstrumentES5506::Filter(); chan[c.chan].envelope=DivInstrumentES5506::Envelope(); } diff --git a/src/engine/platform/es5506.h b/src/engine/platform/es5506.h index 20b139ee7..67bb53725 100644 --- a/src/engine/platform/es5506.h +++ b/src/engine/platform/es5506.h @@ -56,6 +56,7 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { loopMode(DIV_SAMPLE_LOOPMODE_ONESHOT) {} } pcm; int freq, baseFreq, pitch, pitch2, note, ins, sample, wave; + unsigned int volMacroMax, panMacroMax; bool active, insChanged, freqChanged, pcmChanged, keyOn, keyOff, inPorta, useWave, isReverseLoop; struct VolChanged { // Volume changed flags @@ -135,6 +136,8 @@ class DivPlatformES5506: public DivDispatch, public es550x_intf { ins(-1), sample(-1), wave(-1), + volMacroMax(0xffff), + panMacroMax(0xffff), active(false), insChanged(true), freqChanged(false), diff --git a/src/engine/platform/sound/ymfm/ymfm_adpcm.cpp b/src/engine/platform/sound/ymfm/ymfm_adpcm.cpp index 01f35367c..76839e787 100644 --- a/src/engine/platform/sound/ymfm/ymfm_adpcm.cpp +++ b/src/engine/platform/sound/ymfm/ymfm_adpcm.cpp @@ -220,7 +220,7 @@ bool adpcm_a_channel::clock() //------------------------------------------------- template -void adpcm_a_channel::output(ymfm_output &output) const +void adpcm_a_channel::output(ymfm_output &output) { // volume combines instrument and total levels int vol = (m_regs.ch_instrument_level(m_choffs) ^ 0x1f) + (m_regs.total_level() ^ 0x3f); @@ -239,14 +239,18 @@ void adpcm_a_channel::output(ymfm_output &output) const int16_t value = ((int16_t(m_accumulator << 4) * mul) >> shift) & ~3; // apply to left/right as appropriate - if (NumOutputs == 1 || m_regs.ch_pan_left(m_choffs)) + if (NumOutputs == 1 || m_regs.ch_pan_left(m_choffs)) { output.data[0] += value; - if (NumOutputs > 1 && m_regs.ch_pan_right(m_choffs)) + m_lastOut[0] = value; + } + if (NumOutputs > 1 && m_regs.ch_pan_right(m_choffs)) { output.data[1] += value; + m_lastOut[1] = value; + } } -template void adpcm_a_channel::output<1>(ymfm_output<1> &output) const; -template void adpcm_a_channel::output<2>(ymfm_output<2> &output) const; +template void adpcm_a_channel::output<1>(ymfm_output<1> &output); +template void adpcm_a_channel::output<2>(ymfm_output<2> &output); //********************************************************* @@ -528,7 +532,7 @@ void adpcm_b_channel::clock() //------------------------------------------------- template -void adpcm_b_channel::output(ymfm_output &output, uint32_t rshift) const +void adpcm_b_channel::output(ymfm_output &output, uint32_t rshift) { // mask out some channels for debug purposes if ((debug::GLOBAL_ADPCM_B_CHANNEL_MASK & 1) == 0) @@ -541,10 +545,14 @@ void adpcm_b_channel::output(ymfm_output &output, uint32_t rshift) c result = (result * int32_t(m_regs.level())) >> (8 + rshift); // apply to left/right - if (NumOutputs == 1 || m_regs.pan_left()) + if (NumOutputs == 1 || m_regs.pan_left()) { + m_lastOut[0] = result; output.data[0] += result; - if (NumOutputs > 1 && m_regs.pan_right()) + } + if (NumOutputs > 1 && m_regs.pan_right()) { + m_lastOut[1] = result; output.data[1] += result; + } } diff --git a/src/engine/platform/sound/ymfm/ymfm_adpcm.h b/src/engine/platform/sound/ymfm/ymfm_adpcm.h index c08eeae59..58bee8a22 100644 --- a/src/engine/platform/sound/ymfm/ymfm_adpcm.h +++ b/src/engine/platform/sound/ymfm/ymfm_adpcm.h @@ -146,7 +146,10 @@ public: // return the computed output value, with panning applied template - void output(ymfm_output &output) const; + void output(ymfm_output &output); + + // return the last output + int32_t get_last_out(int ch) { return m_lastOut[ch]; } private: // internal state @@ -158,6 +161,7 @@ private: uint32_t m_curaddress; // current address int32_t m_accumulator; // accumulator int32_t m_step_index; // index in the stepping table + int32_t m_lastOut[2]; // last output adpcm_a_registers &m_regs; // reference to registers adpcm_a_engine &m_owner; // reference to our owner }; @@ -326,7 +330,7 @@ public: // return the computed output value, with panning applied template - void output(ymfm_output &output, uint32_t rshift) const; + void output(ymfm_output &output, uint32_t rshift); // return the status register uint8_t status() const { return m_status; } @@ -337,6 +341,9 @@ public: // handle special register writes void write(uint32_t regnum, uint8_t value); + // return the last output + int32_t get_last_out(int ch) { return m_lastOut[ch]; } + private: // helper - return the current address shift uint32_t address_shift() const; @@ -361,6 +368,7 @@ private: int32_t m_accumulator; // accumulator int32_t m_prev_accum; // previous accumulator (for linear interp) int32_t m_adpcm_step; // next forecast + int32_t m_lastOut[2]; // last output adpcm_b_registers &m_regs; // reference to registers adpcm_b_engine &m_owner; // reference to our owner }; @@ -387,6 +395,9 @@ public: template void output(ymfm_output &output, uint32_t rshift); + // get last output + int32_t get_last_out(int ch) { return m_channel->get_last_out(ch); } + // read from the ADPCM-B registers uint32_t read(uint32_t regnum) { return m_channel->read(regnum); } diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index f3cc8c1e1..601a75355 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -428,7 +428,15 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l ymfm::adpcm_b_engine* abe=fm->debug_adpcm_b_engine(); ymfm::ssg_engine::output_data ssgOut; - ymfm::ymfm_output<2> adpcmOut; + + ymfm::fm_channel>* fmChan[6]; + ymfm::adpcm_a_channel* adpcmAChan[6]; + for (int i=0; i<4; i++) { + fmChan[i]=fme->debug_channel(bchOffs[i]); + } + for (int i=0; i<6; i++) { + adpcmAChan[i]=aae->debug_channel(i); + } for (size_t h=start; hdata[oscBuf[i]->needle++]=(fme->debug_channel(ch)->debug_output(0)+fme->debug_channel(ch)->debug_output(1)); + oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1)); } ssge->get_last_out(ssgOut); @@ -467,14 +474,10 @@ void DivPlatformYM2610::acquire(short* bufL, short* bufR, size_t start, size_t l } for (int i=7; i<13; i++) { - adpcmOut.clear(); - aae->debug_channel(i-7)->output<2>(adpcmOut); - oscBuf[i]->data[oscBuf[i]->needle++]=adpcmOut.data[0]+adpcmOut.data[1]; + oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-7]->get_last_out(0)+adpcmAChan[i-7]->get_last_out(1); } - adpcmOut.clear(); - abe->output(adpcmOut,1); - oscBuf[13]->data[oscBuf[13]->needle++]=adpcmOut.data[0]+adpcmOut.data[1]; + oscBuf[13]->data[oscBuf[13]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); } } diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 7d3b6a9c8..4c2730df2 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -408,7 +408,13 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t ymfm::adpcm_b_engine* abe=fm->debug_adpcm_b_engine(); ymfm::ssg_engine::output_data ssgOut; - ymfm::ymfm_output<2> adpcmOut; + + ymfm::fm_channel>* fmChan[6]; + ymfm::adpcm_a_channel* adpcmAChan[6]; + for (int i=0; i<6; i++) { + fmChan[i]=fme->debug_channel(i); + adpcmAChan[i]=aae->debug_channel(i); + } for (size_t h=start; hdata[oscBuf[i]->needle++]=(fme->debug_channel(i)->debug_output(0)+fme->debug_channel(i)->debug_output(1)); + oscBuf[i]->data[oscBuf[i]->needle++]=(fmChan[i]->debug_output(0)+fmChan[i]->debug_output(1)); } ssge->get_last_out(ssgOut); @@ -446,14 +453,10 @@ void DivPlatformYM2610B::acquire(short* bufL, short* bufR, size_t start, size_t } for (int i=9; i<15; i++) { - adpcmOut.clear(); - aae->debug_channel(i-9)->output<2>(adpcmOut); - oscBuf[i]->data[oscBuf[i]->needle++]=adpcmOut.data[0]+adpcmOut.data[1]; + oscBuf[i]->data[oscBuf[i]->needle++]=adpcmAChan[i-9]->get_last_out(0)+adpcmAChan[i-9]->get_last_out(1); } - adpcmOut.clear(); - abe->output(adpcmOut,1); - oscBuf[15]->data[oscBuf[15]->needle++]=adpcmOut.data[0]+adpcmOut.data[1]; + oscBuf[15]->data[oscBuf[15]->needle++]=abe->get_last_out(0)+abe->get_last_out(1); } } diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index eb1ef1058..ff3926423 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #define _USE_MATH_DEFINES #include "dispatch.h" #include "engine.h" @@ -262,6 +263,7 @@ int DivEngine::dispatchCmd(DivCommand c) { } bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effectVal) { +<<<<<<< HEAD switch (sysOfChan[ch]) { case DIV_SYSTEM_YM2612: case DIV_SYSTEM_YM2612_EXT: @@ -599,391 +601,15 @@ bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effe return false; } return true; +======= + if (sysDefs[sysOfChan[ch]]==NULL) return false; + return sysDefs[sysOfChan[ch]]->effectFunc(ch,effect,effectVal); +>>>>>>> 4c9b172b50a240efc37aec8bdd4a59972fbf10c4 } -#define IS_YM2610 (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT || sysOfChan[ch]==DIV_SYSTEM_YM2610_FULL || sysOfChan[ch]==DIV_SYSTEM_YM2610_FULL_EXT || sysOfChan[ch]==DIV_SYSTEM_YM2610B || sysOfChan[ch]==DIV_SYSTEM_YM2610B_EXT) -#define IS_OPM_LIKE (sysOfChan[ch]==DIV_SYSTEM_YM2151 || sysOfChan[ch]==DIV_SYSTEM_OPZ) - bool DivEngine::perSystemPostEffect(int ch, unsigned char effect, unsigned char effectVal) { - switch (sysOfChan[ch]) { - case DIV_SYSTEM_YM2612: - case DIV_SYSTEM_YM2612_EXT: - case DIV_SYSTEM_YM2151: - case DIV_SYSTEM_YM2610: - case DIV_SYSTEM_YM2610_EXT: - case DIV_SYSTEM_YM2610_FULL: - case DIV_SYSTEM_YM2610_FULL_EXT: - case DIV_SYSTEM_YM2610B: - case DIV_SYSTEM_YM2610B_EXT: - case DIV_SYSTEM_OPZ: - switch (effect) { - case 0x10: // LFO or noise mode - if (IS_OPM_LIKE) { - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); - } else { - dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal)); - } - break; - case 0x11: // FB - dispatchCmd(DivCommand(DIV_CMD_FM_FB,ch,effectVal&7)); - break; - case 0x12: // TL op1 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,0,effectVal&0x7f)); - break; - case 0x13: // TL op2 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,1,effectVal&0x7f)); - break; - case 0x14: // TL op3 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,2,effectVal&0x7f)); - break; - case 0x15: // TL op4 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,3,effectVal&0x7f)); - break; - case 0x16: // MULT - if ((effectVal>>4)>0 && (effectVal>>4)<5) { - dispatchCmd(DivCommand(DIV_CMD_FM_MULT,ch,(effectVal>>4)-1,effectVal&15)); - } - break; - case 0x17: // arcade LFO - if (IS_OPM_LIKE) { - dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal)); - } - break; - case 0x18: // EXT or LFO waveform - if (IS_OPM_LIKE) { - dispatchCmd(DivCommand(DIV_CMD_FM_LFO_WAVE,ch,effectVal)); - } else { - dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal)); - } - break; - case 0x19: // AR global - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,-1,effectVal&31)); - break; - case 0x1a: // AR op1 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,0,effectVal&31)); - break; - case 0x1b: // AR op2 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,1,effectVal&31)); - break; - case 0x1c: // AR op3 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,2,effectVal&31)); - break; - case 0x1d: // AR op4 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,3,effectVal&31)); - break; - case 0x1e: // UNOFFICIAL: Arcade AM depth - dispatchCmd(DivCommand(DIV_CMD_FM_AM_DEPTH,ch,effectVal&127)); - break; - case 0x1f: // UNOFFICIAL: Arcade PM depth - dispatchCmd(DivCommand(DIV_CMD_FM_PM_DEPTH,ch,effectVal&127)); - break; - case 0x20: // Neo Geo PSG mode - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - } - break; - case 0x21: // Neo Geo PSG noise freq - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); - } - break; - case 0x22: // UNOFFICIAL: Neo Geo PSG envelope enable - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SET,ch,effectVal)); - } - break; - case 0x23: // UNOFFICIAL: Neo Geo PSG envelope period low - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_LOW,ch,effectVal)); - } - break; - case 0x24: // UNOFFICIAL: Neo Geo PSG envelope period high - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_HIGH,ch,effectVal)); - } - break; - case 0x25: // UNOFFICIAL: Neo Geo PSG envelope slide up - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,-effectVal)); - } - break; - case 0x26: // UNOFFICIAL: Neo Geo PSG envelope slide down - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,effectVal)); - } - break; - case 0x29: // auto-envelope - if (IS_YM2610) { - dispatchCmd(DivCommand(DIV_CMD_AY_AUTO_ENVELOPE,ch,effectVal)); - } - break; - default: - return false; - } - break; - case DIV_SYSTEM_OPLL: - case DIV_SYSTEM_OPLL_DRUMS: - case DIV_SYSTEM_VRC7: - switch (effect) { - case 0x11: // FB - dispatchCmd(DivCommand(DIV_CMD_FM_FB,ch,effectVal&7)); - break; - case 0x12: // TL op1 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,0,effectVal&0x3f)); - break; - case 0x13: // TL op2 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,1,effectVal&0x0f)); - break; - case 0x16: // MULT - if ((effectVal>>4)>0 && (effectVal>>4)<3) { - dispatchCmd(DivCommand(DIV_CMD_FM_MULT,ch,(effectVal>>4)-1,effectVal&15)); - } - break; - case 0x19: // AR global - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,-1,effectVal&31)); - break; - case 0x1a: // AR op1 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,0,effectVal&31)); - break; - case 0x1b: // AR op2 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,1,effectVal&31)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_OPL: - case DIV_SYSTEM_OPL2: - case DIV_SYSTEM_OPL3: - case DIV_SYSTEM_OPL_DRUMS: - case DIV_SYSTEM_OPL2_DRUMS: - case DIV_SYSTEM_OPL3_DRUMS: - switch (effect) { - case 0x10: // DAM - dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal&1)); - break; - case 0x11: // FB - dispatchCmd(DivCommand(DIV_CMD_FM_FB,ch,effectVal&7)); - break; - case 0x12: // TL op1 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,0,effectVal&0x3f)); - break; - case 0x13: // TL op2 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,1,effectVal&0x3f)); - break; - case 0x14: // TL op3 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,2,effectVal&0x3f)); - break; - case 0x15: // TL op4 - dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,3,effectVal&0x3f)); - break; - case 0x16: // MULT - if ((effectVal>>4)>0 && (effectVal>>4)<5) { - dispatchCmd(DivCommand(DIV_CMD_FM_MULT,ch,(effectVal>>4)-1,effectVal&15)); - } - break; - case 0x17: // DVB - dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,2+(effectVal&1))); - break; - case 0x19: // AR global - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,-1,effectVal&15)); - break; - case 0x1a: // AR op1 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,0,effectVal&15)); - break; - case 0x1b: // AR op2 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,1,effectVal&15)); - break; - case 0x1c: // AR op3 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,2,effectVal&15)); - break; - case 0x1d: // AR op4 - dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,3,effectVal&15)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_C64_6581: case DIV_SYSTEM_C64_8580: - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - case 0x11: // cutoff - dispatchCmd(DivCommand(DIV_CMD_C64_CUTOFF,ch,effectVal)); - break; - case 0x12: // duty - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x13: // resonance - dispatchCmd(DivCommand(DIV_CMD_C64_RESONANCE,ch,effectVal)); - break; - case 0x14: // filter mode - dispatchCmd(DivCommand(DIV_CMD_C64_FILTER_MODE,ch,effectVal)); - break; - case 0x15: // reset time - dispatchCmd(DivCommand(DIV_CMD_C64_RESET_TIME,ch,effectVal)); - break; - case 0x1a: // reset mask - dispatchCmd(DivCommand(DIV_CMD_C64_RESET_MASK,ch,effectVal)); - break; - case 0x1b: // cutoff reset - dispatchCmd(DivCommand(DIV_CMD_C64_FILTER_RESET,ch,effectVal)); - break; - case 0x1c: // duty reset - dispatchCmd(DivCommand(DIV_CMD_C64_DUTY_RESET,ch,effectVal)); - break; - case 0x1e: // extended - dispatchCmd(DivCommand(DIV_CMD_C64_EXTENDED,ch,effectVal)); - break; - case 0x30: case 0x31: case 0x32: case 0x33: - case 0x34: case 0x35: case 0x36: case 0x37: - case 0x38: case 0x39: case 0x3a: case 0x3b: - case 0x3c: case 0x3d: case 0x3e: case 0x3f: // fine duty - dispatchCmd(DivCommand(DIV_CMD_C64_FINE_DUTY,ch,((effect&0x0f)<<8)|effectVal)); - break; - case 0x40: case 0x41: case 0x42: case 0x43: - case 0x44: case 0x45: case 0x46: case 0x47: // fine cutoff - dispatchCmd(DivCommand(DIV_CMD_C64_FINE_CUTOFF,ch,((effect&0x07)<<8)|effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_AY8910: - case DIV_SYSTEM_AY8930: - switch (effect) { - case 0x12: // duty on 8930 - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,0x10+(effectVal&15))); - break; - case 0x20: // mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal&15)); - break; - case 0x21: // noise freq - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); - break; - case 0x22: // envelope enable - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SET,ch,effectVal)); - break; - case 0x23: // envelope period low - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_LOW,ch,effectVal)); - break; - case 0x24: // envelope period high - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_HIGH,ch,effectVal)); - break; - case 0x25: // envelope slide up - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,-effectVal)); - break; - case 0x26: // envelope slide down - dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,effectVal)); - break; - case 0x27: // noise and mask - dispatchCmd(DivCommand(DIV_CMD_AY_NOISE_MASK_AND,ch,effectVal)); - break; - case 0x28: // noise or mask - dispatchCmd(DivCommand(DIV_CMD_AY_NOISE_MASK_OR,ch,effectVal)); - break; - case 0x29: // auto-envelope - dispatchCmd(DivCommand(DIV_CMD_AY_AUTO_ENVELOPE,ch,effectVal)); - break; - case 0x2d: // TEST - dispatchCmd(DivCommand(DIV_CMD_AY_IO_WRITE,ch,255,effectVal)); - break; - case 0x2e: // I/O port A - dispatchCmd(DivCommand(DIV_CMD_AY_IO_WRITE,ch,0,effectVal)); - break; - case 0x2f: // I/O port B - dispatchCmd(DivCommand(DIV_CMD_AY_IO_WRITE,ch,1,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_SAA1099: - switch (effect) { - case 0x10: // select channel mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x11: // set noise freq - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); - break; - case 0x12: // setup envelope - dispatchCmd(DivCommand(DIV_CMD_SAA_ENVELOPE,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_TIA: - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_AMIGA: - switch (effect) { - case 0x10: // toggle filter - dispatchCmd(DivCommand(DIV_CMD_AMIGA_FILTER,ch,effectVal)); - break; - case 0x11: // toggle AM - dispatchCmd(DivCommand(DIV_CMD_AMIGA_AM,ch,effectVal)); - break; - case 0x12: // toggle PM - dispatchCmd(DivCommand(DIV_CMD_AMIGA_PM,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_SEGAPCM: - case DIV_SYSTEM_SEGAPCM_COMPAT: - switch (effect) { - case 0x20: // PCM frequency - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_LYNX: - if (effect>=0x30 && effect<0x40) { - int value = ((int)(effect&0x0f)<<8)|effectVal; - dispatchCmd(DivCommand(DIV_CMD_LYNX_LFSR_LOAD,ch,value)); - break; - } - return false; - break; - case DIV_SYSTEM_X1_010: - switch (effect) { - case 0x20: // PCM frequency - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal)); - break; - case 0x22: // envelope mode - dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_MODE,ch,effectVal)); - break; - case 0x23: // envelope period - dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_PERIOD,ch,effectVal)); - break; - case 0x25: // envelope slide up - dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_SLIDE,ch,effectVal)); - break; - case 0x26: // envelope slide down - dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_SLIDE,ch,-effectVal)); - break; - case 0x29: // auto-envelope - dispatchCmd(DivCommand(DIV_CMD_X1_010_AUTO_ENVELOPE,ch,effectVal)); - break; - default: - return false; - } - break; - default: - return false; - } - return true; + if (sysDefs[sysOfChan[ch]]==NULL) return false; + return sysDefs[sysOfChan[ch]]->postEffectFunc(ch,effect,effectVal); } void DivEngine::processRow(int i, bool afterDelay) { @@ -1787,6 +1413,8 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } got.bufsize=size; + std::chrono::steady_clock::time_point ts_processBegin=std::chrono::steady_clock::now(); + // process MIDI events (TODO: everything) if (output) if (output->midiIn) while (!output->midiIn->queue.empty()) { TAMidiMessage& msg=output->midiIn->queue.front(); @@ -2150,4 +1778,8 @@ void DivEngine::nextBuf(float** in, float** out, int inChans, int outChans, unsi } } isBusy.unlock(); + + std::chrono::steady_clock::time_point ts_processEnd=std::chrono::steady_clock::now(); + + processTime=std::chrono::duration_cast(ts_processEnd-ts_processBegin).count(); } diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index a7b9c736c..36331f70a 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -316,6 +316,9 @@ int DivEngine::minVGMVersion(DivSystem which) { return sysDefs[which]->vgmVersion; } +#define IS_YM2610 (sysOfChan[ch]==DIV_SYSTEM_YM2610 || sysOfChan[ch]==DIV_SYSTEM_YM2610_EXT || sysOfChan[ch]==DIV_SYSTEM_YM2610_FULL || sysOfChan[ch]==DIV_SYSTEM_YM2610_FULL_EXT || sysOfChan[ch]==DIV_SYSTEM_YM2610B || sysOfChan[ch]==DIV_SYSTEM_YM2610B_EXT) +#define IS_OPM_LIKE (sysOfChan[ch]==DIV_SYSTEM_YM2151 || sysOfChan[ch]==DIV_SYSTEM_OPZ) + // define systems like: // sysDefs[DIV_SYSTEM_ID]=new DivSysDef( // "Name", "Name (japanese, optional)", fileID, fileID_DMF, channels, isFM, isSTD, vgmVersion, @@ -331,8 +334,305 @@ int DivEngine::minVGMVersion(DivSystem which) { void DivEngine::registerSystems() { logD("registering systems..."); + auto fmPostEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // LFO or noise mode + if (IS_OPM_LIKE) { + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); + } else { + dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal)); + } + break; + case 0x11: // FB + dispatchCmd(DivCommand(DIV_CMD_FM_FB,ch,effectVal&7)); + break; + case 0x12: // TL op1 + dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,0,effectVal&0x7f)); + break; + case 0x13: // TL op2 + dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,1,effectVal&0x7f)); + break; + case 0x14: // TL op3 + dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,2,effectVal&0x7f)); + break; + case 0x15: // TL op4 + dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,3,effectVal&0x7f)); + break; + case 0x16: // MULT + if ((effectVal>>4)>0 && (effectVal>>4)<5) { + dispatchCmd(DivCommand(DIV_CMD_FM_MULT,ch,(effectVal>>4)-1,effectVal&15)); + } + break; + case 0x17: // arcade LFO + if (IS_OPM_LIKE) { + dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal)); + } + break; + case 0x18: // EXT or LFO waveform + if (IS_OPM_LIKE) { + dispatchCmd(DivCommand(DIV_CMD_FM_LFO_WAVE,ch,effectVal)); + } else { + dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal)); + } + break; + case 0x19: // AR global + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,-1,effectVal&31)); + break; + case 0x1a: // AR op1 + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,0,effectVal&31)); + break; + case 0x1b: // AR op2 + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,1,effectVal&31)); + break; + case 0x1c: // AR op3 + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,2,effectVal&31)); + break; + case 0x1d: // AR op4 + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,3,effectVal&31)); + break; + case 0x1e: // UNOFFICIAL: Arcade AM depth + dispatchCmd(DivCommand(DIV_CMD_FM_AM_DEPTH,ch,effectVal&127)); + break; + case 0x1f: // UNOFFICIAL: Arcade PM depth + dispatchCmd(DivCommand(DIV_CMD_FM_PM_DEPTH,ch,effectVal&127)); + break; + case 0x20: // Neo Geo PSG mode + if (IS_YM2610) { + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); + } + break; + case 0x21: // Neo Geo PSG noise freq + if (IS_YM2610) { + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); + } + break; + case 0x22: // UNOFFICIAL: Neo Geo PSG envelope enable + if (IS_YM2610) { + dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SET,ch,effectVal)); + } + break; + case 0x23: // UNOFFICIAL: Neo Geo PSG envelope period low + if (IS_YM2610) { + dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_LOW,ch,effectVal)); + } + break; + case 0x24: // UNOFFICIAL: Neo Geo PSG envelope period high + if (IS_YM2610) { + dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_HIGH,ch,effectVal)); + } + break; + case 0x25: // UNOFFICIAL: Neo Geo PSG envelope slide up + if (IS_YM2610) { + dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,-effectVal)); + } + break; + case 0x26: // UNOFFICIAL: Neo Geo PSG envelope slide down + if (IS_YM2610) { + dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,effectVal)); + } + break; + case 0x29: // auto-envelope + if (IS_YM2610) { + dispatchCmd(DivCommand(DIV_CMD_AY_AUTO_ENVELOPE,ch,effectVal)); + } + break; + default: + return false; + } + return true; + }; + + auto fmOPLLPostEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x11: // FB + dispatchCmd(DivCommand(DIV_CMD_FM_FB,ch,effectVal&7)); + break; + case 0x12: // TL op1 + dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,0,effectVal&0x3f)); + break; + case 0x13: // TL op2 + dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,1,effectVal&0x0f)); + break; + case 0x16: // MULT + if ((effectVal>>4)>0 && (effectVal>>4)<3) { + dispatchCmd(DivCommand(DIV_CMD_FM_MULT,ch,(effectVal>>4)-1,effectVal&15)); + } + break; + case 0x19: // AR global + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,-1,effectVal&31)); + break; + case 0x1a: // AR op1 + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,0,effectVal&31)); + break; + case 0x1b: // AR op2 + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,1,effectVal&31)); + break; + default: + return false; + } + return true; + }; + + auto fmOPLPostEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // DAM + dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,effectVal&1)); + break; + case 0x11: // FB + dispatchCmd(DivCommand(DIV_CMD_FM_FB,ch,effectVal&7)); + break; + case 0x12: // TL op1 + dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,0,effectVal&0x3f)); + break; + case 0x13: // TL op2 + dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,1,effectVal&0x3f)); + break; + case 0x14: // TL op3 + dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,2,effectVal&0x3f)); + break; + case 0x15: // TL op4 + dispatchCmd(DivCommand(DIV_CMD_FM_TL,ch,3,effectVal&0x3f)); + break; + case 0x16: // MULT + if ((effectVal>>4)>0 && (effectVal>>4)<5) { + dispatchCmd(DivCommand(DIV_CMD_FM_MULT,ch,(effectVal>>4)-1,effectVal&15)); + } + break; + case 0x17: // DVB + dispatchCmd(DivCommand(DIV_CMD_FM_LFO,ch,2+(effectVal&1))); + break; + case 0x19: // AR global + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,-1,effectVal&15)); + break; + case 0x1a: // AR op1 + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,0,effectVal&15)); + break; + case 0x1b: // AR op2 + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,1,effectVal&15)); + break; + case 0x1c: // AR op3 + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,2,effectVal&15)); + break; + case 0x1d: // AR op4 + dispatchCmd(DivCommand(DIV_CMD_FM_AR,ch,3,effectVal&15)); + break; + default: + return false; + } + return true; + }; + + auto c64PostEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // select waveform + dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); + break; + case 0x11: // cutoff + dispatchCmd(DivCommand(DIV_CMD_C64_CUTOFF,ch,effectVal)); + break; + case 0x12: // duty + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); + break; + case 0x13: // resonance + dispatchCmd(DivCommand(DIV_CMD_C64_RESONANCE,ch,effectVal)); + break; + case 0x14: // filter mode + dispatchCmd(DivCommand(DIV_CMD_C64_FILTER_MODE,ch,effectVal)); + break; + case 0x15: // reset time + dispatchCmd(DivCommand(DIV_CMD_C64_RESET_TIME,ch,effectVal)); + break; + case 0x1a: // reset mask + dispatchCmd(DivCommand(DIV_CMD_C64_RESET_MASK,ch,effectVal)); + break; + case 0x1b: // cutoff reset + dispatchCmd(DivCommand(DIV_CMD_C64_FILTER_RESET,ch,effectVal)); + break; + case 0x1c: // duty reset + dispatchCmd(DivCommand(DIV_CMD_C64_DUTY_RESET,ch,effectVal)); + break; + case 0x1e: // extended + dispatchCmd(DivCommand(DIV_CMD_C64_EXTENDED,ch,effectVal)); + break; + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: // fine duty + dispatchCmd(DivCommand(DIV_CMD_C64_FINE_DUTY,ch,((effect&0x0f)<<8)|effectVal)); + break; + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: // fine cutoff + dispatchCmd(DivCommand(DIV_CMD_C64_FINE_CUTOFF,ch,((effect&0x07)<<8)|effectVal)); + break; + default: + return false; + } + return true; + }; + + auto ayPostEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x12: // duty on 8930 + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,0x10+(effectVal&15))); + break; + case 0x20: // mode + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal&15)); + break; + case 0x21: // noise freq + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); + break; + case 0x22: // envelope enable + dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SET,ch,effectVal)); + break; + case 0x23: // envelope period low + dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_LOW,ch,effectVal)); + break; + case 0x24: // envelope period high + dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_HIGH,ch,effectVal)); + break; + case 0x25: // envelope slide up + dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,-effectVal)); + break; + case 0x26: // envelope slide down + dispatchCmd(DivCommand(DIV_CMD_AY_ENVELOPE_SLIDE,ch,effectVal)); + break; + case 0x27: // noise and mask + dispatchCmd(DivCommand(DIV_CMD_AY_NOISE_MASK_AND,ch,effectVal)); + break; + case 0x28: // noise or mask + dispatchCmd(DivCommand(DIV_CMD_AY_NOISE_MASK_OR,ch,effectVal)); + break; + case 0x29: // auto-envelope + dispatchCmd(DivCommand(DIV_CMD_AY_AUTO_ENVELOPE,ch,effectVal)); + break; + case 0x2d: // TEST + dispatchCmd(DivCommand(DIV_CMD_AY_IO_WRITE,ch,255,effectVal)); + break; + case 0x2e: // I/O port A + dispatchCmd(DivCommand(DIV_CMD_AY_IO_WRITE,ch,0,effectVal)); + break; + case 0x2f: // I/O port B + dispatchCmd(DivCommand(DIV_CMD_AY_IO_WRITE,ch,1,effectVal)); + break; + default: + return false; + } + return true; + }; + + auto segaPCMPostEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x20: // PCM frequency + dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal)); + break; + default: + return false; + } + return true; + }; + sysDefs[DIV_SYSTEM_YMU759]=new DivSysDef( - "Yamaha YMU759", NULL, 0x01, 0x01, 17, true, false, 0, false, + "Yamaha YMU759 (MA-2)", NULL, 0x01, 0x01, 17, true, false, 0, false, {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "PCM" }, // name {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "PCM" }, // short {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PCM }, // type @@ -354,7 +654,18 @@ void DivEngine::registerSystems() { {"Square 1", "Square 2", "Square 3", "Noise"}, {"S1", "S2", "S3", "NO"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE}, - {DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD} + {DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD}, + {}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x20: // SN noise mode + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_SMS_OPLL]=new DivSysDef( @@ -367,7 +678,27 @@ void DivEngine::registerSystems() { {"Pulse 1", "Pulse 2", "Wavetable", "Noise"}, {"S1", "S2", "WA", "NO"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE}, - {DIV_INS_GB, DIV_INS_GB, DIV_INS_GB, DIV_INS_GB} + {DIV_INS_GB, DIV_INS_GB, DIV_INS_GB, DIV_INS_GB}, + {}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // select waveform + dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); + break; + case 0x11: case 0x12: // duty or noise mode + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); + break; + case 0x13: // sweep params + dispatchCmd(DivCommand(DIV_CMD_GB_SWEEP_TIME,ch,effectVal)); + break; + case 0x14: // sweep direction + dispatchCmd(DivCommand(DIV_CMD_GB_SWEEP_DIR,ch,effectVal)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_PCE]=new DivSysDef( @@ -376,7 +707,29 @@ void DivEngine::registerSystems() { {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6"}, {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE, DIV_INS_PCE}, - {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // select waveform + dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); + break; + case 0x11: // noise mode + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); + break; + case 0x12: // LFO mode + dispatchCmd(DivCommand(DIV_CMD_PCE_LFO_MODE,ch,effectVal)); + break; + case 0x13: // LFO speed + dispatchCmd(DivCommand(DIV_CMD_PCE_LFO_SPEED,ch,effectVal)); + break; + case 0x17: // PCM enable + dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_NES]=new DivSysDef( @@ -384,7 +737,30 @@ void DivEngine::registerSystems() { {"Pulse 1", "Pulse 2", "Triangle", "Noise", "PCM"}, {"S1", "S2", "TR", "NO", "PCM"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE, DIV_CH_NOISE, DIV_CH_PCM}, - {DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA} + {DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA}, + {}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x11: // DMC write + dispatchCmd(DivCommand(DIV_CMD_NES_DMC,ch,effectVal)); + break; + case 0x12: // duty or noise mode + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); + break; + case 0x13: // sweep up + dispatchCmd(DivCommand(DIV_CMD_NES_SWEEP,ch,0,effectVal)); + break; + case 0x14: // sweep down + dispatchCmd(DivCommand(DIV_CMD_NES_SWEEP,ch,1,effectVal)); + break; + case 0x18: // DPCM mode + dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,effectVal)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_NES_VRC7]=new DivSysDef( @@ -402,7 +778,10 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3"}, {"CH1", "CH2", "CH3"}, {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_C64, DIV_INS_C64, DIV_INS_C64} + {DIV_INS_C64, DIV_INS_C64, DIV_INS_C64}, + {}, + [](int,unsigned char,unsigned char) -> bool {return false;}, + c64PostEffectHandler ); sysDefs[DIV_SYSTEM_C64_8580]=new DivSysDef( @@ -410,7 +789,10 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3"}, {"CH1", "CH2", "CH3"}, {DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_C64, DIV_INS_C64, DIV_INS_C64} + {DIV_INS_C64, DIV_INS_C64, DIV_INS_C64}, + {}, + [](int,unsigned char,unsigned char) -> bool {return false;}, + c64PostEffectHandler ); sysDefs[DIV_SYSTEM_ARCADE]=new DivSysDef( @@ -418,12 +800,26 @@ void DivEngine::registerSystems() { {}, {}, {}, {} ); + auto fmHardResetEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x30: // toggle hard-reset + dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); + break; + default: + return false; + } + return true; + }; + sysDefs[DIV_SYSTEM_YM2610]=new DivSysDef( "Neo Geo CD", NULL, 0x09, 0x09, 13, true, true, 0x151, false, {"FM 1", "FM 2", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6"}, {"F1", "F2", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + {}, + fmHardResetEffectHandler, + fmPostEffectHandler ); sysDefs[DIV_SYSTEM_YM2610_EXT]=new DivSysDef( @@ -431,7 +827,10 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2 OP1", "FM 2 OP2", "FM 2 OP3", "FM 2 OP4", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6"}, {"F1", "O1", "O2", "O3", "O4", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6"}, {DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + {}, + fmHardResetEffectHandler, + fmPostEffectHandler ); sysDefs[DIV_SYSTEM_AY8910]=new DivSysDef( @@ -439,7 +838,10 @@ void DivEngine::registerSystems() { {"PSG 1", "PSG 2", "PSG 3"}, {"S1", "S2", "S3"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, - {DIV_INS_AY, DIV_INS_AY, DIV_INS_AY} + {DIV_INS_AY, DIV_INS_AY, DIV_INS_AY}, + {}, + [](int,unsigned char,unsigned char) -> bool {return false;}, + ayPostEffectHandler ); sysDefs[DIV_SYSTEM_AMIGA]=new DivSysDef( @@ -447,24 +849,61 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4"}, {"CH1", "CH2", "CH3", "CH4"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + {}, + [](int,unsigned char,unsigned char) -> bool {return false;}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // toggle filter + dispatchCmd(DivCommand(DIV_CMD_AMIGA_FILTER,ch,effectVal)); + break; + case 0x11: // toggle AM + dispatchCmd(DivCommand(DIV_CMD_AMIGA_AM,ch,effectVal)); + break; + case 0x12: // toggle PM + dispatchCmd(DivCommand(DIV_CMD_AMIGA_PM,ch,effectVal)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_YM2151]=new DivSysDef( - "Yamaha YM2151", NULL, 0x82, 0, 8, true, false, 0x150, false, + "Yamaha YM2151 (OPM)", NULL, 0x82, 0, 8, true, false, 0x150, false, {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM} + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM}, + {}, + fmHardResetEffectHandler, + fmPostEffectHandler ); + auto opn2EffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x17: // DAC enable + dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); + break; + case 0x30: // toggle hard-reset + dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); + break; + default: + return false; + } + return true; + }; + sysDefs[DIV_SYSTEM_YM2612]=new DivSysDef( - "Yamaha YM2612", NULL, 0x83, 0, 6, true, false, 0x150, false, + "Yamaha YM2612 (OPN2)", NULL, 0x83, 0, 6, true, false, 0x150, false, {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6"}, {"F1", "F2", "F3", "F4", "F5", "F6"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM}, - {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA} + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, + opn2EffectHandler, + fmPostEffectHandler ); sysDefs[DIV_SYSTEM_TIA]=new DivSysDef( @@ -472,7 +911,19 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2"}, {"CH1", "CH2"}, {DIV_CH_WAVE, DIV_CH_WAVE}, - {DIV_INS_TIA, DIV_INS_TIA} + {DIV_INS_TIA, DIV_INS_TIA}, + {}, + [](int,unsigned char,unsigned char) -> bool {return false;}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // select waveform + dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_SAA1099]=new DivSysDef( @@ -480,7 +931,25 @@ void DivEngine::registerSystems() { {"PSG 1", "PSG 2", "PSG 3", "PSG 4", "PSG 5", "PSG 6"}, {"S1", "S2", "S3", "S4", "S5", "S6"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, - {DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099} + {DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099, DIV_INS_SAA1099}, + {}, + [](int,unsigned char,unsigned char) -> bool {return false;}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // select channel mode + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); + break; + case 0x11: // set noise freq + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_FREQ,ch,effectVal)); + break; + case 0x12: // setup envelope + dispatchCmd(DivCommand(DIV_CMD_SAA_ENVELOPE,ch,effectVal)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_AY8930]=new DivSysDef( @@ -488,15 +957,31 @@ void DivEngine::registerSystems() { {"PSG 1", "PSG 2", "PSG 3"}, {"S1", "S2", "S3"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, - {DIV_INS_AY8930, DIV_INS_AY8930, DIV_INS_AY8930} + {DIV_INS_AY8930, DIV_INS_AY8930, DIV_INS_AY8930}, + {}, + [](int,unsigned char,unsigned char) -> bool {return false;}, + ayPostEffectHandler ); + auto waveOnlyEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // select waveform + dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); + break; + default: + return false; + } + return true; + }; + sysDefs[DIV_SYSTEM_VIC20]=new DivSysDef( "Commodore VIC-20", NULL, 0x85, 0, 4, false, true, 0, false, {"Low", "Mid", "High", "Noise"}, {"LO", "MID", "HI", "NO"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE}, - {DIV_INS_VIC, DIV_INS_VIC, DIV_INS_VIC, DIV_INS_VIC} + {DIV_INS_VIC, DIV_INS_VIC, DIV_INS_VIC, DIV_INS_VIC}, + {}, + waveOnlyEffectHandler ); sysDefs[DIV_SYSTEM_PET]=new DivSysDef( @@ -504,7 +989,9 @@ void DivEngine::registerSystems() { {"Wave"}, {"PET"}, {DIV_CH_PULSE}, - {DIV_INS_PET} + {DIV_INS_PET}, + {}, + waveOnlyEffectHandler ); sysDefs[DIV_SYSTEM_SNES]=new DivSysDef( @@ -521,15 +1008,42 @@ void DivEngine::registerSystems() { {"V1", "V2", "VS"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_WAVE}, {DIV_INS_VRC6, DIV_INS_VRC6, DIV_INS_VRC6_SAW}, - {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_NULL} + {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_NULL}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x12: // duty or noise mode + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); + break; + case 0x17: // PCM enable + dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); + break; + default: + return false; + } + return true; + } ); + auto oplEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x30: // toggle hard-reset + dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); + break; + default: + return false; + } + return true; + }; + sysDefs[DIV_SYSTEM_OPLL]=new DivSysDef( - "Yamaha OPLL", NULL, 0x89, 0, 9, true, false, 0x150, false, + "Yamaha YM2413 (OPLL)", NULL, 0x89, 0, 9, true, false, 0x150, false, {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL} + {DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL}, + {}, + oplEffectHandler, + fmOPLLPostEffectHandler ); sysDefs[DIV_SYSTEM_FDS]=new DivSysDef( @@ -537,7 +1051,33 @@ void DivEngine::registerSystems() { {"FDS"}, {"FDS"}, {DIV_CH_WAVE}, - {DIV_INS_FDS} + {DIV_INS_FDS}, + {}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // select waveform + dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); + break; + case 0x11: // modulation depth + dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_DEPTH,ch,effectVal)); + break; + case 0x12: // modulation enable/high + dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_HIGH,ch,effectVal)); + break; + case 0x13: // modulation low + dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_LOW,ch,effectVal)); + break; + case 0x14: // modulation pos + dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_POS,ch,effectVal)); + break; + case 0x15: // modulation wave + dispatchCmd(DivCommand(DIV_CMD_FDS_MOD_WAVE,ch,effectVal)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_MMC5]=new DivSysDef( @@ -545,7 +1085,21 @@ void DivEngine::registerSystems() { {"Pulse 1", "Pulse 2", "PCM"}, {"S1", "S2", "PCM"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM}, - {DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA} + {DIV_INS_STD, DIV_INS_STD, DIV_INS_AMIGA}, + {}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x11: // DMC write + dispatchCmd(DivCommand(DIV_CMD_NES_DMC,ch,effectVal)); + break; + case 0x12: // duty or noise mode + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_N163]=new DivSysDef( @@ -553,11 +1107,58 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8"}, {"CH1", "CH2", "CH3", "CH4", "CH5", "CH6", "CH7", "CH8"}, {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, - {DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163} + {DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163, DIV_INS_N163}, + {}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // select instrument waveform + dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); + break; + case 0x11: // select instrument waveform position in RAM + dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_POSITION,ch,effectVal)); + break; + case 0x12: // select instrument waveform length in RAM + dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LENGTH,ch,effectVal)); + break; + case 0x13: // change instrument waveform update mode + dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_MODE,ch,effectVal)); + break; + case 0x14: // select waveform for load to RAM + dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LOAD,ch,effectVal)); + break; + case 0x15: // select waveform position for load to RAM + dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LOADPOS,ch,effectVal)); + break; + case 0x16: // select waveform length for load to RAM + dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LOADLEN,ch,effectVal)); + break; + case 0x17: // change waveform load mode + dispatchCmd(DivCommand(DIV_CMD_N163_WAVE_LOADMODE,ch,effectVal)); + break; + case 0x18: // change channel limits + dispatchCmd(DivCommand(DIV_CMD_N163_CHANNEL_LIMIT,ch,effectVal)); + break; + case 0x20: // (global) select waveform for load to RAM + dispatchCmd(DivCommand(DIV_CMD_N163_GLOBAL_WAVE_LOAD,ch,effectVal)); + break; + case 0x21: // (global) select waveform position for load to RAM + dispatchCmd(DivCommand(DIV_CMD_N163_GLOBAL_WAVE_LOADPOS,ch,effectVal)); + break; + case 0x22: // (global) select waveform length for load to RAM + dispatchCmd(DivCommand(DIV_CMD_N163_GLOBAL_WAVE_LOADLEN,ch,effectVal)); + break; + case 0x23: // (global) change waveform load mode + dispatchCmd(DivCommand(DIV_CMD_N163_GLOBAL_WAVE_LOADMODE,ch,effectVal)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_OPN]=new DivSysDef( - "Yamaha YM2203", NULL, 0x8d, 0, 6, true, false, 0, false, + "Yamaha YM2203 (OPN)", NULL, 0x8d, 0, 6, true, false, 0, false, {"FM 1", "FM 2", "FM 3", "PSG 1", "PSG 2", "PSG 3"}, {"F1", "F2", "F3", "S1", "S2", "S3"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE}, @@ -565,7 +1166,7 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_PC98]=new DivSysDef( - "Yamaha YM2608", NULL, 0x8e, 0, 16, true, false, 0, false, + "Yamaha YM2608 (OPNA)", NULL, 0x8e, 0, 16, true, false, 0, false, {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Square 1", "Square 2", "Square 3", "Kick", "Snare", "Top", "HiHat", "Tom", "Rim", "ADPCM"}, {"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "BD", "SD", "TP", "HH", "TM", "RM", "P"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_PCM}, @@ -573,27 +1174,36 @@ void DivEngine::registerSystems() { ); sysDefs[DIV_SYSTEM_OPL]=new DivSysDef( - "Yamaha OPL", NULL, 0x8f, 0, 9, true, false, 0x151, false, + "Yamaha YM3526 (OPL)", NULL, 0x8f, 0, 9, true, false, 0x151, false, {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL} + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, + {}, + oplEffectHandler, + fmOPLPostEffectHandler ); sysDefs[DIV_SYSTEM_OPL2]=new DivSysDef( - "Yamaha OPL2", NULL, 0x90, 0, 9, true, false, 0x151, false, + "Yamaha YM3812 (OPL2)", NULL, 0x90, 0, 9, true, false, 0x151, false, {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8", "FM 9"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL} + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, + {}, + oplEffectHandler, + fmOPLPostEffectHandler ); sysDefs[DIV_SYSTEM_OPL3]=new DivSysDef( - "Yamaha OPL3", NULL, 0x91, 0, 18, true, false, 0x151, false, + "Yamaha YMF262 (OPL3)", NULL, 0x91, 0, 18, true, false, 0x151, false, {"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "FM 16", "FM 17", "FM 18"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18"}, {DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL} + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, + {}, + oplEffectHandler, + fmOPLPostEffectHandler ); sysDefs[DIV_SYSTEM_MULTIPCM]=new DivSysDef( @@ -634,15 +1244,49 @@ void DivEngine::registerSystems() { {"CH1", "CH2", "CH3", "CH4"}, {DIV_CH_WAVE, DIV_CH_PCM, DIV_CH_WAVE, DIV_CH_NOISE}, {DIV_INS_SWAN, DIV_INS_SWAN, DIV_INS_SWAN, DIV_INS_SWAN}, - {DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_NULL, DIV_INS_NULL} + {DIV_INS_NULL, DIV_INS_AMIGA, DIV_INS_NULL, DIV_INS_NULL}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // select waveform + dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); + break; + case 0x11: // noise mode + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); + break; + case 0x12: // sweep period + dispatchCmd(DivCommand(DIV_CMD_WS_SWEEP_TIME,ch,effectVal)); + break; + case 0x13: // sweep amount + dispatchCmd(DivCommand(DIV_CMD_WS_SWEEP_AMOUNT,ch,effectVal)); + break; + case 0x17: // PCM enable + dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_OPZ]=new DivSysDef( - "Yamaha TX81Z/YS200", NULL, 0x98, 0, 8, true, false, 0, false, + "Yamaha YM2414 (OPZ)", NULL, 0x98, 0, 8, true, false, 0, false, {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "FM 7", "FM 8"}, {"F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ} + {DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ, DIV_INS_OPZ}, + {}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x2f: // toggle hard-reset + dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); + break; + default: + return false; + } + return true; + }, + fmPostEffectHandler ); sysDefs[DIV_SYSTEM_POKEMINI]=new DivSysDef( @@ -658,7 +1302,10 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + {}, + [](int,unsigned char,unsigned char) -> bool {return false;}, + segaPCMPostEffectHandler ); sysDefs[DIV_SYSTEM_VBOY]=new DivSysDef( @@ -674,15 +1321,21 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6"}, {"F1", "F2", "F3", "F4", "F5", "F6"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, - {DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL} + {DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL}, + {}, + oplEffectHandler, + fmOPLLPostEffectHandler ); sysDefs[DIV_SYSTEM_YM2610B]=new DivSysDef( - "Yamaha YM2610B", NULL, 0x9e, 0, 16, true, false, 0x151, false, + "Yamaha YM2610B (OPNB-B)", NULL, 0x9e, 0, 16, true, false, 0x151, false, {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "F2", "F3", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + {}, + fmHardResetEffectHandler, + fmPostEffectHandler ); sysDefs[DIV_SYSTEM_SFX_BEEPER]=new DivSysDef( @@ -699,7 +1352,9 @@ void DivEngine::registerSystems() { {"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM}, {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM}, - {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA} + {DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_NULL, DIV_INS_AMIGA}, + opn2EffectHandler, + fmPostEffectHandler ); sysDefs[DIV_SYSTEM_SCC]=new DivSysDef( @@ -710,12 +1365,29 @@ void DivEngine::registerSystems() { {DIV_INS_SCC, DIV_INS_SCC, DIV_INS_SCC, DIV_INS_SCC, DIV_INS_SCC} ); + auto oplDrumsEffectHandler=[this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x18: // drum mode toggle + dispatchCmd(DivCommand(DIV_CMD_FM_EXTCH,ch,effectVal)); + break; + case 0x30: // toggle hard-reset + dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); + break; + default: + return false; + } + return true; + }; + sysDefs[DIV_SYSTEM_OPL_DRUMS]=new DivSysDef( "Yamaha OPL with drums", NULL, 0xa2, 0, 11, true, false, 0x151, false, {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat"}, {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL} + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, + {}, + oplDrumsEffectHandler, + fmOPLPostEffectHandler ); sysDefs[DIV_SYSTEM_OPL2_DRUMS]=new DivSysDef( @@ -723,7 +1395,10 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat"}, {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL} + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, + {}, + oplDrumsEffectHandler, + fmOPLPostEffectHandler ); sysDefs[DIV_SYSTEM_OPL3_DRUMS]=new DivSysDef( @@ -731,15 +1406,21 @@ void DivEngine::registerSystems() { {"4OP 1", "FM 2", "4OP 3", "FM 4", "4OP 5", "FM 6", "4OP 7", "FM 8", "4OP 9", "FM 10", "4OP 11", "FM 12", "FM 13", "FM 14", "FM 15", "Kick", "Snare", "Tom", "Top", "HiHat"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "BD", "SD", "TM", "TP", "HH"}, {DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL} + {DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL, DIV_INS_OPL}, + {}, + oplDrumsEffectHandler, + fmOPLPostEffectHandler ); sysDefs[DIV_SYSTEM_YM2610_FULL]=new DivSysDef( - "Yamaha YM2610", NULL, 0xa5, 0, 14, true, false, 0x151, false, + "Yamaha YM2610 (OPNB)", NULL, 0xa5, 0, 14, true, false, 0x151, false, {"FM 1", "FM 2", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "F2", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + {}, + fmHardResetEffectHandler, + fmPostEffectHandler ); sysDefs[DIV_SYSTEM_YM2610_FULL_EXT]=new DivSysDef( @@ -747,7 +1428,10 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2 OP1", "FM 2 OP2", "FM 2 OP3", "FM 2 OP4", "FM 3", "FM 4", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "O1", "O2", "O3", "O4", "F3", "F4", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + {}, + fmHardResetEffectHandler, + fmPostEffectHandler ); sysDefs[DIV_SYSTEM_OPLL_DRUMS]=new DivSysDef( @@ -755,7 +1439,10 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3", "FM 4", "FM 5", "FM 6", "Kick", "Snare", "Tom", "Top", "HiHat"}, {"F1", "F2", "F3", "F4", "F5", "F6", "BD", "SD", "TM", "TP", "HH"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL} + {DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL, DIV_INS_OPLL}, + {}, + oplDrumsEffectHandler, + fmOPLLPostEffectHandler ); sysDefs[DIV_SYSTEM_LYNX]=new DivSysDef( @@ -763,7 +1450,17 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4"}, {"CH1", "CH2", "CH3", "CH4"}, {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, - {DIV_INS_MIKEY, DIV_INS_MIKEY, DIV_INS_MIKEY, DIV_INS_MIKEY} + {DIV_INS_MIKEY, DIV_INS_MIKEY, DIV_INS_MIKEY, DIV_INS_MIKEY}, + {}, + [](int,unsigned char,unsigned char) -> bool {return false;}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + if (effect>=0x30 && effect<0x40) { + int value=((int)(effect&0x0f)<<8)|effectVal; + dispatchCmd(DivCommand(DIV_CMD_LYNX_LFSR_LOAD,ch,value)); + return true; + } + return false; + } ); sysDefs[DIV_SYSTEM_QSOUND]=new DivSysDef( @@ -771,7 +1468,29 @@ void DivEngine::registerSystems() { {"PCM 1", "PCM 2", "PCM 3", "PCM 4", "PCM 5", "PCM 6", "PCM 7", "PCM 8", "PCM 9", "PCM 10", "PCM 11", "PCM 12", "PCM 13", "PCM 14", "PCM 15", "PCM 16", "ADPCM 1", "ADPCM 2", "ADPCM 3"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "A1", "A2", "A3"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_NOISE, DIV_CH_NOISE, DIV_CH_NOISE}, - {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + {}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // echo feedback + dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_FEEDBACK,ch,effectVal)); + break; + case 0x11: // echo level + dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_LEVEL,ch,effectVal)); + break; + case 0x12: // surround + dispatchCmd(DivCommand(DIV_CMD_QSOUND_SURROUND,ch,effectVal)); + break; + default: + if ((effect&0xf0)==0x30) { + dispatchCmd(DivCommand(DIV_CMD_QSOUND_ECHO_DELAY,ch,((effect & 0x0f) << 8) | effectVal)); + } else { + return false; + } + break; + } + return true; + } ); sysDefs[DIV_SYSTEM_VERA]=new DivSysDef( @@ -779,7 +1498,21 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "PCM"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "PCM"}, {DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM}, - {DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_AMIGA} + {DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_VERA, DIV_INS_AMIGA}, + {}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x20: // select waveform + dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); + break; + case 0x22: // duty + dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_YM2610B_EXT]=new DivSysDef( @@ -787,7 +1520,10 @@ void DivEngine::registerSystems() { {"FM 1", "FM 2", "FM 3 OP1", "FM 3 OP2", "FM 3 OP3", "FM 3 OP4", "FM 4", "FM 5", "FM 6", "PSG 1", "PSG 2", "PSG 3", "ADPCM-A 1", "ADPCM-A 2", "ADPCM-A 3", "ADPCM-A 4", "ADPCM-A 5", "ADPCM-A 6", "ADPCM-B"}, {"F1", "F2", "O1", "O2", "O3", "O4", "F4", "F5", "F6", "S1", "S2", "S3", "P1", "P2", "P3", "P4", "P5", "P6", "B"}, {DIV_CH_FM, DIV_CH_FM, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_OP, DIV_CH_FM, DIV_CH_FM, DIV_CH_FM, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PULSE, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_FM, DIV_INS_AY, DIV_INS_AY, DIV_INS_AY, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + {}, + fmHardResetEffectHandler, + fmPostEffectHandler ); sysDefs[DIV_SYSTEM_SEGAPCM_COMPAT]=new DivSysDef( @@ -795,7 +1531,10 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5"}, {"P1", "P2", "P3", "P4", "P5"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + {}, + [](int,unsigned char,unsigned char) -> bool {return false;}, + segaPCMPostEffectHandler ); sysDefs[DIV_SYSTEM_X1_010]=new DivSysDef( @@ -804,7 +1543,48 @@ void DivEngine::registerSystems() { {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16"}, {DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE, DIV_CH_WAVE}, {DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010, DIV_INS_X1_010}, - {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA} + {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // select waveform + dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); + break; + case 0x11: // select envelope shape + dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_SHAPE,ch,effectVal)); + break; + case 0x17: // PCM enable + dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); + break; + default: + return false; + } + return true; + }, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x20: // PCM frequency + dispatchCmd(DivCommand(DIV_CMD_SAMPLE_FREQ,ch,effectVal)); + break; + case 0x22: // envelope mode + dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_MODE,ch,effectVal)); + break; + case 0x23: // envelope period + dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_PERIOD,ch,effectVal)); + break; + case 0x25: // envelope slide up + dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_SLIDE,ch,effectVal)); + break; + case 0x26: // envelope slide down + dispatchCmd(DivCommand(DIV_CMD_X1_010_ENVELOPE_SLIDE,ch,-effectVal)); + break; + case 0x29: // auto-envelope + dispatchCmd(DivCommand(DIV_CMD_X1_010_AUTO_ENVELOPE,ch,effectVal)); + break; + default: + return false; + } + return true; + } ); sysDefs[DIV_SYSTEM_BUBSYS_WSG]=new DivSysDef( @@ -812,7 +1592,9 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2"}, {"CH1", "CH2"}, {DIV_CH_WAVE, DIV_CH_WAVE}, - {DIV_INS_SCC, DIV_INS_SCC} + {DIV_INS_SCC, DIV_INS_SCC}, + {}, + waveOnlyEffectHandler ); // to Grauw: feel free to change this to 24 during development of OPL4's PCM part. @@ -837,7 +1619,53 @@ void DivEngine::registerSystems() { {"Channel 1", "Channel 2", "Channel 3", "Channel 4", "Channel 5", "Channel 6", "Channel 7", "Channel 8", "Channel 9", "Channel 10", "Channel 11", "Channel 12", "Channel 13", "Channel 14", "Channel 15", "Channel 16", "Channel 17", "Channel 18", "Channel 19", "Channel 20", "Channel 21", "Channel 22", "Channel 23", "Channel 24", "Channel 25", "Channel 26", "Channel 27", "Channel 28", "Channel 29", "Channel 30", "Channel 31", "Channel 32"}, {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32"}, {DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM, DIV_CH_PCM}, - {DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506} + {DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506, DIV_INS_ES5506}, + {DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA, DIV_INS_AMIGA}, + [this](int ch, unsigned char effect, unsigned char effectVal) -> bool { + switch (effect) { + case 0x10: // select waveform + dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); + break; + case 0x11: // filter mode + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_MODE,ch,effectVal&3)); + break; + case 0x20: + case 0x21: // envelope ECOUNT + dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_COUNT,ch,((effect&0x01)<<8)|effectVal)); + break; + case 0x22: // envelope LVRAMP + dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_LVRAMP,ch,effectVal)); + break; + case 0x23: // envelope RVRAMP + dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_RVRAMP,ch,effectVal)); + break; + case 0x24: + case 0x25: // envelope K1RAMP + dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_K1RAMP,ch,effectVal,effect&0x01)); + break; + case 0x26: + case 0x27: // envelope K2RAMP + dispatchCmd(DivCommand(DIV_CMD_ES5506_ENVELOPE_K2RAMP,ch,effectVal,effect&0x01)); + break; + case 0x28: // filter K1 slide up + case 0x29: // filter K1 slide down + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K1_SLIDE,ch,effectVal,effect&0x01)); + break; + case 0x2a: // filter K2 slide up + case 0x2b: // filter K2 slide down + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K2_SLIDE,ch,effectVal,effect&0x01)); + break; + default: + if ((effect&0xf0)==0x30) { + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K1,ch,((effect&0x0f)<<8)|effectVal)); + } else if ((effect&0xf0)==0x40) { + dispatchCmd(DivCommand(DIV_CMD_ES5506_FILTER_K2,ch,((effect&0x0f)<<8)|effectVal)); + } else { + return false; + } + } + break; + } ); sysDefs[DIV_SYSTEM_Y8950]=new DivSysDef( diff --git a/src/gui/debug.cpp b/src/gui/debug.cpp index b4bf6e764..4d33a8e24 100644 --- a/src/gui/debug.cpp +++ b/src/gui/debug.cpp @@ -345,6 +345,8 @@ void putDispatchChan(void* data, int chanNum, int type) { ImGui::Text("- ins: %d",ch->ins); ImGui::Text("- sample: %d",ch->sample); ImGui::Text("- wave: %d",ch->wave); + ImGui::Text("- VolMacroMax: %d",ch->volMacroMax); + ImGui::Text("- PanMacroMax: %d",ch->panMacroMax); ImGui::Text("* PCM:"); ImGui::Text(" - index: %d",ch->pcm.index); ImGui::Text(" - freqOffs: %.6f",ch->pcm.freqOffs); diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index f98b19c8b..d41eacf16 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -149,42 +149,95 @@ void FurnaceGUI::drawDebug() { ImGui::Text("%d: ",i); continue; } - ImGui::Text("%d: %s",i,sample->name.c_str()); - ImGui::Indent(); - ImGui::Text("rate: %d",sample->rate); - ImGui::Text("centerRate: %d",sample->centerRate); - ImGui::Text("loopStart: %d",sample->loopStart); - ImGui::Text("loopOffP: %d",sample->loopOffP); - ImGui::Text("depth: %d",sample->depth); - ImGui::Text("length8: %d",sample->length8); - ImGui::Text("length16: %d",sample->length16); - ImGui::Text("length1: %d",sample->length1); - ImGui::Text("lengthDPCM: %d",sample->lengthDPCM); - ImGui::Text("lengthQSoundA: %d",sample->lengthQSoundA); - ImGui::Text("lengthA: %d",sample->lengthA); - ImGui::Text("lengthB: %d",sample->lengthB); - ImGui::Text("lengthX68: %d",sample->lengthX68); - ImGui::Text("lengthBRR: %d",sample->lengthBRR); - ImGui::Text("lengthVOX: %d",sample->lengthVOX); + if (ImGui::TreeNode(fmt::sprintf("%d: %s",i,sample->name).c_str())) { + ImGui::Text("rate: %d",sample->rate); + ImGui::Text("centerRate: %d",sample->centerRate); + ImGui::Text("loopStart: %d",sample->loopStart); + ImGui::Text("loopOffP: %d",sample->loopOffP); + ImGui::Text("depth: %d",sample->depth); + ImGui::Text("length8: %d",sample->length8); + ImGui::Text("length16: %d",sample->length16); + ImGui::Text("length1: %d",sample->length1); + ImGui::Text("lengthDPCM: %d",sample->lengthDPCM); + ImGui::Text("lengthQSoundA: %d",sample->lengthQSoundA); + ImGui::Text("lengthA: %d",sample->lengthA); + ImGui::Text("lengthB: %d",sample->lengthB); + ImGui::Text("lengthX68: %d",sample->lengthX68); + ImGui::Text("lengthBRR: %d",sample->lengthBRR); + ImGui::Text("lengthVOX: %d",sample->lengthVOX); - ImGui::Text("off8: %x",sample->off8); - ImGui::Text("off16: %x",sample->off16); - ImGui::Text("off1: %x",sample->off1); - ImGui::Text("offDPCM: %x",sample->offDPCM); - ImGui::Text("offQSoundA: %x",sample->offQSoundA); - ImGui::Text("offA: %x",sample->offA); - ImGui::Text("offB: %x",sample->offB); - ImGui::Text("offX68: %x",sample->offX68); - ImGui::Text("offBRR: %x",sample->offBRR); - ImGui::Text("offVOX: %x",sample->offVOX); - ImGui::Text("offSegaPCM: %x",sample->offSegaPCM); - ImGui::Text("offQSound: %x",sample->offQSound); - ImGui::Text("offX1_010: %x",sample->offX1_010); - ImGui::Text("offES5506: %x",sample->offES5506); - ImGui::Text("offSU: %x",sample->offSU); + ImGui::Text("off8: %x",sample->off8); + ImGui::Text("off16: %x",sample->off16); + ImGui::Text("off1: %x",sample->off1); + ImGui::Text("offDPCM: %x",sample->offDPCM); + ImGui::Text("offQSoundA: %x",sample->offQSoundA); + ImGui::Text("offA: %x",sample->offA); + ImGui::Text("offB: %x",sample->offB); + ImGui::Text("offX68: %x",sample->offX68); + ImGui::Text("offBRR: %x",sample->offBRR); + ImGui::Text("offVOX: %x",sample->offVOX); + ImGui::Text("offSegaPCM: %x",sample->offSegaPCM); + ImGui::Text("offQSound: %x",sample->offQSound); + ImGui::Text("offX1_010: %x",sample->offX1_010); + ImGui::Text("offES5506: %x",sample->offES5506); + ImGui::Text("offSU: %x",sample->offSU); - ImGui::Text("samples: %d",sample->samples); - ImGui::Unindent(); + ImGui::Text("samples: %d",sample->samples); + ImGui::TreePop(); + } + } + ImGui::TreePop(); + } + if (ImGui::TreeNode("Oscilloscope Debug")) { + int c=0; + for (int i=0; isong.systemLen; i++) { + DivSystem system=e->song.system[i]; + if (e->getChannelCount(system)>0) { + if (ImGui::TreeNode(fmt::sprintf("%d: %s",i,e->getSystemName(system)).c_str())) { + if (ImGui::BeginTable("OscilloscopeTable",4,ImGuiTableFlags_Borders|ImGuiTableFlags_SizingStretchSame)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("Channel"); + ImGui::TableNextColumn(); + ImGui::Text("Follow"); + ImGui::TableNextColumn(); + ImGui::Text("Address"); + ImGui::TableNextColumn(); + ImGui::Text("Data"); + + for (int j=0; jgetChannelCount(system); j++, c++) { + ImGui::TableNextRow(); + // channel + ImGui::TableNextColumn(); + ImGui::Text("%d",j); + // follow + ImGui::TableNextColumn(); + ImGui::Checkbox(fmt::sprintf("##%d_OSCFollow_%d",i,c).c_str(),&e->getOscBuffer(c)->follow); + // address + ImGui::TableNextColumn(); + int needle=e->getOscBuffer(c)->follow?e->getOscBuffer(c)->needle:e->getOscBuffer(c)->followNeedle; + ImGui::BeginDisabled(e->getOscBuffer(c)->follow); + if (ImGui::InputInt(fmt::sprintf("##%d_OSCFollowNeedle_%d",i,c).c_str(),&needle,1,100)) { + e->getOscBuffer(c)->followNeedle=MIN(MAX(needle,0),65535); + } + ImGui::EndDisabled(); + // data + ImGui::TableNextColumn(); + ImGui::Text("%d",e->getOscBuffer(c)->data[needle]); + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + } else { + ImGui::Text("%d: ",i); + continue; + } } ImGui::TreePop(); } diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index b515d6535..e4539b794 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -225,1484 +225,1505 @@ void FurnaceGUI::drawSettings() { } if (ImGui::BeginTabBar("settingsTab")) { if (ImGui::BeginTabItem("General")) { - ImGui::Text("Workspace layout:"); - ImGui::SameLine(); - if (ImGui::Button("Import")) { - openFileDialog(GUI_FILE_IMPORT_LAYOUT); - } - ImGui::SameLine(); - if (ImGui::Button("Export")) { - openFileDialog(GUI_FILE_EXPORT_LAYOUT); - } - ImGui::SameLine(); - if (ImGui::Button("Reset")) { - showWarning("Are you sure you want to reset the workspace layout?",GUI_WARN_RESET_LAYOUT); - } - - ImGui::Separator(); - - ImGui::Text("Initial system/chips:"); - ImGui::SameLine(); - if (ImGui::Button("Current systems")) { - settings.initialSys.clear(); - for (int i=0; isong.systemLen; i++) { - settings.initialSys.push_back(e->song.system[i]); - settings.initialSys.push_back(e->song.systemVol[i]); - settings.initialSys.push_back(e->song.systemPan[i]); - settings.initialSys.push_back(e->song.systemFlags[i]); + ImVec2 settingsViewSize=ImGui::GetContentRegionAvail(); + settingsViewSize.y-=ImGui::GetFrameHeight()+ImGui::GetStyle().WindowPadding.y; + if (ImGui::BeginChild("SettingsView",settingsViewSize)) { + ImGui::Text("Workspace layout:"); + ImGui::SameLine(); + if (ImGui::Button("Import")) { + openFileDialog(GUI_FILE_IMPORT_LAYOUT); } - } - ImGui::SameLine(); - if (ImGui::Button("Randomize")) { - settings.initialSys.clear(); - int howMany=1+rand()%3; - int totalAvailSys=0; - for (totalAvailSys=0; availableSystems[totalAvailSys]; totalAvailSys++); - if (totalAvailSys>0) { - for (int i=0; isong.systemLen; i++) { + settings.initialSys.push_back(e->song.system[i]); + settings.initialSys.push_back(e->song.systemVol[i]); + settings.initialSys.push_back(e->song.systemPan[i]); + settings.initialSys.push_back(e->song.systemFlags[i]); + } + } + ImGui::SameLine(); + if (ImGui::Button("Randomize")) { + settings.initialSys.clear(); + int howMany=1+rand()%3; + int totalAvailSys=0; + for (totalAvailSys=0; availableSystems[totalAvailSys]; totalAvailSys++); + if (totalAvailSys>0) { + for (int i=0; i=8) { + settings.initialSys.erase(settings.initialSys.begin()+i,settings.initialSys.begin()+i+4); + i-=4; + } + } + + if (ImGui::Button(ICON_FA_PLUS "##InitSysAdd")) { + settings.initialSys.push_back(DIV_SYSTEM_YM2612); settings.initialSys.push_back(64); settings.initialSys.push_back(0); settings.initialSys.push_back(0); } - } - ImGui::SameLine(); - if (ImGui::Button("Reset to defaults")) { - settings.initialSys.clear(); - settings.initialSys.push_back(DIV_SYSTEM_YM2612); - settings.initialSys.push_back(64); - settings.initialSys.push_back(0); - settings.initialSys.push_back(0); - settings.initialSys.push_back(DIV_SYSTEM_SMS); - settings.initialSys.push_back(32); - settings.initialSys.push_back(0); - settings.initialSys.push_back(0); - } - for (size_t i=0; i":settings.audioDevice; + if (ImGui::BeginCombo("##AudioDevice",audioDevName.c_str())) { + if (ImGui::Selectable("",settings.audioDevice.empty())) { + settings.audioDevice=""; + } + for (String& i: e->getAudioDevices()) { + if (ImGui::Selectable(i.c_str(),i==settings.audioDevice)) { + settings.audioDevice=i; } } ImGui::EndCombo(); } + ImGui::Text("Sample rate"); ImGui::SameLine(); - if (ImGui::Checkbox("Invert",&doInvert)) { - settings.initialSys[i+1]^=128; + String sr=fmt::sprintf("%d",settings.audioRate); + if (ImGui::BeginCombo("##SampleRate",sr.c_str())) { + SAMPLE_RATE_SELECTABLE(8000); + SAMPLE_RATE_SELECTABLE(16000); + SAMPLE_RATE_SELECTABLE(22050); + SAMPLE_RATE_SELECTABLE(32000); + SAMPLE_RATE_SELECTABLE(44100); + SAMPLE_RATE_SELECTABLE(48000); + SAMPLE_RATE_SELECTABLE(88200); + SAMPLE_RATE_SELECTABLE(96000); + SAMPLE_RATE_SELECTABLE(192000); + ImGui::EndCombo(); } + + ImGui::Text("Buffer size"); ImGui::SameLine(); - ImGui::BeginDisabled(settings.initialSys.size()<=4); - if (ImGui::Button(ICON_FA_MINUS "##InitSysRemove")) { - doRemove=true; + String bs=fmt::sprintf("%d (latency: ~%.1fms)",settings.audioBufSize,2000.0*(double)settings.audioBufSize/(double)MAX(1,settings.audioRate)); + if (ImGui::BeginCombo("##BufferSize",bs.c_str())) { + BUFFER_SIZE_SELECTABLE(64); + BUFFER_SIZE_SELECTABLE(128); + BUFFER_SIZE_SELECTABLE(256); + BUFFER_SIZE_SELECTABLE(512); + BUFFER_SIZE_SELECTABLE(1024); + BUFFER_SIZE_SELECTABLE(2048); + ImGui::EndCombo(); } - ImGui::EndDisabled(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-(50.0f*dpiScale)); - if (CWSliderScalar("Volume",ImGuiDataType_S8,&vol,&_ZERO,&_ONE_HUNDRED_TWENTY_SEVEN)) { - settings.initialSys[i+1]=(settings.initialSys[i+1]&128)|vol; - } rightClickable - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x-(50.0f*dpiScale)); - CWSliderScalar("Panning",ImGuiDataType_S8,&settings.initialSys[i+2],&_MINUS_ONE_HUNDRED_TWENTY_SEVEN,&_ONE_HUNDRED_TWENTY_SEVEN); rightClickable - // oh please MSVC don't cry - if (ImGui::TreeNode("Configure")) { - drawSysConf(-1,(DivSystem)settings.initialSys[i],(unsigned int&)settings.initialSys[i+3],false); - ImGui::TreePop(); + ImGui::Text("Quality"); + ImGui::SameLine(); + ImGui::Combo("##Quality",&settings.audioQuality,audioQualities,2); + + ImGui::Text("Metronome volume"); + ImGui::SameLine(); + if (ImGui::SliderInt("##MetroVol",&settings.metroVol,0,200,"%d%%")) { + if (settings.metroVol<0) settings.metroVol=0; + if (settings.metroVol>200) settings.metroVol=200; + e->setMetronomeVol(((float)settings.metroVol)/100.0f); } - ImGui::PopID(); - if (doRemove && settings.initialSys.size()>=8) { - settings.initialSys.erase(settings.initialSys.begin()+i,settings.initialSys.begin()+i+4); - i-=4; + bool lowLatencyB=settings.lowLatency; + if (ImGui::Checkbox("Low-latency mode (experimental!)",&lowLatencyB)) { + settings.lowLatency=lowLatencyB; } - } - - if (ImGui::Button(ICON_FA_PLUS "##InitSysAdd")) { - settings.initialSys.push_back(DIV_SYSTEM_YM2612); - settings.initialSys.push_back(64); - settings.initialSys.push_back(0); - settings.initialSys.push_back(0); - } - - ImGui::Separator(); - - ImGui::Text("Toggle channel solo on:"); - if (ImGui::RadioButton("Right-click or double-click##soloA",settings.soloAction==0)) { - settings.soloAction=0; - } - if (ImGui::RadioButton("Right-click##soloR",settings.soloAction==1)) { - settings.soloAction=1; - } - if (ImGui::RadioButton("Double-click##soloD",settings.soloAction==2)) { - settings.soloAction=2; - } - - bool pushNibbleB=settings.pushNibble; - if (ImGui::Checkbox("Push value when overwriting instead of clearing it",&pushNibbleB)) { - settings.pushNibble=pushNibbleB; - } - - bool pullDeleteBehaviorB=settings.pullDeleteBehavior; - if (ImGui::Checkbox("Move cursor up on backspace-delete",&pullDeleteBehaviorB)) { - settings.pullDeleteBehavior=pullDeleteBehaviorB; - } - - bool stepOnDeleteB=settings.stepOnDelete; - if (ImGui::Checkbox("Move cursor by edit step on delete",&stepOnDeleteB)) { - settings.stepOnDelete=stepOnDeleteB; - } - - bool absorbInsInputB=settings.absorbInsInput; - if (ImGui::Checkbox("Change current instrument when changing instrument column (absorb)",&absorbInsInputB)) { - settings.absorbInsInput=absorbInsInputB; - } - - bool effectDeletionAltersValueB=settings.effectDeletionAltersValue; - if (ImGui::Checkbox("Delete effect value when deleting effect",&effectDeletionAltersValueB)) { - settings.effectDeletionAltersValue=effectDeletionAltersValueB; - } - - bool scrollChangesOrderB=settings.scrollChangesOrder; - if (ImGui::Checkbox("Change order when scrolling outside of pattern bounds",&scrollChangesOrderB)) { - settings.scrollChangesOrder=scrollChangesOrderB; - } - - bool stepOnInsertB=settings.stepOnInsert; - if (ImGui::Checkbox("Move cursor by edit step on insert (push)",&stepOnInsertB)) { - settings.stepOnInsert=stepOnInsertB; - } - - bool cursorPastePosB=settings.cursorPastePos; - if (ImGui::Checkbox("Move cursor to end of clipboard content when pasting",&cursorPastePosB)) { - settings.cursorPastePos=cursorPastePosB; - } - - bool cursorMoveNoScrollB=settings.cursorMoveNoScroll; - if (ImGui::Checkbox("Don't scroll when moving cursor",&cursorMoveNoScrollB)) { - settings.cursorMoveNoScroll=cursorMoveNoScrollB; - } - - bool allowEditDockingB=settings.allowEditDocking; - if (ImGui::Checkbox("Allow docking editors",&allowEditDockingB)) { - settings.allowEditDocking=allowEditDockingB; - } - - bool avoidRaisingPatternB=settings.avoidRaisingPattern; - if (ImGui::Checkbox("Don't raise pattern editor on click",&avoidRaisingPatternB)) { - settings.avoidRaisingPattern=avoidRaisingPatternB; - } - - bool insFocusesPatternB=settings.insFocusesPattern; - if (ImGui::Checkbox("Focus pattern editor when selecting instrument",&insFocusesPatternB)) { - settings.insFocusesPattern=insFocusesPatternB; - } - - bool restartOnFlagChangeB=settings.restartOnFlagChange; - if (ImGui::Checkbox("Restart song when changing system properties",&restartOnFlagChangeB)) { - settings.restartOnFlagChange=restartOnFlagChangeB; - } - - bool sysFileDialogB=settings.sysFileDialog; - if (ImGui::Checkbox("Use system file picker",&sysFileDialogB)) { - settings.sysFileDialog=sysFileDialogB; - } - - bool moveWindowTitleB=settings.moveWindowTitle; - if (ImGui::Checkbox("Only allow window movement when clicking on title bar",&moveWindowTitleB)) { - settings.moveWindowTitle=moveWindowTitleB; - applyUISettings(false); - } - - bool eventDelayB=settings.eventDelay; - if (ImGui::Checkbox("Enable event delay",&eventDelayB)) { - settings.eventDelay=eventDelayB; - applyUISettings(false); - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("may cause issues with high-polling-rate mice when previewing notes."); - } - - bool powerSaveB=settings.powerSave; - if (ImGui::Checkbox("Power-saving mode",&powerSaveB)) { - settings.powerSave=powerSaveB; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("saves power by lowering the frame rate to 2fps when idle.\nmay cause issues under Mesa drivers!"); - } - - ImGui::Text("Note preview behavior:"); - if (ImGui::RadioButton("Never##npb0",settings.notePreviewBehavior==0)) { - settings.notePreviewBehavior=0; - } - if (ImGui::RadioButton("When cursor is in Note column##npb1",settings.notePreviewBehavior==1)) { - settings.notePreviewBehavior=1; - } - if (ImGui::RadioButton("When cursor is in Note column or not in edit mode##npb2",settings.notePreviewBehavior==2)) { - settings.notePreviewBehavior=2; - } - if (ImGui::RadioButton("Always##npb3",settings.notePreviewBehavior==3)) { - settings.notePreviewBehavior=3; - } - - ImGui::Text("Wrap pattern cursor horizontally:"); - if (ImGui::RadioButton("No##wrapH0",settings.wrapHorizontal==0)) { - settings.wrapHorizontal=0; - } - if (ImGui::RadioButton("Yes##wrapH1",settings.wrapHorizontal==1)) { - settings.wrapHorizontal=1; - } - if (ImGui::RadioButton("Yes, and move to next/prev row##wrapH2",settings.wrapHorizontal==2)) { - settings.wrapHorizontal=2; - } - - ImGui::Text("Wrap pattern cursor vertically:"); - if (ImGui::RadioButton("No##wrapV0",settings.wrapVertical==0)) { - settings.wrapVertical=0; - } - if (ImGui::RadioButton("Yes##wrapV1",settings.wrapVertical==1)) { - settings.wrapVertical=1; - } - if (ImGui::RadioButton("Yes, and move to next/prev pattern##wrapV2",settings.wrapVertical==2)) { - settings.wrapVertical=2; - } - - ImGui::Text("Cursor movement keys behavior:"); - if (ImGui::RadioButton("Move by one##cmk0",settings.scrollStep==0)) { - settings.scrollStep=0; - } - if (ImGui::RadioButton("Move by Edit Step##cmk1",settings.scrollStep==1)) { - settings.scrollStep=1; - } - - ImGui::Text("Effect input cursor behavior:"); - if (ImGui::RadioButton("Move down##eicb0",settings.effectCursorDir==0)) { - settings.effectCursorDir=0; - } - if (ImGui::RadioButton("Move to effect value (otherwise move down)##eicb1",settings.effectCursorDir==1)) { - settings.effectCursorDir=1; - } - if (ImGui::RadioButton("Move to effect value/next effect and wrap around##eicb2",settings.effectCursorDir==2)) { - settings.effectCursorDir=2; - } - - ImGui::EndTabItem(); - } - if (ImGui::BeginTabItem("Audio/MIDI")) { - ImGui::Text("Backend"); - ImGui::SameLine(); - ImGui::Combo("##Backend",&settings.audioEngine,audioBackends,2); - - ImGui::Text("Device"); - ImGui::SameLine(); - String audioDevName=settings.audioDevice.empty()?"":settings.audioDevice; - if (ImGui::BeginCombo("##AudioDevice",audioDevName.c_str())) { - if (ImGui::Selectable("",settings.audioDevice.empty())) { - settings.audioDevice=""; + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("reduces latency by running the engine faster than the tick rate.\nuseful for live playback/jam mode.\n\nwarning: experimental! may produce glitches.\nonly enable if your buffer size is small (10ms or less)."); } - for (String& i: e->getAudioDevices()) { - if (ImGui::Selectable(i.c_str(),i==settings.audioDevice)) { - settings.audioDevice=i; - } + + bool forceMonoB=settings.forceMono; + if (ImGui::Checkbox("Force mono audio",&forceMonoB)) { + settings.forceMono=forceMonoB; } - ImGui::EndCombo(); - } - ImGui::Text("Sample rate"); - ImGui::SameLine(); - String sr=fmt::sprintf("%d",settings.audioRate); - if (ImGui::BeginCombo("##SampleRate",sr.c_str())) { - SAMPLE_RATE_SELECTABLE(8000); - SAMPLE_RATE_SELECTABLE(16000); - SAMPLE_RATE_SELECTABLE(22050); - SAMPLE_RATE_SELECTABLE(32000); - SAMPLE_RATE_SELECTABLE(44100); - SAMPLE_RATE_SELECTABLE(48000); - SAMPLE_RATE_SELECTABLE(88200); - SAMPLE_RATE_SELECTABLE(96000); - SAMPLE_RATE_SELECTABLE(192000); - ImGui::EndCombo(); - } + TAAudioDesc& audioWant=e->getAudioDescWant(); + TAAudioDesc& audioGot=e->getAudioDescGot(); - ImGui::Text("Buffer size"); - ImGui::SameLine(); - String bs=fmt::sprintf("%d (latency: ~%.1fms)",settings.audioBufSize,2000.0*(double)settings.audioBufSize/(double)MAX(1,settings.audioRate)); - if (ImGui::BeginCombo("##BufferSize",bs.c_str())) { - BUFFER_SIZE_SELECTABLE(64); - BUFFER_SIZE_SELECTABLE(128); - BUFFER_SIZE_SELECTABLE(256); - BUFFER_SIZE_SELECTABLE(512); - BUFFER_SIZE_SELECTABLE(1024); - BUFFER_SIZE_SELECTABLE(2048); - ImGui::EndCombo(); - } - - ImGui::Text("Quality"); - ImGui::SameLine(); - ImGui::Combo("##Quality",&settings.audioQuality,audioQualities,2); + ImGui::Text("want: %d samples @ %.0fHz",audioWant.bufsize,audioWant.rate); + ImGui::Text("got: %d samples @ %.0fHz",audioGot.bufsize,audioGot.rate); - ImGui::Text("Metronome volume"); - ImGui::SameLine(); - if (ImGui::SliderInt("##MetroVol",&settings.metroVol,0,200,"%d%%")) { - if (settings.metroVol<0) settings.metroVol=0; - if (settings.metroVol>200) settings.metroVol=200; - e->setMetronomeVol(((float)settings.metroVol)/100.0f); - } + ImGui::Separator(); - bool lowLatencyB=settings.lowLatency; - if (ImGui::Checkbox("Low-latency mode (experimental!)",&lowLatencyB)) { - settings.lowLatency=lowLatencyB; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("reduces latency by running the engine faster than the tick rate.\nuseful for live playback/jam mode.\n\nwarning: experimental! may produce glitches.\nonly enable if your buffer size is small (10ms or less)."); - } - - bool forceMonoB=settings.forceMono; - if (ImGui::Checkbox("Force mono audio",&forceMonoB)) { - settings.forceMono=forceMonoB; - } - - TAAudioDesc& audioWant=e->getAudioDescWant(); - TAAudioDesc& audioGot=e->getAudioDescGot(); - - ImGui::Text("want: %d samples @ %.0fHz",audioWant.bufsize,audioWant.rate); - ImGui::Text("got: %d samples @ %.0fHz",audioGot.bufsize,audioGot.rate); - - ImGui::Separator(); - - ImGui::Text("MIDI input"); - ImGui::SameLine(); - String midiInName=settings.midiInDevice.empty()?"":settings.midiInDevice; - bool hasToReloadMidi=false; - if (ImGui::BeginCombo("##MidiInDevice",midiInName.c_str())) { - if (ImGui::Selectable("",settings.midiInDevice.empty())) { - settings.midiInDevice=""; - hasToReloadMidi=true; - } - for (String& i: e->getMidiIns()) { - if (ImGui::Selectable(i.c_str(),i==settings.midiInDevice)) { - settings.midiInDevice=i; + ImGui::Text("MIDI input"); + ImGui::SameLine(); + String midiInName=settings.midiInDevice.empty()?"":settings.midiInDevice; + bool hasToReloadMidi=false; + if (ImGui::BeginCombo("##MidiInDevice",midiInName.c_str())) { + if (ImGui::Selectable("",settings.midiInDevice.empty())) { + settings.midiInDevice=""; hasToReloadMidi=true; } - } - ImGui::EndCombo(); - } - - if (hasToReloadMidi) { - midiMap.read(e->getConfigPath()+DIR_SEPARATOR_STR+"midiIn_"+stripName(settings.midiInDevice)+".cfg"); - midiMap.compile(); - } - - ImGui::Text("MIDI output"); - ImGui::SameLine(); - String midiOutName=settings.midiOutDevice.empty()?"":settings.midiOutDevice; - if (ImGui::BeginCombo("##MidiOutDevice",midiOutName.c_str())) { - if (ImGui::Selectable("",settings.midiOutDevice.empty())) { - settings.midiOutDevice=""; - } - for (String& i: e->getMidiIns()) { - if (ImGui::Selectable(i.c_str(),i==settings.midiOutDevice)) { - settings.midiOutDevice=i; - } - } - ImGui::EndCombo(); - } - - if (ImGui::TreeNode("MIDI input settings")) { - ImGui::Checkbox("Note input",&midiMap.noteInput); - ImGui::Checkbox("Velocity input",&midiMap.volInput); - // TODO - //ImGui::Checkbox("Use raw velocity value (don't map from linear to log)",&midiMap.rawVolume); - //ImGui::Checkbox("Polyphonic/chord input",&midiMap.polyInput); - ImGui::Checkbox("Map MIDI channels to direct channels",&midiMap.directChannel); - ImGui::Checkbox("Program change is instrument selection",&midiMap.programChange); - //ImGui::Checkbox("Listen to MIDI clock",&midiMap.midiClock); - //ImGui::Checkbox("Listen to MIDI time code",&midiMap.midiTimeCode); - ImGui::Combo("Value input style",&midiMap.valueInputStyle,valueInputStyles,7); - if (midiMap.valueInputStyle>3) { - if (midiMap.valueInputStyle==6) { - if (ImGui::InputInt("Control##valueCCS",&midiMap.valueInputControlSingle,1,16)) { - if (midiMap.valueInputControlSingle<0) midiMap.valueInputControlSingle=0; - if (midiMap.valueInputControlSingle>127) midiMap.valueInputControlSingle=127; - } - } else { - if (ImGui::InputInt((midiMap.valueInputStyle==4)?"CC of upper nibble##valueCC1":"MSB CC##valueCC1",&midiMap.valueInputControlMSB,1,16)) { - if (midiMap.valueInputControlMSB<0) midiMap.valueInputControlMSB=0; - if (midiMap.valueInputControlMSB>127) midiMap.valueInputControlMSB=127; - } - if (ImGui::InputInt((midiMap.valueInputStyle==4)?"CC of lower nibble##valueCC2":"LSB CC##valueCC2",&midiMap.valueInputControlLSB,1,16)) { - if (midiMap.valueInputControlLSB<0) midiMap.valueInputControlLSB=0; - if (midiMap.valueInputControlLSB>127) midiMap.valueInputControlLSB=127; + for (String& i: e->getMidiIns()) { + if (ImGui::Selectable(i.c_str(),i==settings.midiInDevice)) { + settings.midiInDevice=i; + hasToReloadMidi=true; } } + ImGui::EndCombo(); } - if (ImGui::TreeNode("Per-column control change")) { - for (int i=0; i<18; i++) { - ImGui::PushID(i); - ImGui::Combo(specificControls[i],&midiMap.valueInputSpecificStyle[i],valueSInputStyles,4); - if (midiMap.valueInputSpecificStyle[i]>0) { - ImGui::Indent(); - if (midiMap.valueInputSpecificStyle[i]==3) { - if (ImGui::InputInt("Control##valueCCS",&midiMap.valueInputSpecificSingle[i],1,16)) { - if (midiMap.valueInputSpecificSingle[i]<0) midiMap.valueInputSpecificSingle[i]=0; - if (midiMap.valueInputSpecificSingle[i]>127) midiMap.valueInputSpecificSingle[i]=127; - } - } else { - if (ImGui::InputInt((midiMap.valueInputSpecificStyle[i]==4)?"CC of upper nibble##valueCC1":"MSB CC##valueCC1",&midiMap.valueInputSpecificMSB[i],1,16)) { - if (midiMap.valueInputSpecificMSB[i]<0) midiMap.valueInputSpecificMSB[i]=0; - if (midiMap.valueInputSpecificMSB[i]>127) midiMap.valueInputSpecificMSB[i]=127; - } - if (ImGui::InputInt((midiMap.valueInputSpecificStyle[i]==4)?"CC of lower nibble##valueCC2":"LSB CC##valueCC2",&midiMap.valueInputSpecificLSB[i],1,16)) { - if (midiMap.valueInputSpecificLSB[i]<0) midiMap.valueInputSpecificLSB[i]=0; - if (midiMap.valueInputSpecificLSB[i]>127) midiMap.valueInputSpecificLSB[i]=127; - } - } - ImGui::Unindent(); - } - ImGui::PopID(); - } - ImGui::TreePop(); - } - if (ImGui::SliderFloat("Volume curve",&midiMap.volExp,0.01,8.0,"%.2f")) { - if (midiMap.volExp<0.01) midiMap.volExp=0.01; - if (midiMap.volExp>8.0) midiMap.volExp=8.0; - } rightClickable - float curve[128]; - for (int i=0; i<128; i++) { - curve[i]=(int)(pow((double)i/127.0,midiMap.volExp)*127.0); - } - ImGui::PlotLines("##VolCurveDisplay",curve,128,0,"Volume curve",0.0,127.0,ImVec2(200.0f*dpiScale,200.0f*dpiScale)); - ImGui::Text("Actions:"); + if (hasToReloadMidi) { + midiMap.read(e->getConfigPath()+DIR_SEPARATOR_STR+"midiIn_"+stripName(settings.midiInDevice)+".cfg"); + midiMap.compile(); + } + + ImGui::Text("MIDI output"); ImGui::SameLine(); - if (ImGui::Button(ICON_FA_PLUS "##AddAction")) { - midiMap.binds.push_back(MIDIBind()); - } - ImGui::SameLine(); - if (ImGui::Button(ICON_FA_EXTERNAL_LINK "##AddLearnAction")) { - midiMap.binds.push_back(MIDIBind()); - learning=midiMap.binds.size()-1; - } - if (learning!=-1) { - ImGui::SameLine(); - ImGui::Text("(learning! press a button or move a slider/knob/something on your device.)"); - } - - if (ImGui::BeginTable("MIDIActions",7)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.2); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.1); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.3); - ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.2); - ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.5); - ImGui::TableSetupColumn("c5",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c6",ImGuiTableColumnFlags_WidthFixed); - - ImGui::TableNextRow(ImGuiTableRowFlags_Headers); - ImGui::TableNextColumn(); - ImGui::Text("Type"); - ImGui::TableNextColumn(); - ImGui::Text("Channel"); - ImGui::TableNextColumn(); - ImGui::Text("Note/Control"); - ImGui::TableNextColumn(); - ImGui::Text("Velocity/Value"); - ImGui::TableNextColumn(); - ImGui::Text("Action"); - ImGui::TableNextColumn(); - ImGui::Text("Learn"); - ImGui::TableNextColumn(); - ImGui::Text("Remove"); - - for (size_t i=0; i":settings.midiOutDevice; + if (ImGui::BeginCombo("##MidiOutDevice",midiOutName.c_str())) { + if (ImGui::Selectable("",settings.midiOutDevice.empty())) { + settings.midiOutDevice=""; + } + for (String& i: e->getMidiIns()) { + if (ImGui::Selectable(i.c_str(),i==settings.midiOutDevice)) { + settings.midiOutDevice=i; } + } + ImGui::EndCombo(); + } - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("##BChannel",messageChannels[bind.channel])) { - if (ImGui::Selectable(messageChannels[16],bind.channel==16)) { - bind.channel=16; + if (ImGui::TreeNode("MIDI input settings")) { + ImGui::Checkbox("Note input",&midiMap.noteInput); + ImGui::Checkbox("Velocity input",&midiMap.volInput); + // TODO + //ImGui::Checkbox("Use raw velocity value (don't map from linear to log)",&midiMap.rawVolume); + //ImGui::Checkbox("Polyphonic/chord input",&midiMap.polyInput); + ImGui::Checkbox("Map MIDI channels to direct channels",&midiMap.directChannel); + ImGui::Checkbox("Program change is instrument selection",&midiMap.programChange); + //ImGui::Checkbox("Listen to MIDI clock",&midiMap.midiClock); + //ImGui::Checkbox("Listen to MIDI time code",&midiMap.midiTimeCode); + ImGui::Combo("Value input style",&midiMap.valueInputStyle,valueInputStyles,7); + if (midiMap.valueInputStyle>3) { + if (midiMap.valueInputStyle==6) { + if (ImGui::InputInt("Control##valueCCS",&midiMap.valueInputControlSingle,1,16)) { + if (midiMap.valueInputControlSingle<0) midiMap.valueInputControlSingle=0; + if (midiMap.valueInputControlSingle>127) midiMap.valueInputControlSingle=127; } - for (int j=0; j<16; j++) { - if (ImGui::Selectable(messageChannels[j],bind.channel==j)) { - bind.channel=j; - } - } - ImGui::EndCombo(); - } - - ImGui::TableNextColumn(); - if (bind.data1==128) { - snprintf(bindID,1024,"Any"); } else { - const char* nName="???"; - if ((bind.data1+60)>0 && (bind.data1+60)<180) { - nName=noteNames[bind.data1+60]; + if (ImGui::InputInt((midiMap.valueInputStyle==4)?"CC of upper nibble##valueCC1":"MSB CC##valueCC1",&midiMap.valueInputControlMSB,1,16)) { + if (midiMap.valueInputControlMSB<0) midiMap.valueInputControlMSB=0; + if (midiMap.valueInputControlMSB>127) midiMap.valueInputControlMSB=127; + } + if (ImGui::InputInt((midiMap.valueInputStyle==4)?"CC of lower nibble##valueCC2":"LSB CC##valueCC2",&midiMap.valueInputControlLSB,1,16)) { + if (midiMap.valueInputControlLSB<0) midiMap.valueInputControlLSB=0; + if (midiMap.valueInputControlLSB>127) midiMap.valueInputControlLSB=127; } - snprintf(bindID,1024,"%d (0x%.2X, %s)",bind.data1,bind.data1,nName); } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("##BValue1",bindID)) { - if (ImGui::Selectable("Any",bind.data1==128)) { - bind.data1=128; - } - for (int j=0; j<128; j++) { - const char* nName="???"; - if ((j+60)>0 && (j+60)<180) { - nName=noteNames[j+60]; - } - snprintf(bindID,1024,"%d (0x%.2X, %s)##BV1_%d",j,j,nName,j); - if (ImGui::Selectable(bindID,bind.data1==j)) { - bind.data1=j; - } - } - ImGui::EndCombo(); - } - - ImGui::TableNextColumn(); - if (bind.data2==128) { - snprintf(bindID,1024,"Any"); - } else { - snprintf(bindID,1024,"%d (0x%.2X)",bind.data2,bind.data2); - } - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("##BValue2",bindID)) { - if (ImGui::Selectable("Any",bind.data2==128)) { - bind.data2=128; - } - for (int j=0; j<128; j++) { - snprintf(bindID,1024,"%d (0x%.2X)##BV2_%d",j,j,j); - if (ImGui::Selectable(bindID,bind.data2==j)) { - bind.data2=j; - } - } - ImGui::EndCombo(); - } - - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::BeginCombo("##BAction",(bind.action==0)?"--none--":guiActions[bind.action].friendlyName)) { - if (ImGui::Selectable("--none--",bind.action==0)) { - bind.action=0; - } - for (int j=0; j0) { + ImGui::Indent(); + if (midiMap.valueInputSpecificStyle[i]==3) { + if (ImGui::InputInt("Control##valueCCS",&midiMap.valueInputSpecificSingle[i],1,16)) { + if (midiMap.valueInputSpecificSingle[i]<0) midiMap.valueInputSpecificSingle[i]=0; + if (midiMap.valueInputSpecificSingle[i]>127) midiMap.valueInputSpecificSingle[i]=127; + } } else { - snprintf(bindID,1024,"%s##BA_%d",guiActions[j].friendlyName,j); - if (ImGui::Selectable(bindID,bind.action==j)) { - bind.action=j; + if (ImGui::InputInt((midiMap.valueInputSpecificStyle[i]==4)?"CC of upper nibble##valueCC1":"MSB CC##valueCC1",&midiMap.valueInputSpecificMSB[i],1,16)) { + if (midiMap.valueInputSpecificMSB[i]<0) midiMap.valueInputSpecificMSB[i]=0; + if (midiMap.valueInputSpecificMSB[i]>127) midiMap.valueInputSpecificMSB[i]=127; + } + if (ImGui::InputInt((midiMap.valueInputSpecificStyle[i]==4)?"CC of lower nibble##valueCC2":"LSB CC##valueCC2",&midiMap.valueInputSpecificLSB[i],1,16)) { + if (midiMap.valueInputSpecificLSB[i]<0) midiMap.valueInputSpecificLSB[i]=0; + if (midiMap.valueInputSpecificLSB[i]>127) midiMap.valueInputSpecificLSB[i]=127; } } + ImGui::Unindent(); } - ImGui::EndCombo(); + ImGui::PopID(); } - - ImGui::TableNextColumn(); - if (ImGui::Button((learning==(int)i)?("waiting...##BLearn"):(ICON_FA_SQUARE_O "##BLearn"))) { - if (learning==(int)i) { - learning=-1; - } else { - learning=i; - } - } - - ImGui::TableNextColumn(); - if (ImGui::Button(ICON_FA_TIMES "##BRemove")) { - midiMap.binds.erase(midiMap.binds.begin()+i); - if (learning==(int)i) learning=-1; - i--; - } - - ImGui::PopID(); + ImGui::TreePop(); } - ImGui::EndTable(); + if (ImGui::SliderFloat("Volume curve",&midiMap.volExp,0.01,8.0,"%.2f")) { + if (midiMap.volExp<0.01) midiMap.volExp=0.01; + if (midiMap.volExp>8.0) midiMap.volExp=8.0; + } rightClickable + float curve[128]; + for (int i=0; i<128; i++) { + curve[i]=(int)(pow((double)i/127.0,midiMap.volExp)*127.0); + } + ImGui::PlotLines("##VolCurveDisplay",curve,128,0,"Volume curve",0.0,127.0,ImVec2(200.0f*dpiScale,200.0f*dpiScale)); + + ImGui::Text("Actions:"); + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_PLUS "##AddAction")) { + midiMap.binds.push_back(MIDIBind()); + } + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_EXTERNAL_LINK "##AddLearnAction")) { + midiMap.binds.push_back(MIDIBind()); + learning=midiMap.binds.size()-1; + } + if (learning!=-1) { + ImGui::SameLine(); + ImGui::Text("(learning! press a button or move a slider/knob/something on your device.)"); + } + + if (ImGui::BeginTable("MIDIActions",7)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.2); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.1); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.3); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch,0.2); + ImGui::TableSetupColumn("c4",ImGuiTableColumnFlags_WidthStretch,0.5); + ImGui::TableSetupColumn("c5",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c6",ImGuiTableColumnFlags_WidthFixed); + + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("Type"); + ImGui::TableNextColumn(); + ImGui::Text("Channel"); + ImGui::TableNextColumn(); + ImGui::Text("Note/Control"); + ImGui::TableNextColumn(); + ImGui::Text("Velocity/Value"); + ImGui::TableNextColumn(); + ImGui::Text("Action"); + ImGui::TableNextColumn(); + ImGui::Text("Learn"); + ImGui::TableNextColumn(); + ImGui::Text("Remove"); + + for (size_t i=0; i0 && (bind.data1+60)<180) { + nName=noteNames[bind.data1+60]; + } + snprintf(bindID,1024,"%d (0x%.2X, %s)",bind.data1,bind.data1,nName); + } + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##BValue1",bindID)) { + if (ImGui::Selectable("Any",bind.data1==128)) { + bind.data1=128; + } + for (int j=0; j<128; j++) { + const char* nName="???"; + if ((j+60)>0 && (j+60)<180) { + nName=noteNames[j+60]; + } + snprintf(bindID,1024,"%d (0x%.2X, %s)##BV1_%d",j,j,nName,j); + if (ImGui::Selectable(bindID,bind.data1==j)) { + bind.data1=j; + } + } + ImGui::EndCombo(); + } + + ImGui::TableNextColumn(); + if (bind.data2==128) { + snprintf(bindID,1024,"Any"); + } else { + snprintf(bindID,1024,"%d (0x%.2X)",bind.data2,bind.data2); + } + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##BValue2",bindID)) { + if (ImGui::Selectable("Any",bind.data2==128)) { + bind.data2=128; + } + for (int j=0; j<128; j++) { + snprintf(bindID,1024,"%d (0x%.2X)##BV2_%d",j,j,j); + if (ImGui::Selectable(bindID,bind.data2==j)) { + bind.data2=j; + } + } + ImGui::EndCombo(); + } + + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (ImGui::BeginCombo("##BAction",(bind.action==0)?"--none--":guiActions[bind.action].friendlyName)) { + if (ImGui::Selectable("--none--",bind.action==0)) { + bind.action=0; + } + for (int j=0; j3.0f) settings.dpiScale=3.0f; - } rightClickable - } - ImGui::Text("Main font"); - ImGui::SameLine(); - ImGui::Combo("##MainFont",&settings.mainFont,mainFonts,7); - if (settings.mainFont==6) { - ImGui::InputText("##MainFontPath",&settings.mainFontPath); - ImGui::SameLine(); - if (ImGui::Button(ICON_FA_FOLDER "##MainFontLoad")) { - openFileDialog(GUI_FILE_LOAD_MAIN_FONT); - } - } - if (ImGui::InputInt("Size##MainFontSize",&settings.mainFontSize)) { - if (settings.mainFontSize<3) settings.mainFontSize=3; - if (settings.mainFontSize>96) settings.mainFontSize=96; - } - ImGui::Text("Pattern font"); - ImGui::SameLine(); - ImGui::Combo("##PatFont",&settings.patFont,patFonts,7); - if (settings.patFont==6) { - ImGui::InputText("##PatFontPath",&settings.patFontPath); - ImGui::SameLine(); - if (ImGui::Button(ICON_FA_FOLDER "##PatFontLoad")) { - openFileDialog(GUI_FILE_LOAD_PAT_FONT); - } - } - if (ImGui::InputInt("Size##PatFontSize",&settings.patFontSize)) { - if (settings.patFontSize<3) settings.patFontSize=3; - if (settings.patFontSize>96) settings.patFontSize=96; - } - - bool loadJapaneseB=settings.loadJapanese; - if (ImGui::Checkbox("Display Japanese characters",&loadJapaneseB)) { - settings.loadJapanese=loadJapaneseB; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip( - "Only toggle this option if you have enough graphics memory.\n" - "This is a temporary solution until dynamic font atlas is implemented in Dear ImGui.\n\n" - "このオプションは、十分なグラフィックメモリがある場合にのみ切り替えてください。\n" - "これは、Dear ImGuiにダイナミックフォントアトラスが実装されるまでの一時的な解決策です。" - ); - } - - ImGui::Separator(); - - ImGui::Text("Orders row number format:"); - if (ImGui::RadioButton("Decimal##orbD",settings.orderRowsBase==0)) { - settings.orderRowsBase=0; - } - if (ImGui::RadioButton("Hexadecimal##orbH",settings.orderRowsBase==1)) { - settings.orderRowsBase=1; - } - - ImGui::Text("Pattern row number format:"); - if (ImGui::RadioButton("Decimal##prbD",settings.patRowsBase==0)) { - settings.patRowsBase=0; - } - if (ImGui::RadioButton("Hexadecimal##prbH",settings.patRowsBase==1)) { - settings.patRowsBase=1; - } - - ImGui::Text("FM parameter names:"); - if (ImGui::RadioButton("Friendly##fmn0",settings.fmNames==0)) { - settings.fmNames=0; - } - if (ImGui::RadioButton("Technical##fmn1",settings.fmNames==1)) { - settings.fmNames=1; - } - if (ImGui::RadioButton("Technical (alternate)##fmn2",settings.fmNames==2)) { - settings.fmNames=2; - } - - ImGui::Separator(); - - ImGui::Text("Title bar:"); - if (ImGui::RadioButton("Furnace##tbar0",settings.titleBarInfo==0)) { - settings.titleBarInfo=0; - updateWindowTitle(); - } - if (ImGui::RadioButton("Song Name - Furnace##tbar1",settings.titleBarInfo==1)) { - settings.titleBarInfo=1; - updateWindowTitle(); - } - if (ImGui::RadioButton("file_name.fur - Furnace##tbar2",settings.titleBarInfo==2)) { - settings.titleBarInfo=2; - updateWindowTitle(); - } - if (ImGui::RadioButton("/path/to/file.fur - Furnace##tbar3",settings.titleBarInfo==3)) { - settings.titleBarInfo=3; - updateWindowTitle(); - } - - bool titleBarSysB=settings.titleBarSys; - if (ImGui::Checkbox("Display system name on title bar",&titleBarSysB)) { - settings.titleBarSys=titleBarSysB; - updateWindowTitle(); - } - - ImGui::Text("Status bar:"); - if (ImGui::RadioButton("Cursor details##sbar0",settings.statusDisplay==0)) { - settings.statusDisplay=0; - } - if (ImGui::RadioButton("File path##sbar1",settings.statusDisplay==1)) { - settings.statusDisplay=1; - } - if (ImGui::RadioButton("Cursor details or file path##sbar2",settings.statusDisplay==2)) { - settings.statusDisplay=2; - } - if (ImGui::RadioButton("Nothing##sbar3",settings.statusDisplay==3)) { - settings.statusDisplay=3; - } - - ImGui::Text("Play/edit controls layout:"); - if (ImGui::RadioButton("Classic##ecl0",settings.controlLayout==0)) { - settings.controlLayout=0; - } - if (ImGui::RadioButton("Compact##ecl1",settings.controlLayout==1)) { - settings.controlLayout=1; - } - if (ImGui::RadioButton("Compact (vertical)##ecl2",settings.controlLayout==2)) { - settings.controlLayout=2; - } - if (ImGui::RadioButton("Split##ecl3",settings.controlLayout==3)) { - settings.controlLayout=3; - } - - ImGui::Text("FM parameter editor layout:"); - if (ImGui::RadioButton("Modern##fml0",settings.fmLayout==0)) { - settings.fmLayout=0; - } - if (ImGui::RadioButton("Compact (2x2, classic)##fml1",settings.fmLayout==1)) { - settings.fmLayout=1; - } - if (ImGui::RadioButton("Compact (1x4)##fml2",settings.fmLayout==2)) { - settings.fmLayout=2; - } - if (ImGui::RadioButton("Compact (4x1)##fml3",settings.fmLayout==3)) { - settings.fmLayout=3; - } - - ImGui::Text("Position of Sustain in FM editor:"); - if (ImGui::RadioButton("Between Decay and Sustain Rate##susp0",settings.susPosition==0)) { - settings.susPosition=0; - } - if (ImGui::RadioButton("After Release Rate##susp1",settings.susPosition==1)) { - settings.susPosition=1; - } - - ImGui::Separator(); - - bool insEditColorizeB=settings.insEditColorize; - if (ImGui::Checkbox("Colorize instrument editor using instrument type",&insEditColorizeB)) { - settings.insEditColorize=insEditColorizeB; - } - - bool separateFMColorsB=settings.separateFMColors; - if (ImGui::Checkbox("Use separate colors for carriers/modulators in FM editor",&separateFMColorsB)) { - settings.separateFMColors=separateFMColorsB; - } - - bool macroViewB=settings.macroView; - if (ImGui::Checkbox("Classic macro view (standard macros only; deprecated!)",¯oViewB)) { - settings.macroView=macroViewB; - } - - bool unifiedDataViewB=settings.unifiedDataView; - if (ImGui::Checkbox("Unified instrument/wavetable/sample list",&unifiedDataViewB)) { - settings.unifiedDataView=unifiedDataViewB; - } - - bool chipNamesB=settings.chipNames; - if (ImGui::Checkbox("Use chip names instead of system names",&chipNamesB)) { - settings.chipNames=chipNamesB; - } - - bool oplStandardWaveNamesB=settings.oplStandardWaveNames; - if (ImGui::Checkbox("Use standard OPL waveform names",&oplStandardWaveNamesB)) { - settings.oplStandardWaveNames=oplStandardWaveNamesB; - } - - if (nonLatchNibble) { - bool hiddenSystemsB=settings.hiddenSystems; - if (ImGui::Checkbox(":smile: :star_struck: :sunglasses: :ok_hand:",&hiddenSystemsB)) { - settings.hiddenSystems=hiddenSystemsB; - } - } - - bool overflowHighlightB=settings.overflowHighlight; - if (ImGui::Checkbox("Overflow pattern highlights",&overflowHighlightB)) { - settings.overflowHighlight=overflowHighlightB; - } - - bool viewPrevPatternB=settings.viewPrevPattern; - if (ImGui::Checkbox("Display previous/next pattern",&viewPrevPatternB)) { - settings.viewPrevPattern=viewPrevPatternB; - } - - bool germanNotationB=settings.germanNotation; - if (ImGui::Checkbox("Use German notation",&germanNotationB)) { - settings.germanNotation=germanNotationB; - } - - // sorry. temporarily disabled until ImGui has a way to add separators in tables arbitrarily. - /*bool sysSeparatorsB=settings.sysSeparators; - if (ImGui::Checkbox("Add separators between systems in Orders",&sysSeparatorsB)) { - settings.sysSeparators=sysSeparatorsB; - }*/ - - bool partyTimeB=settings.partyTime; - if (ImGui::Checkbox("About screen party time",&partyTimeB)) { - settings.partyTime=partyTimeB; - } - if (ImGui::IsItemHovered()) { - ImGui::SetTooltip("Warning: may cause epileptic seizures."); - } - - ImGui::Separator(); - - bool waveLayoutB=settings.waveLayout; - if (ImGui::Checkbox("Use compact wave editor",&waveLayoutB)) { - settings.waveLayout=waveLayoutB; - } - - bool sampleLayoutB=settings.sampleLayout; - if (ImGui::Checkbox("Use compact sample editor",&sampleLayoutB)) { - settings.sampleLayout=sampleLayoutB; - } - - bool roundedWindowsB=settings.roundedWindows; - if (ImGui::Checkbox("Rounded window corners",&roundedWindowsB)) { - settings.roundedWindows=roundedWindowsB; - } - - bool roundedButtonsB=settings.roundedButtons; - if (ImGui::Checkbox("Rounded buttons",&roundedButtonsB)) { - settings.roundedButtons=roundedButtonsB; - } - - bool roundedMenusB=settings.roundedMenus; - if (ImGui::Checkbox("Rounded menu corners",&roundedMenusB)) { - settings.roundedMenus=roundedMenusB; - } - - bool frameBordersB=settings.frameBorders; - if (ImGui::Checkbox("Borders around widgets",&frameBordersB)) { - settings.frameBorders=frameBordersB; - } - - ImGui::Separator(); - - ImGui::Text("Oscilloscope settings:"); - - bool oscRoundedCornersB=settings.oscRoundedCorners; - if (ImGui::Checkbox("Rounded corners",&oscRoundedCornersB)) { - settings.oscRoundedCorners=oscRoundedCornersB; - } - - bool oscTakesEntireWindowB=settings.oscTakesEntireWindow; - if (ImGui::Checkbox("Fill entire window",&oscTakesEntireWindowB)) { - settings.oscTakesEntireWindow=oscTakesEntireWindowB; - } - - bool oscBorderB=settings.oscBorder; - if (ImGui::Checkbox("Border",&oscBorderB)) { - settings.oscBorder=oscBorderB; - } - - ImGui::Separator(); - - if (ImGui::TreeNode("Color scheme")) { - if (ImGui::Button("Import")) { - openFileDialog(GUI_FILE_IMPORT_COLORS); - } - ImGui::SameLine(); - if (ImGui::Button("Export")) { - openFileDialog(GUI_FILE_EXPORT_COLORS); - } - ImGui::SameLine(); - if (ImGui::Button("Reset defaults")) { - showWarning("Are you sure you want to reset the color scheme?",GUI_WARN_RESET_COLORS); - } - if (ImGui::TreeNode("General")) { - ImGui::Text("Color scheme type:"); - if (ImGui::RadioButton("Dark##gcb0",settings.guiColorsBase==0)) { - settings.guiColorsBase=0; + ImVec2 settingsViewSize=ImGui::GetContentRegionAvail(); + settingsViewSize.y-=ImGui::GetFrameHeight()+ImGui::GetStyle().WindowPadding.y; + if (ImGui::BeginChild("SettingsView",settingsViewSize)) { + bool dpiScaleAuto=(settings.dpiScale<0.5f); + if (ImGui::Checkbox("Automatic UI scaling factor",&dpiScaleAuto)) { + if (dpiScaleAuto) { + settings.dpiScale=0.0f; + } else { + settings.dpiScale=1.0f; } - if (ImGui::RadioButton("Light##gcb1",settings.guiColorsBase==1)) { - settings.guiColorsBase=1; + } + if (!dpiScaleAuto) { + if (ImGui::SliderFloat("UI scaling factor",&settings.dpiScale,1.0f,3.0f,"%.2fx")) { + if (settings.dpiScale<0.5f) settings.dpiScale=0.5f; + if (settings.dpiScale>3.0f) settings.dpiScale=3.0f; + } rightClickable + } + ImGui::Text("Main font"); + ImGui::SameLine(); + ImGui::Combo("##MainFont",&settings.mainFont,mainFonts,7); + if (settings.mainFont==6) { + ImGui::InputText("##MainFontPath",&settings.mainFontPath); + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_FOLDER "##MainFontLoad")) { + openFileDialog(GUI_FILE_LOAD_MAIN_FONT); } - UI_COLOR_CONFIG(GUI_COLOR_BACKGROUND,"Background"); - UI_COLOR_CONFIG(GUI_COLOR_FRAME_BACKGROUND,"Window background"); - UI_COLOR_CONFIG(GUI_COLOR_MODAL_BACKDROP,"Modal backdrop"); - UI_COLOR_CONFIG(GUI_COLOR_HEADER,"Header"); - UI_COLOR_CONFIG(GUI_COLOR_TEXT,"Text"); - UI_COLOR_CONFIG(GUI_COLOR_ACCENT_PRIMARY,"Primary"); - UI_COLOR_CONFIG(GUI_COLOR_ACCENT_SECONDARY,"Secondary"); - UI_COLOR_CONFIG(GUI_COLOR_BORDER,"Border"); - UI_COLOR_CONFIG(GUI_COLOR_BORDER_SHADOW,"Border shadow"); - UI_COLOR_CONFIG(GUI_COLOR_TOGGLE_ON,"Toggle on"); - UI_COLOR_CONFIG(GUI_COLOR_TOGGLE_OFF,"Toggle off"); - UI_COLOR_CONFIG(GUI_COLOR_EDITING,"Editing"); - UI_COLOR_CONFIG(GUI_COLOR_SONG_LOOP,"Song loop"); - UI_COLOR_CONFIG(GUI_COLOR_PLAYBACK_STAT,"Playback status"); - ImGui::TreePop(); } - if (ImGui::TreeNode("File Picker (built-in)")) { - UI_COLOR_CONFIG(GUI_COLOR_FILE_DIR,"Directory"); - UI_COLOR_CONFIG(GUI_COLOR_FILE_SONG_NATIVE,"Song (native)"); - UI_COLOR_CONFIG(GUI_COLOR_FILE_SONG_IMPORT,"Song (import)"); - UI_COLOR_CONFIG(GUI_COLOR_FILE_INSTR,"Instrument"); - UI_COLOR_CONFIG(GUI_COLOR_FILE_AUDIO,"Audio"); - UI_COLOR_CONFIG(GUI_COLOR_FILE_WAVE,"Wavetable"); - UI_COLOR_CONFIG(GUI_COLOR_FILE_VGM,"VGM"); - UI_COLOR_CONFIG(GUI_COLOR_FILE_FONT,"Font"); - UI_COLOR_CONFIG(GUI_COLOR_FILE_OTHER,"Other"); - ImGui::TreePop(); + if (ImGui::InputInt("Size##MainFontSize",&settings.mainFontSize)) { + if (settings.mainFontSize<3) settings.mainFontSize=3; + if (settings.mainFontSize>96) settings.mainFontSize=96; } - if (ImGui::TreeNode("Oscilloscope")) { - UI_COLOR_CONFIG(GUI_COLOR_OSC_BORDER,"Border"); - UI_COLOR_CONFIG(GUI_COLOR_OSC_BG1,"Background (top-left)"); - UI_COLOR_CONFIG(GUI_COLOR_OSC_BG2,"Background (top-right)"); - UI_COLOR_CONFIG(GUI_COLOR_OSC_BG3,"Background (bottom-left)"); - UI_COLOR_CONFIG(GUI_COLOR_OSC_BG4,"Background (bottom-right)"); - UI_COLOR_CONFIG(GUI_COLOR_OSC_WAVE,"Waveform"); - UI_COLOR_CONFIG(GUI_COLOR_OSC_WAVE_PEAK,"Waveform (clip)"); - UI_COLOR_CONFIG(GUI_COLOR_OSC_REF,"Reference"); - UI_COLOR_CONFIG(GUI_COLOR_OSC_GUIDE,"Guide"); - ImGui::TreePop(); + ImGui::Text("Pattern font"); + ImGui::SameLine(); + ImGui::Combo("##PatFont",&settings.patFont,patFonts,7); + if (settings.patFont==6) { + ImGui::InputText("##PatFontPath",&settings.patFontPath); + ImGui::SameLine(); + if (ImGui::Button(ICON_FA_FOLDER "##PatFontLoad")) { + openFileDialog(GUI_FILE_LOAD_PAT_FONT); + } } - if (ImGui::TreeNode("Volume Meter")) { - UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_LOW,"Low"); - UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_HIGH,"High"); - UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_PEAK,"Clip"); - ImGui::TreePop(); + if (ImGui::InputInt("Size##PatFontSize",&settings.patFontSize)) { + if (settings.patFontSize<3) settings.patFontSize=3; + if (settings.patFontSize>96) settings.patFontSize=96; } - if (ImGui::TreeNode("Orders")) { - UI_COLOR_CONFIG(GUI_COLOR_ORDER_ROW_INDEX,"Order number"); - UI_COLOR_CONFIG(GUI_COLOR_ORDER_ACTIVE,"Current order background"); - UI_COLOR_CONFIG(GUI_COLOR_ORDER_SIMILAR,"Similar patterns"); - UI_COLOR_CONFIG(GUI_COLOR_ORDER_INACTIVE,"Inactive patterns"); - ImGui::TreePop(); - } - if (ImGui::TreeNode("Envelope View")) { - UI_COLOR_CONFIG(GUI_COLOR_FM_ENVELOPE,"Envelope"); - UI_COLOR_CONFIG(GUI_COLOR_FM_ENVELOPE_SUS_GUIDE,"Sustain guide"); - UI_COLOR_CONFIG(GUI_COLOR_FM_ENVELOPE_RELEASE,"Release"); - ImGui::TreePop(); + bool loadJapaneseB=settings.loadJapanese; + if (ImGui::Checkbox("Display Japanese characters",&loadJapaneseB)) { + settings.loadJapanese=loadJapaneseB; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip( + "Only toggle this option if you have enough graphics memory.\n" + "This is a temporary solution until dynamic font atlas is implemented in Dear ImGui.\n\n" + "このオプションは、十分なグラフィックメモリがある場合にのみ切り替えてください。\n" + "これは、Dear ImGuiにダイナミックフォントアトラスが実装されるまでの一時的な解決策です。" + ); } - if (ImGui::TreeNode("FM Editor")) { - UI_COLOR_CONFIG(GUI_COLOR_FM_ALG_BG,"Algorithm background"); - UI_COLOR_CONFIG(GUI_COLOR_FM_ALG_LINE,"Algorithm lines"); - UI_COLOR_CONFIG(GUI_COLOR_FM_MOD,"Modulator"); - UI_COLOR_CONFIG(GUI_COLOR_FM_CAR,"Carrier"); - UI_COLOR_CONFIG(GUI_COLOR_FM_SSG,"SSG-EG"); - UI_COLOR_CONFIG(GUI_COLOR_FM_WAVE,"Waveform"); + ImGui::Separator(); - ImGui::TextWrapped("(the following colors only apply when \"Use separate colors for carriers/modulators in FM editor\" is on!)"); + ImGui::Text("Orders row number format:"); + if (ImGui::RadioButton("Decimal##orbD",settings.orderRowsBase==0)) { + settings.orderRowsBase=0; + } + if (ImGui::RadioButton("Hexadecimal##orbH",settings.orderRowsBase==1)) { + settings.orderRowsBase=1; + } - UI_COLOR_CONFIG(GUI_COLOR_FM_PRIMARY_MOD,"Mod. accent (primary)"); - UI_COLOR_CONFIG(GUI_COLOR_FM_SECONDARY_MOD,"Mod. accent (secondary)"); - UI_COLOR_CONFIG(GUI_COLOR_FM_BORDER_MOD,"Mod. border"); - UI_COLOR_CONFIG(GUI_COLOR_FM_BORDER_SHADOW_MOD,"Mod. border shadow"); - - UI_COLOR_CONFIG(GUI_COLOR_FM_PRIMARY_CAR,"Car. accent (primary"); - UI_COLOR_CONFIG(GUI_COLOR_FM_SECONDARY_CAR,"Car. accent (secondary)"); - UI_COLOR_CONFIG(GUI_COLOR_FM_BORDER_CAR,"Car. border"); - UI_COLOR_CONFIG(GUI_COLOR_FM_BORDER_SHADOW_CAR,"Car. border shadow"); - + ImGui::Text("Pattern row number format:"); + if (ImGui::RadioButton("Decimal##prbD",settings.patRowsBase==0)) { + settings.patRowsBase=0; + } + if (ImGui::RadioButton("Hexadecimal##prbH",settings.patRowsBase==1)) { + settings.patRowsBase=1; + } + + ImGui::Text("FM parameter names:"); + if (ImGui::RadioButton("Friendly##fmn0",settings.fmNames==0)) { + settings.fmNames=0; + } + if (ImGui::RadioButton("Technical##fmn1",settings.fmNames==1)) { + settings.fmNames=1; + } + if (ImGui::RadioButton("Technical (alternate)##fmn2",settings.fmNames==2)) { + settings.fmNames=2; + } + + ImGui::Separator(); + + ImGui::Text("Title bar:"); + if (ImGui::RadioButton("Furnace##tbar0",settings.titleBarInfo==0)) { + settings.titleBarInfo=0; + updateWindowTitle(); + } + if (ImGui::RadioButton("Song Name - Furnace##tbar1",settings.titleBarInfo==1)) { + settings.titleBarInfo=1; + updateWindowTitle(); + } + if (ImGui::RadioButton("file_name.fur - Furnace##tbar2",settings.titleBarInfo==2)) { + settings.titleBarInfo=2; + updateWindowTitle(); + } + if (ImGui::RadioButton("/path/to/file.fur - Furnace##tbar3",settings.titleBarInfo==3)) { + settings.titleBarInfo=3; + updateWindowTitle(); + } + + bool titleBarSysB=settings.titleBarSys; + if (ImGui::Checkbox("Display system name on title bar",&titleBarSysB)) { + settings.titleBarSys=titleBarSysB; + updateWindowTitle(); + } + + ImGui::Text("Status bar:"); + if (ImGui::RadioButton("Cursor details##sbar0",settings.statusDisplay==0)) { + settings.statusDisplay=0; + } + if (ImGui::RadioButton("File path##sbar1",settings.statusDisplay==1)) { + settings.statusDisplay=1; + } + if (ImGui::RadioButton("Cursor details or file path##sbar2",settings.statusDisplay==2)) { + settings.statusDisplay=2; + } + if (ImGui::RadioButton("Nothing##sbar3",settings.statusDisplay==3)) { + settings.statusDisplay=3; + } + + ImGui::Text("Play/edit controls layout:"); + if (ImGui::RadioButton("Classic##ecl0",settings.controlLayout==0)) { + settings.controlLayout=0; + } + if (ImGui::RadioButton("Compact##ecl1",settings.controlLayout==1)) { + settings.controlLayout=1; + } + if (ImGui::RadioButton("Compact (vertical)##ecl2",settings.controlLayout==2)) { + settings.controlLayout=2; + } + if (ImGui::RadioButton("Split##ecl3",settings.controlLayout==3)) { + settings.controlLayout=3; + } + + ImGui::Text("FM parameter editor layout:"); + if (ImGui::RadioButton("Modern##fml0",settings.fmLayout==0)) { + settings.fmLayout=0; + } + if (ImGui::RadioButton("Compact (2x2, classic)##fml1",settings.fmLayout==1)) { + settings.fmLayout=1; + } + if (ImGui::RadioButton("Compact (1x4)##fml2",settings.fmLayout==2)) { + settings.fmLayout=2; + } + if (ImGui::RadioButton("Compact (4x1)##fml3",settings.fmLayout==3)) { + settings.fmLayout=3; + } + + ImGui::Text("Position of Sustain in FM editor:"); + if (ImGui::RadioButton("Between Decay and Sustain Rate##susp0",settings.susPosition==0)) { + settings.susPosition=0; + } + if (ImGui::RadioButton("After Release Rate##susp1",settings.susPosition==1)) { + settings.susPosition=1; + } + + ImGui::Separator(); + + bool insEditColorizeB=settings.insEditColorize; + if (ImGui::Checkbox("Colorize instrument editor using instrument type",&insEditColorizeB)) { + settings.insEditColorize=insEditColorizeB; + } + + bool separateFMColorsB=settings.separateFMColors; + if (ImGui::Checkbox("Use separate colors for carriers/modulators in FM editor",&separateFMColorsB)) { + settings.separateFMColors=separateFMColorsB; + } + + bool macroViewB=settings.macroView; + if (ImGui::Checkbox("Classic macro view (standard macros only; deprecated!)",¯oViewB)) { + settings.macroView=macroViewB; + } + + bool unifiedDataViewB=settings.unifiedDataView; + if (ImGui::Checkbox("Unified instrument/wavetable/sample list",&unifiedDataViewB)) { + settings.unifiedDataView=unifiedDataViewB; + } + + bool chipNamesB=settings.chipNames; + if (ImGui::Checkbox("Use chip names instead of system names",&chipNamesB)) { + settings.chipNames=chipNamesB; + } + + bool oplStandardWaveNamesB=settings.oplStandardWaveNames; + if (ImGui::Checkbox("Use standard OPL waveform names",&oplStandardWaveNamesB)) { + settings.oplStandardWaveNames=oplStandardWaveNamesB; + } + + if (nonLatchNibble) { + bool hiddenSystemsB=settings.hiddenSystems; + if (ImGui::Checkbox(":smile: :star_struck: :sunglasses: :ok_hand:",&hiddenSystemsB)) { + settings.hiddenSystems=hiddenSystemsB; + } + } + + bool overflowHighlightB=settings.overflowHighlight; + if (ImGui::Checkbox("Overflow pattern highlights",&overflowHighlightB)) { + settings.overflowHighlight=overflowHighlightB; + } + + bool viewPrevPatternB=settings.viewPrevPattern; + if (ImGui::Checkbox("Display previous/next pattern",&viewPrevPatternB)) { + settings.viewPrevPattern=viewPrevPatternB; + } + + bool germanNotationB=settings.germanNotation; + if (ImGui::Checkbox("Use German notation",&germanNotationB)) { + settings.germanNotation=germanNotationB; + } + + // sorry. temporarily disabled until ImGui has a way to add separators in tables arbitrarily. + /*bool sysSeparatorsB=settings.sysSeparators; + if (ImGui::Checkbox("Add separators between systems in Orders",&sysSeparatorsB)) { + settings.sysSeparators=sysSeparatorsB; + }*/ + + bool partyTimeB=settings.partyTime; + if (ImGui::Checkbox("About screen party time",&partyTimeB)) { + settings.partyTime=partyTimeB; + } + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Warning: may cause epileptic seizures."); + } + + ImGui::Separator(); + + bool waveLayoutB=settings.waveLayout; + if (ImGui::Checkbox("Use compact wave editor",&waveLayoutB)) { + settings.waveLayout=waveLayoutB; + } + + bool sampleLayoutB=settings.sampleLayout; + if (ImGui::Checkbox("Use compact sample editor",&sampleLayoutB)) { + settings.sampleLayout=sampleLayoutB; + } + + bool roundedWindowsB=settings.roundedWindows; + if (ImGui::Checkbox("Rounded window corners",&roundedWindowsB)) { + settings.roundedWindows=roundedWindowsB; + } + + bool roundedButtonsB=settings.roundedButtons; + if (ImGui::Checkbox("Rounded buttons",&roundedButtonsB)) { + settings.roundedButtons=roundedButtonsB; + } + + bool roundedMenusB=settings.roundedMenus; + if (ImGui::Checkbox("Rounded menu corners",&roundedMenusB)) { + settings.roundedMenus=roundedMenusB; + } + + bool frameBordersB=settings.frameBorders; + if (ImGui::Checkbox("Borders around widgets",&frameBordersB)) { + settings.frameBorders=frameBordersB; + } + + ImGui::Separator(); + + ImGui::Text("Oscilloscope settings:"); + + bool oscRoundedCornersB=settings.oscRoundedCorners; + if (ImGui::Checkbox("Rounded corners",&oscRoundedCornersB)) { + settings.oscRoundedCorners=oscRoundedCornersB; + } + + bool oscTakesEntireWindowB=settings.oscTakesEntireWindow; + if (ImGui::Checkbox("Fill entire window",&oscTakesEntireWindowB)) { + settings.oscTakesEntireWindow=oscTakesEntireWindowB; + } + + bool oscBorderB=settings.oscBorder; + if (ImGui::Checkbox("Border",&oscBorderB)) { + settings.oscBorder=oscBorderB; + } + + ImGui::Separator(); + + if (ImGui::TreeNode("Color scheme")) { + if (ImGui::Button("Import")) { + openFileDialog(GUI_FILE_IMPORT_COLORS); + } + ImGui::SameLine(); + if (ImGui::Button("Export")) { + openFileDialog(GUI_FILE_EXPORT_COLORS); + } + ImGui::SameLine(); + if (ImGui::Button("Reset defaults")) { + showWarning("Are you sure you want to reset the color scheme?",GUI_WARN_RESET_COLORS); + } + if (ImGui::TreeNode("General")) { + ImGui::Text("Color scheme type:"); + if (ImGui::RadioButton("Dark##gcb0",settings.guiColorsBase==0)) { + settings.guiColorsBase=0; + } + if (ImGui::RadioButton("Light##gcb1",settings.guiColorsBase==1)) { + settings.guiColorsBase=1; + } + UI_COLOR_CONFIG(GUI_COLOR_BACKGROUND,"Background"); + UI_COLOR_CONFIG(GUI_COLOR_FRAME_BACKGROUND,"Window background"); + UI_COLOR_CONFIG(GUI_COLOR_MODAL_BACKDROP,"Modal backdrop"); + UI_COLOR_CONFIG(GUI_COLOR_HEADER,"Header"); + UI_COLOR_CONFIG(GUI_COLOR_TEXT,"Text"); + UI_COLOR_CONFIG(GUI_COLOR_ACCENT_PRIMARY,"Primary"); + UI_COLOR_CONFIG(GUI_COLOR_ACCENT_SECONDARY,"Secondary"); + UI_COLOR_CONFIG(GUI_COLOR_BORDER,"Border"); + UI_COLOR_CONFIG(GUI_COLOR_BORDER_SHADOW,"Border shadow"); + UI_COLOR_CONFIG(GUI_COLOR_TOGGLE_ON,"Toggle on"); + UI_COLOR_CONFIG(GUI_COLOR_TOGGLE_OFF,"Toggle off"); + UI_COLOR_CONFIG(GUI_COLOR_EDITING,"Editing"); + UI_COLOR_CONFIG(GUI_COLOR_SONG_LOOP,"Song loop"); + UI_COLOR_CONFIG(GUI_COLOR_PLAYBACK_STAT,"Playback status"); + ImGui::TreePop(); + } + if (ImGui::TreeNode("File Picker (built-in)")) { + UI_COLOR_CONFIG(GUI_COLOR_FILE_DIR,"Directory"); + UI_COLOR_CONFIG(GUI_COLOR_FILE_SONG_NATIVE,"Song (native)"); + UI_COLOR_CONFIG(GUI_COLOR_FILE_SONG_IMPORT,"Song (import)"); + UI_COLOR_CONFIG(GUI_COLOR_FILE_INSTR,"Instrument"); + UI_COLOR_CONFIG(GUI_COLOR_FILE_AUDIO,"Audio"); + UI_COLOR_CONFIG(GUI_COLOR_FILE_WAVE,"Wavetable"); + UI_COLOR_CONFIG(GUI_COLOR_FILE_VGM,"VGM"); + UI_COLOR_CONFIG(GUI_COLOR_FILE_FONT,"Font"); + UI_COLOR_CONFIG(GUI_COLOR_FILE_OTHER,"Other"); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Oscilloscope")) { + UI_COLOR_CONFIG(GUI_COLOR_OSC_BORDER,"Border"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_BG1,"Background (top-left)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_BG2,"Background (top-right)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_BG3,"Background (bottom-left)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_BG4,"Background (bottom-right)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_WAVE,"Waveform"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_WAVE_PEAK,"Waveform (clip)"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_REF,"Reference"); + UI_COLOR_CONFIG(GUI_COLOR_OSC_GUIDE,"Guide"); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Volume Meter")) { + UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_LOW,"Low"); + UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_HIGH,"High"); + UI_COLOR_CONFIG(GUI_COLOR_VOLMETER_PEAK,"Clip"); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Orders")) { + UI_COLOR_CONFIG(GUI_COLOR_ORDER_ROW_INDEX,"Order number"); + UI_COLOR_CONFIG(GUI_COLOR_ORDER_ACTIVE,"Current order background"); + UI_COLOR_CONFIG(GUI_COLOR_ORDER_SIMILAR,"Similar patterns"); + UI_COLOR_CONFIG(GUI_COLOR_ORDER_INACTIVE,"Inactive patterns"); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Envelope View")) { + UI_COLOR_CONFIG(GUI_COLOR_FM_ENVELOPE,"Envelope"); + UI_COLOR_CONFIG(GUI_COLOR_FM_ENVELOPE_SUS_GUIDE,"Sustain guide"); + UI_COLOR_CONFIG(GUI_COLOR_FM_ENVELOPE_RELEASE,"Release"); + + ImGui::TreePop(); + } + if (ImGui::TreeNode("FM Editor")) { + UI_COLOR_CONFIG(GUI_COLOR_FM_ALG_BG,"Algorithm background"); + UI_COLOR_CONFIG(GUI_COLOR_FM_ALG_LINE,"Algorithm lines"); + UI_COLOR_CONFIG(GUI_COLOR_FM_MOD,"Modulator"); + UI_COLOR_CONFIG(GUI_COLOR_FM_CAR,"Carrier"); + + UI_COLOR_CONFIG(GUI_COLOR_FM_SSG,"SSG-EG"); + UI_COLOR_CONFIG(GUI_COLOR_FM_WAVE,"Waveform"); + + ImGui::TextWrapped("(the following colors only apply when \"Use separate colors for carriers/modulators in FM editor\" is on!)"); + + UI_COLOR_CONFIG(GUI_COLOR_FM_PRIMARY_MOD,"Mod. accent (primary)"); + UI_COLOR_CONFIG(GUI_COLOR_FM_SECONDARY_MOD,"Mod. accent (secondary)"); + UI_COLOR_CONFIG(GUI_COLOR_FM_BORDER_MOD,"Mod. border"); + UI_COLOR_CONFIG(GUI_COLOR_FM_BORDER_SHADOW_MOD,"Mod. border shadow"); + + UI_COLOR_CONFIG(GUI_COLOR_FM_PRIMARY_CAR,"Car. accent (primary"); + UI_COLOR_CONFIG(GUI_COLOR_FM_SECONDARY_CAR,"Car. accent (secondary)"); + UI_COLOR_CONFIG(GUI_COLOR_FM_BORDER_CAR,"Car. border"); + UI_COLOR_CONFIG(GUI_COLOR_FM_BORDER_SHADOW_CAR,"Car. border shadow"); + + ImGui::TreePop(); + } + if (ImGui::TreeNode("Macro Editor")) { + UI_COLOR_CONFIG(GUI_COLOR_MACRO_VOLUME,"Volume"); + UI_COLOR_CONFIG(GUI_COLOR_MACRO_PITCH,"Pitch"); + UI_COLOR_CONFIG(GUI_COLOR_MACRO_WAVE,"Wave"); + UI_COLOR_CONFIG(GUI_COLOR_MACRO_OTHER,"Other"); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Instrument Types")) { + UI_COLOR_CONFIG(GUI_COLOR_INSTR_FM,"FM (4-operator)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_STD,"Standard"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_GB,"Game Boy"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_C64,"C64"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_AMIGA,"Amiga/Sample"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_PCE,"PC Engine"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_AY,"AY-3-8910/SSG"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_AY8930,"AY8930"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_TIA,"TIA"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_SAA1099,"SAA1099"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_VIC,"VIC"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_PET,"PET"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_VRC6,"VRC6"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_VRC6_SAW,"VRC6 (saw)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPLL,"FM (OPLL)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPL,"FM (OPL)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_FDS,"FDS"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_VBOY,"Virtual Boy"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_N163,"Namco 163"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_SCC,"Konami SCC"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPZ,"FM (OPZ)"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_POKEY,"POKEY"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_BEEPER,"PC Beeper"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_SWAN,"WonderSwan"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_MIKEY,"Lynx"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_VERA,"VERA"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_X1_010,"X1-010"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_ES5506,"ES5506"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_MULTIPCM,"MultiPCM"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_SNES,"SNES"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_SU,"Sound Unit"); + UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,"Other/Unknown"); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Channel")) { + UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_FM,"FM"); + UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_PULSE,"Pulse"); + UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_NOISE,"Noise"); + UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_PCM,"PCM"); + UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_WAVE,"Wave"); + UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_OP,"FM operator"); + UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_MUTED,"Muted"); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Pattern")) { + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_PLAY_HEAD,"Playhead"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_CURSOR,"Cursor"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_CURSOR_HOVER,"Cursor (hovered)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_CURSOR_ACTIVE,"Cursor (clicked)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_SELECTION,"Selection"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_SELECTION_HOVER,"Selection (hovered)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_SELECTION_ACTIVE,"Selection (clicked)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_HI_1,"Highlight 1"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_HI_2,"Highlight 2"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_ROW_INDEX,"Row number"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_ROW_INDEX_HI1,"Row number (highlight 1)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_ROW_INDEX_HI2,"Row number (highlight 2)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_ACTIVE,"Note"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_ACTIVE_HI1,"Note (highlight 1)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_ACTIVE_HI2,"Note (highlight 2)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_INACTIVE,"Blank"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_INACTIVE_HI1,"Blank (highlight 1)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_INACTIVE_HI2,"Blank (highlight 2)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_INS,"Instrument"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_INS_WARN,"Instrument (invalid type)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_INS_ERROR,"Instrument (out of range)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_VOLUME_MIN,"Volume (0%)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_VOLUME_HALF,"Volume (50%)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_VOLUME_MAX,"Volume (100%)"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_INVALID,"Invalid effect"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_PITCH,"Pitch effect"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_VOLUME,"Volume effect"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_PANNING,"Panning effect"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SONG,"Song effect"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_TIME,"Time effect"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SPEED,"Speed effect"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,"Primary system effect"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,"Secondary system effect"); + UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_MISC,"Miscellaneous"); + UI_COLOR_CONFIG(GUI_COLOR_EE_VALUE,"External command output"); + ImGui::TreePop(); + } + if (ImGui::TreeNode("Log Viewer")) { + UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_ERROR,"Log level: Error"); + UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_WARNING,"Log level: Warning"); + UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_INFO,"Log level: Info"); + UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_DEBUG,"Log level: Debug"); + UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_TRACE,"Log level: Trace/Verbose"); + ImGui::TreePop(); + } ImGui::TreePop(); } - if (ImGui::TreeNode("Macro Editor")) { - UI_COLOR_CONFIG(GUI_COLOR_MACRO_VOLUME,"Volume"); - UI_COLOR_CONFIG(GUI_COLOR_MACRO_PITCH,"Pitch"); - UI_COLOR_CONFIG(GUI_COLOR_MACRO_WAVE,"Wave"); - UI_COLOR_CONFIG(GUI_COLOR_MACRO_OTHER,"Other"); - ImGui::TreePop(); - } - if (ImGui::TreeNode("Instrument Types")) { - UI_COLOR_CONFIG(GUI_COLOR_INSTR_FM,"FM (4-operator)"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_STD,"Standard"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_GB,"Game Boy"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_C64,"C64"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_AMIGA,"Amiga/Sample"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_PCE,"PC Engine"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_AY,"AY-3-8910/SSG"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_AY8930,"AY8930"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_TIA,"TIA"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_SAA1099,"SAA1099"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_VIC,"VIC"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_PET,"PET"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_VRC6,"VRC6"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_VRC6_SAW,"VRC6 (saw)"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPLL,"FM (OPLL)"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPL,"FM (OPL)"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_FDS,"FDS"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_VBOY,"Virtual Boy"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_N163,"Namco 163"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_SCC,"Konami SCC"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_OPZ,"FM (OPZ)"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_POKEY,"POKEY"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_BEEPER,"PC Beeper"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_SWAN,"WonderSwan"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_MIKEY,"Lynx"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_VERA,"VERA"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_X1_010,"X1-010"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_ES5506,"ES5506"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_MULTIPCM,"MultiPCM"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_SNES,"SNES"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_SU,"Sound Unit"); - UI_COLOR_CONFIG(GUI_COLOR_INSTR_UNKNOWN,"Other/Unknown"); - ImGui::TreePop(); - } - if (ImGui::TreeNode("Channel")) { - UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_FM,"FM"); - UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_PULSE,"Pulse"); - UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_NOISE,"Noise"); - UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_PCM,"PCM"); - UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_WAVE,"Wave"); - UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_OP,"FM operator"); - UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_MUTED,"Muted"); - ImGui::TreePop(); - } - if (ImGui::TreeNode("Pattern")) { - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_PLAY_HEAD,"Playhead"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_CURSOR,"Cursor"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_CURSOR_HOVER,"Cursor (hovered)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_CURSOR_ACTIVE,"Cursor (clicked)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_SELECTION,"Selection"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_SELECTION_HOVER,"Selection (hovered)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_SELECTION_ACTIVE,"Selection (clicked)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_HI_1,"Highlight 1"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_HI_2,"Highlight 2"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_ROW_INDEX,"Row number"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_ROW_INDEX_HI1,"Row number (highlight 1)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_ROW_INDEX_HI2,"Row number (highlight 2)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_ACTIVE,"Note"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_ACTIVE_HI1,"Note (highlight 1)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_ACTIVE_HI2,"Note (highlight 2)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_INACTIVE,"Blank"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_INACTIVE_HI1,"Blank (highlight 1)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_INACTIVE_HI2,"Blank (highlight 2)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_INS,"Instrument"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_INS_WARN,"Instrument (invalid type)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_INS_ERROR,"Instrument (out of range)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_VOLUME_MIN,"Volume (0%)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_VOLUME_HALF,"Volume (50%)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_VOLUME_MAX,"Volume (100%)"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_INVALID,"Invalid effect"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_PITCH,"Pitch effect"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_VOLUME,"Volume effect"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_PANNING,"Panning effect"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SONG,"Song effect"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_TIME,"Time effect"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SPEED,"Speed effect"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SYS_PRIMARY,"Primary system effect"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_SYS_SECONDARY,"Secondary system effect"); - UI_COLOR_CONFIG(GUI_COLOR_PATTERN_EFFECT_MISC,"Miscellaneous"); - UI_COLOR_CONFIG(GUI_COLOR_EE_VALUE,"External command output"); - ImGui::TreePop(); - } - if (ImGui::TreeNode("Log Viewer")) { - UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_ERROR,"Log level: Error"); - UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_WARNING,"Log level: Warning"); - UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_INFO,"Log level: Info"); - UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_DEBUG,"Log level: Debug"); - UI_COLOR_CONFIG(GUI_COLOR_LOGLEVEL_TRACE,"Log level: Trace/Verbose"); - ImGui::TreePop(); - } - ImGui::TreePop(); } - + ImGui::EndChild(); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("Keyboard")) { - if (ImGui::Button("Import")) { - openFileDialog(GUI_FILE_IMPORT_KEYBINDS); - } - ImGui::SameLine(); - if (ImGui::Button("Export")) { - openFileDialog(GUI_FILE_EXPORT_KEYBINDS); - } - ImGui::SameLine(); - if (ImGui::Button("Reset defaults")) { - showWarning("Are you sure you want to reset the keyboard settings?",GUI_WARN_RESET_KEYBINDS); - } - if (ImGui::TreeNode("Global hotkeys")) { - KEYBIND_CONFIG_BEGIN("keysGlobal"); - - UI_KEYBIND_CONFIG(GUI_ACTION_OPEN); - UI_KEYBIND_CONFIG(GUI_ACTION_OPEN_BACKUP); - UI_KEYBIND_CONFIG(GUI_ACTION_SAVE); - UI_KEYBIND_CONFIG(GUI_ACTION_SAVE_AS); - UI_KEYBIND_CONFIG(GUI_ACTION_UNDO); - UI_KEYBIND_CONFIG(GUI_ACTION_REDO); - UI_KEYBIND_CONFIG(GUI_ACTION_PLAY_TOGGLE); - UI_KEYBIND_CONFIG(GUI_ACTION_PLAY); - UI_KEYBIND_CONFIG(GUI_ACTION_STOP); - UI_KEYBIND_CONFIG(GUI_ACTION_PLAY_REPEAT); - UI_KEYBIND_CONFIG(GUI_ACTION_PLAY_CURSOR); - UI_KEYBIND_CONFIG(GUI_ACTION_STEP_ONE); - UI_KEYBIND_CONFIG(GUI_ACTION_OCTAVE_UP); - UI_KEYBIND_CONFIG(GUI_ACTION_OCTAVE_DOWN); - UI_KEYBIND_CONFIG(GUI_ACTION_INS_UP); - UI_KEYBIND_CONFIG(GUI_ACTION_INS_DOWN); - UI_KEYBIND_CONFIG(GUI_ACTION_STEP_UP); - UI_KEYBIND_CONFIG(GUI_ACTION_STEP_DOWN); - UI_KEYBIND_CONFIG(GUI_ACTION_TOGGLE_EDIT); - UI_KEYBIND_CONFIG(GUI_ACTION_METRONOME); - UI_KEYBIND_CONFIG(GUI_ACTION_REPEAT_PATTERN); - UI_KEYBIND_CONFIG(GUI_ACTION_FOLLOW_ORDERS); - UI_KEYBIND_CONFIG(GUI_ACTION_FOLLOW_PATTERN); - UI_KEYBIND_CONFIG(GUI_ACTION_FULLSCREEN); - UI_KEYBIND_CONFIG(GUI_ACTION_PANIC); - - KEYBIND_CONFIG_END; - ImGui::TreePop(); - } - if (ImGui::TreeNode("Window activation")) { - KEYBIND_CONFIG_BEGIN("keysWindow"); - - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_EDIT_CONTROLS); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_ORDERS); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_INS_LIST); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_INS_EDIT); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_SONG_INFO); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_PATTERN); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_WAVE_LIST); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_WAVE_EDIT); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_SAMPLE_LIST); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_SAMPLE_EDIT); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_ABOUT); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_SETTINGS); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_MIXER); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_DEBUG); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_OSCILLOSCOPE); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_CHAN_OSC); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_VOL_METER); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_STATS); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_COMPAT_FLAGS); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_PIANO); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_NOTES); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_CHANNELS); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_REGISTER_VIEW); - UI_KEYBIND_CONFIG(GUI_ACTION_WINDOW_LOG); - - UI_KEYBIND_CONFIG(GUI_ACTION_COLLAPSE_WINDOW); - UI_KEYBIND_CONFIG(GUI_ACTION_CLOSE_WINDOW); - - KEYBIND_CONFIG_END; - ImGui::TreePop(); - } - if (ImGui::TreeNode("Note input")) { - std::vector sorted; - if (ImGui::BeginTable("keysNoteInput",4)) { - for (std::map::value_type& i: noteKeys) { - std::vector::iterator j; - for (j=sorted.begin(); j!=sorted.end(); j++) { - if (j->val>i.second) { - break; - } - } - sorted.insert(j,MappedInput(i.first,i.second)); - } - - static char id[4096]; - - ImGui::TableNextRow(ImGuiTableRowFlags_Headers); - ImGui::TableNextColumn(); - ImGui::Text("Key"); - ImGui::TableNextColumn(); - ImGui::Text("Type"); - ImGui::TableNextColumn(); - ImGui::Text("Value"); - ImGui::TableNextColumn(); - ImGui::Text("Remove"); - - for (MappedInput& i: sorted) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::Text("%s",SDL_GetScancodeName((SDL_Scancode)i.scan)); - ImGui::TableNextColumn(); - if (i.val==102) { - snprintf(id,4095,"Envelope release##SNType_%d",i.scan); - if (ImGui::Button(id)) { - noteKeys[i.scan]=0; - } - } else if (i.val==101) { - snprintf(id,4095,"Note release##SNType_%d",i.scan); - if (ImGui::Button(id)) { - noteKeys[i.scan]=102; - } - } else if (i.val==100) { - snprintf(id,4095,"Note off##SNType_%d",i.scan); - if (ImGui::Button(id)) { - noteKeys[i.scan]=101; - } - } else { - snprintf(id,4095,"Note##SNType_%d",i.scan); - if (ImGui::Button(id)) { - noteKeys[i.scan]=100; - } - } - ImGui::TableNextColumn(); - if (i.val<100) { - snprintf(id,4095,"##SNValue_%d",i.scan); - if (ImGui::InputInt(id,&i.val,1,1)) { - if (i.val<0) i.val=0; - if (i.val>96) i.val=96; - noteKeys[i.scan]=i.val; - } - } - ImGui::TableNextColumn(); - snprintf(id,4095,ICON_FA_TIMES "##SNRemove_%d",i.scan); - if (ImGui::Button(id)) { - noteKeys.erase(i.scan); - } - } - ImGui::EndTable(); - - if (ImGui::BeginCombo("##SNAddNew","Add...")) { - for (int i=0; i sorted; + if (ImGui::BeginTable("keysNoteInput",4)) { + for (std::map::value_type& i: noteKeys) { + std::vector::iterator j; + for (j=sorted.begin(); j!=sorted.end(); j++) { + if (j->val>i.second) { + break; + } + } + sorted.insert(j,MappedInput(i.first,i.second)); + } + + static char id[4096]; + + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); + ImGui::TableNextColumn(); + ImGui::Text("Key"); + ImGui::TableNextColumn(); + ImGui::Text("Type"); + ImGui::TableNextColumn(); + ImGui::Text("Value"); + ImGui::TableNextColumn(); + ImGui::Text("Remove"); + + for (MappedInput& i: sorted) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("%s",SDL_GetScancodeName((SDL_Scancode)i.scan)); + ImGui::TableNextColumn(); + if (i.val==102) { + snprintf(id,4095,"Envelope release##SNType_%d",i.scan); + if (ImGui::Button(id)) { + noteKeys[i.scan]=0; + } + } else if (i.val==101) { + snprintf(id,4095,"Note release##SNType_%d",i.scan); + if (ImGui::Button(id)) { + noteKeys[i.scan]=102; + } + } else if (i.val==100) { + snprintf(id,4095,"Note off##SNType_%d",i.scan); + if (ImGui::Button(id)) { + noteKeys[i.scan]=101; + } + } else { + snprintf(id,4095,"Note##SNType_%d",i.scan); + if (ImGui::Button(id)) { + noteKeys[i.scan]=100; + } + } + ImGui::TableNextColumn(); + if (i.val<100) { + snprintf(id,4095,"##SNValue_%d",i.scan); + if (ImGui::InputInt(id,&i.val,1,1)) { + if (i.val<0) i.val=0; + if (i.val>96) i.val=96; + noteKeys[i.scan]=i.val; + } + } + ImGui::TableNextColumn(); + snprintf(id,4095,ICON_FA_TIMES "##SNRemove_%d",i.scan); + if (ImGui::Button(id)) { + noteKeys.erase(i.scan); + } + } + ImGui::EndTable(); + + if (ImGui::BeginCombo("##SNAddNew","Add...")) { + for (int i=0; i +#include void FurnaceGUI::drawStats() { if (nextWindow==GUI_WINDOW_STATS) { @@ -28,6 +29,13 @@ void FurnaceGUI::drawStats() { } if (!statsOpen) return; if (ImGui::Begin("Statistics",&statsOpen)) { + size_t lastProcTime=e->processTime; + double maxGot=1000000000.0*(double)e->getAudioDescGot().bufsize/(double)e->getAudioDescGot().rate; + String procStr=fmt::sprintf("%.1f%%",100.0*((double)lastProcTime/(double)maxGot)); + ImGui::Text("Audio load"); + ImGui::SameLine(); + ImGui::ProgressBar((double)lastProcTime/maxGot,ImVec2(-FLT_MIN,0),procStr.c_str()); + ImGui::Separator(); for (int i=0; isong.systemLen; i++) { DivDispatch* dispatch=e->getDispatch(i); for (int j=0; dispatch!=NULL && dispatch->getSampleMemCapacity(j)>0; j++) {