From ffa0727bf61bddc5ca07d219862bd63a04d9fe6b Mon Sep 17 00:00:00 2001 From: Laurens Holst Date: Mon, 2 May 2022 19:38:17 +0200 Subject: [PATCH 1/9] AY8930: Fix VGM output. It was generating writes to register addresses > 15. --- src/engine/platform/ay8930.cpp | 29 ++++++++++++++++++----------- src/engine/platform/ay8930.h | 1 + 2 files changed, 19 insertions(+), 11 deletions(-) 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); From 3f0c83eb45c08b8757bdd8d5aeb8658247e62ece Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 3 May 2022 10:20:20 +0900 Subject: [PATCH 2/9] Debug improvements Add oscilloscope debug, Hideable sample debug --- .gitignore | 1 + src/engine/dispatch.h | 6 +- src/gui/debugWindow.cpp | 118 +++++++++++++++++++++++++++++----------- 3 files changed, 92 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index df492a378..636c827fc 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ test/songs/ test/delta/ test/result/ .vs/ +CMakeSettings.json \ No newline at end of file diff --git a/src/engine/dispatch.h b/src/engine/dispatch.h index 2646a7947..8799c7821 100644 --- a/src/engine/dispatch.h +++ b/src/engine/dispatch.h @@ -222,15 +222,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/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 7b232a9cf..dc21a8c60 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -149,40 +149,94 @@ 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("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("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++) { + 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]); + c++; + } + ImGui::EndTable(); + } + ImGui::TreePop(); + } + } else { + ImGui::Text("%d: ",i); + continue; + } } ImGui::TreePop(); } From 0d5962bb08006e68ab6528d7c90c2ee896e37c3b Mon Sep 17 00:00:00 2001 From: cam900 Date: Tue, 3 May 2022 10:28:01 +0900 Subject: [PATCH 3/9] Reduce unnecessary line --- src/gui/debugWindow.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index cc4bb1592..71856c8fc 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -209,7 +209,7 @@ void FurnaceGUI::drawDebug() { ImGui::TableNextColumn(); ImGui::Text("Data"); - for (int j=0; jgetChannelCount(system); j++) { + for (int j=0; jgetChannelCount(system); j++, c++) { ImGui::TableNextRow(); // channel ImGui::TableNextColumn(); @@ -228,7 +228,6 @@ void FurnaceGUI::drawDebug() { // data ImGui::TableNextColumn(); ImGui::Text("%d",e->getOscBuffer(c)->data[needle]); - c++; } ImGui::EndTable(); } From ebc3df9494c09de950b95b08bd918acf09da5fe9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Mon, 2 May 2022 23:38:54 -0500 Subject: [PATCH 4/9] NO --- papers/doc/7-systems/opl.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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". From e40e7c0fef9cf17b738a6b96f0e99dd360f460f2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 3 May 2022 01:23:38 -0500 Subject: [PATCH 5/9] sysDef refactor, part 3 - PLEASE READ to cam900 and grauw: I have moved the per-system effect processing code to sysDef.cpp as lambdas you may want to do the same when you pull this commit. --- src/engine/engine.h | 4 +- src/engine/playback.cpp | 679 +------------------------------ src/engine/sysDef.cpp | 870 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 832 insertions(+), 721 deletions(-) diff --git a/src/engine/engine.h b/src/engine/engine.h index dc1436eed..809df944d 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -208,8 +208,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), diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index c959f64ac..0010d5a99 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -251,684 +251,13 @@ int DivEngine::dispatchCmd(DivCommand c) { } bool DivEngine::perSystemEffect(int ch, unsigned char effect, unsigned char effectVal) { - switch (sysOfChan[ch]) { - case DIV_SYSTEM_YM2612: - case DIV_SYSTEM_YM2612_EXT: - switch (effect) { - case 0x17: // DAC enable - dispatchCmd(DivCommand(DIV_CMD_SAMPLE_MODE,ch,(effectVal>0))); - break; - case 0x20: // SN noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - case 0x30: // toggle hard-reset - dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_YM2151: - case DIV_SYSTEM_YM2610: - case DIV_SYSTEM_YM2610_EXT: - case DIV_SYSTEM_YM2610B: - case DIV_SYSTEM_YM2610B_EXT: - case DIV_SYSTEM_OPZ: - switch (effect) { - case 0x30: // toggle hard-reset - dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_SMS: - switch (effect) { - case 0x20: // SN noise mode - dispatchCmd(DivCommand(DIV_CMD_STD_NOISE_MODE,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_GB: - 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; - } - break; - case DIV_SYSTEM_PCE: - 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; - } - break; - case DIV_SYSTEM_NES: - case DIV_SYSTEM_MMC5: - 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; - } - break; - case DIV_SYSTEM_FDS: - 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; - } - break; - case DIV_SYSTEM_OPLL_DRUMS: - case DIV_SYSTEM_OPL_DRUMS: - case DIV_SYSTEM_OPL2_DRUMS: - case DIV_SYSTEM_OPL3_DRUMS: - 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; - } - break; - case DIV_SYSTEM_OPLL: - case DIV_SYSTEM_VRC7: - case DIV_SYSTEM_OPL: - case DIV_SYSTEM_OPL2: - case DIV_SYSTEM_OPL3: - switch (effect) { - case 0x30: // toggle hard-reset - dispatchCmd(DivCommand(DIV_CMD_FM_HARD_RESET,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_N163: - 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; - } - break; - case DIV_SYSTEM_QSOUND: - 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; - } - break; - case DIV_SYSTEM_X1_010: - 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; - } - break; - case DIV_SYSTEM_SWAN: - 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; - } - break; - case DIV_SYSTEM_VERA: - 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; - } - break; - case DIV_SYSTEM_BUBSYS_WSG: - case DIV_SYSTEM_PET: - case DIV_SYSTEM_VIC20: - switch (effect) { - case 0x10: // select waveform - dispatchCmd(DivCommand(DIV_CMD_WAVE,ch,effectVal)); - break; - default: - return false; - } - break; - case DIV_SYSTEM_VRC6: - 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; - } - break; - default: - return false; - } - return true; + if (sysDefs[sysOfChan[ch]]==NULL) return false; + return sysDefs[sysOfChan[ch]]->effectFunc(ch,effect,effectVal); } -#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) { diff --git a/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index 8f280847c..aed1d9f7c 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,6 +334,303 @@ 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, {"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 @@ -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,7 +849,25 @@ 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( @@ -455,16 +875,35 @@ void DivEngine::registerSystems() { {"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, {"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, {"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,7 +1107,54 @@ 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( @@ -577,7 +1178,10 @@ void DivEngine::registerSystems() { {"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( @@ -585,7 +1189,10 @@ void DivEngine::registerSystems() { {"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( @@ -593,7 +1200,10 @@ 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", "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,7 +1244,29 @@ 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( @@ -642,7 +1274,19 @@ void DivEngine::registerSystems() { {"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,7 +1321,10 @@ 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( @@ -682,7 +1332,10 @@ void DivEngine::registerSystems() { {"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,7 +1406,10 @@ 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( @@ -739,7 +1417,10 @@ void DivEngine::registerSystems() { {"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. From 31a35e5395fdeac563820c55f5617a2055624d68 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 3 May 2022 01:29:31 -0500 Subject: [PATCH 6/9] better FM chip names --- TODO.md | 3 --- src/engine/sysDef.cpp | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/TODO.md b/TODO.md index 54e966303..26efc81db 100644 --- a/TODO.md +++ b/TODO.md @@ -20,8 +20,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 @@ -32,5 +30,4 @@ - 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/src/engine/sysDef.cpp b/src/engine/sysDef.cpp index aed1d9f7c..11e34187e 100644 --- a/src/engine/sysDef.cpp +++ b/src/engine/sysDef.cpp @@ -632,7 +632,7 @@ void DivEngine::registerSystems() { }; 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 @@ -871,7 +871,7 @@ void DivEngine::registerSystems() { ); 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}, @@ -896,7 +896,7 @@ void DivEngine::registerSystems() { }; 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}, @@ -1036,7 +1036,7 @@ void DivEngine::registerSystems() { }; 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}, @@ -1158,7 +1158,7 @@ void DivEngine::registerSystems() { ); 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}, @@ -1166,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}, @@ -1174,7 +1174,7 @@ 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}, @@ -1185,7 +1185,7 @@ void DivEngine::registerSystems() { ); 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}, @@ -1196,7 +1196,7 @@ void DivEngine::registerSystems() { ); 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}, @@ -1270,7 +1270,7 @@ void DivEngine::registerSystems() { ); 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}, @@ -1328,7 +1328,7 @@ void DivEngine::registerSystems() { ); 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}, @@ -1413,7 +1413,7 @@ void DivEngine::registerSystems() { ); 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}, From c23ee8e7c994bc0f12bb5e6453648a53d0abfddd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 3 May 2022 01:48:57 -0500 Subject: [PATCH 7/9] GUI: put "OK" and "Cancel" buttons in the bottom --- src/gui/settings.cpp | 2819 +++++++++++++++++++++--------------------- 1 file changed, 1420 insertions(+), 1399 deletions(-) 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 Date: Tue, 3 May 2022 02:29:12 -0500 Subject: [PATCH 8/9] GUI: add audio load meter to statistics --- TODO.md | 1 - src/engine/engine.h | 5 ++++- src/engine/playback.cpp | 7 +++++++ src/gui/stats.cpp | 8 ++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index 26efc81db..4e352566f 100644 --- a/TODO.md +++ b/TODO.md @@ -28,6 +28,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 - find and replace \ No newline at end of file diff --git a/src/engine/engine.h b/src/engine/engine.h index 809df944d..572fd90bc 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 @@ -416,6 +417,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); @@ -923,7 +925,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/playback.cpp b/src/engine/playback.cpp index 0010d5a99..5572fea05 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" @@ -1060,6 +1061,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(); @@ -1338,4 +1341,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/gui/stats.cpp b/src/gui/stats.cpp index 35d6cfc49..9e1790c9e 100644 --- a/src/gui/stats.cpp +++ b/src/gui/stats.cpp @@ -19,6 +19,7 @@ #include "gui.h" #include +#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++) { From 4c9b172b50a240efc37aec8bdd4a59972fbf10c4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 3 May 2022 02:52:38 -0500 Subject: [PATCH 9/9] YM2610: optimize oscilloscope fetch CPU usage --- src/engine/platform/sound/ymfm/ymfm_adpcm.cpp | 24 ++++++++++++------- src/engine/platform/sound/ymfm/ymfm_adpcm.h | 15 ++++++++++-- src/engine/platform/ym2610.cpp | 21 +++++++++------- src/engine/platform/ym2610b.cpp | 19 ++++++++------- 4 files changed, 52 insertions(+), 27 deletions(-) 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 3711515aa..a45266086 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 9c126c2b3..a66f0b575 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); } }