From 216acd5ec5a8130f9d9f04dea5623db3a7720a81 Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Tue, 13 Sep 2022 09:21:16 +0000 Subject: [PATCH 01/39] fix n163 doc 256 bytes, not 128. https://www.nesdev.org/wiki/Namco_163_audio also some better wording --- papers/doc/7-systems/n163.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/n163.md b/papers/doc/7-systems/n163.md index 3c2f389f9..78aca3ae6 100644 --- a/papers/doc/7-systems/n163.md +++ b/papers/doc/7-systems/n163.md @@ -1,6 +1,6 @@ # Namco 163 (also called N163, Namco C163, Namco 106 (sic), Namco 160 or Namco 129) -This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 128 byte of internal RAM, and both channel register and wavetables are stored here. Wavetables are variable size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. But waveform RAM area becomes smaller as more channels are activated; as channel registers consumes 8 bytes for each channel. You must avoid conflict with channel register area and waveform for avoid broken channel playback. +This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 256 bytes of internal RAM, and both channel register and wavetables are stored here. Wavetables are variable in size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. But waveform RAM area becomes smaller as more channels are activated; as channel registers consume 8 bytes for each channel. You must avoid conflict with channel register area and waveform to avoid broken channel playback. It outputs only a single channel at clock; so its sound quality gets more crunchy as more channels are activated. From f60e650a91070cdd7914150e7d1888c6bc1707d5 Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Tue, 13 Sep 2022 19:18:08 +0000 Subject: [PATCH 02/39] correct doc no brainwashing --- papers/doc/7-systems/n163.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/papers/doc/7-systems/n163.md b/papers/doc/7-systems/n163.md index 78aca3ae6..fb9502deb 100644 --- a/papers/doc/7-systems/n163.md +++ b/papers/doc/7-systems/n163.md @@ -1,8 +1,8 @@ # Namco 163 (also called N163, Namco C163, Namco 106 (sic), Namco 160 or Namco 129) -This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 256 bytes of internal RAM, and both channel register and wavetables are stored here. Wavetables are variable in size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. But waveform RAM area becomes smaller as more channels are activated; as channel registers consume 8 bytes for each channel. You must avoid conflict with channel register area and waveform to avoid broken channel playback. +This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 256 nibbles (128 bytes) of internal RAM, and both channel registers and wavetables are stored here. Wavetables are variable in size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. At least 64 bytes can dedicated to waves, with more available if not all channels are used - waveform RAM area becomes smaller as more channels are activated, since channel registers consume 8 bytes for each channel. You must avoid conflict with channel register area and waveform to avoid broken channel playback. -It outputs only a single channel at clock; so its sound quality gets more crunchy as more channels are activated. +Namco 163 does not internally mix its channels. Instead, each channel is output one at a time, when multiple channels are used it will cycle between them; so its sound quality gets more crunchy as more channels are activated. Furnace supports loading waveforms into RAM and waveform playback simultaneously, and channel limit is dynamically changeable with effect commands. You must load waveform to RAM first for playback, as its load behavior auto-updates when every waveform changes. From 6a735ee3487068f4fface2ee4b38611f867472a2 Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Tue, 13 Sep 2022 19:25:37 +0000 Subject: [PATCH 03/39] no noise for MMC5 --- papers/doc/7-systems/mmc5.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/mmc5.md b/papers/doc/7-systems/mmc5.md index faf305c60..5949dbb94 100644 --- a/papers/doc/7-systems/mmc5.md +++ b/papers/doc/7-systems/mmc5.md @@ -9,4 +9,4 @@ additionally, it offers an 8-bit DAC which can be used to play samples. only one # effects - `12xx`: set duty cycle or noise mode of channel. - - may be 0-3 for the pulse channels and 0-1 for the noise channel. + - may be 0-3 for the pulse channels From 70ca9033c76bef4d8624f09d11b1cb1f13209782 Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Tue, 13 Sep 2022 19:58:43 +0000 Subject: [PATCH 04/39] Add Generic PCM DAC document --- papers/doc/7-systems/dac.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 papers/doc/7-systems/dac.md diff --git a/papers/doc/7-systems/dac.md b/papers/doc/7-systems/dac.md new file mode 100644 index 000000000..856db2cd0 --- /dev/null +++ b/papers/doc/7-systems/dac.md @@ -0,0 +1,7 @@ +# Generic PCM DAC + +Realtek HD Audio's predecessor. It's just a 1/8/16-bit sample channel, with freely selectable rate and mono/stereo settings. With it, you can emulate PCM DACs found in Williams arcade boards, Sound Blasters, MSX TurboR, Atari STE, NEC PC-9801-86 etc. + +# effects + +none yet. From 359fda701677d83f1d9c58a96da5e3ca2c34825b Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Wed, 14 Sep 2022 11:04:28 +0000 Subject: [PATCH 05/39] addressing feedback --- papers/doc/7-systems/mmc5.md | 2 +- papers/doc/7-systems/n163.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/papers/doc/7-systems/mmc5.md b/papers/doc/7-systems/mmc5.md index 5949dbb94..d483bd57c 100644 --- a/papers/doc/7-systems/mmc5.md +++ b/papers/doc/7-systems/mmc5.md @@ -9,4 +9,4 @@ additionally, it offers an 8-bit DAC which can be used to play samples. only one # effects - `12xx`: set duty cycle or noise mode of channel. - - may be 0-3 for the pulse channels + - may be 0-3 for the pulse channels. diff --git a/papers/doc/7-systems/n163.md b/papers/doc/7-systems/n163.md index fb9502deb..90f432289 100644 --- a/papers/doc/7-systems/n163.md +++ b/papers/doc/7-systems/n163.md @@ -1,8 +1,8 @@ # Namco 163 (also called N163, Namco C163, Namco 106 (sic), Namco 160 or Namco 129) -This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 256 nibbles (128 bytes) of internal RAM, and both channel registers and wavetables are stored here. Wavetables are variable in size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. At least 64 bytes can dedicated to waves, with more available if not all channels are used - waveform RAM area becomes smaller as more channels are activated, since channel registers consume 8 bytes for each channel. You must avoid conflict with channel register area and waveform to avoid broken channel playback. +This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 256 nibbles (128 bytes) of internal RAM, and both channel registers and wavetables are stored here. Wavetables are variable in size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. At least 128 nibbles (64 bytes) can be dedicated to waves, with more available if not all channels are used - waveform RAM area becomes smaller as more channels are activated, since channel registers consume 8 bytes for each channel. You must avoid conflict with channel register area and waveform to avoid broken channel playback. -Namco 163 does not internally mix its channels. Instead, each channel is output one at a time, when multiple channels are used it will cycle between them; so its sound quality gets more crunchy as more channels are activated. +Namco 163 does not internally mix its channels. Because of that, only one channel can be output at the time, when multiple channels are used it will cycle between them, similarily to OPLL. Therefore, its sound quality gets more crunchy as more channels are activated. Furnace supports loading waveforms into RAM and waveform playback simultaneously, and channel limit is dynamically changeable with effect commands. You must load waveform to RAM first for playback, as its load behavior auto-updates when every waveform changes. From 6bf6a854efc9d6d702699a48484e689396b3b993 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 17 Sep 2022 22:55:58 -0500 Subject: [PATCH 06/39] GUI: comfortable wave macro height --- src/gui/doAction.cpp | 3 +++ src/gui/gui.cpp | 1 + src/gui/gui.h | 6 ++++++ src/gui/insEdit.cpp | 2 +- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/gui/doAction.cpp b/src/gui/doAction.cpp index 92e12a742..468b7e37c 100644 --- a/src/gui/doAction.cpp +++ b/src/gui/doAction.cpp @@ -645,6 +645,7 @@ void FurnaceGUI::doAction(int what) { } else { wantScrollList=true; MARK_MODIFIED; + RESET_WAVE_MACRO_ZOOM; } break; case GUI_ACTION_WAVE_LIST_DUPLICATE: @@ -657,6 +658,7 @@ void FurnaceGUI::doAction(int what) { (*e->song.wave[curWave])=(*e->song.wave[prevWave]); wantScrollList=true; MARK_MODIFIED; + RESET_WAVE_MACRO_ZOOM; } } break; @@ -1326,6 +1328,7 @@ void FurnaceGUI::doAction(int what) { } nextWindow=GUI_WINDOW_WAVE_EDIT; MARK_MODIFIED; + RESET_WAVE_MACRO_ZOOM; } } break; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 5153e1f6a..06fc65f08 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3884,6 +3884,7 @@ bool FurnaceGUI::loop() { showError("cannot load wavetable! ("+e->getLastError()+")"); } else { MARK_MODIFIED; + RESET_WAVE_MACRO_ZOOM; } } break; diff --git a/src/gui/gui.h b/src/gui/gui.h index 1c8ee713f..6499c4d19 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -47,6 +47,12 @@ #define MARK_MODIFIED modified=true; #define WAKE_UP drawHalt=16; +#define RESET_WAVE_MACRO_ZOOM \ + for (DivInstrument* _wi: e->song.ins) { \ + _wi->std.waveMacro.vZoom=-1; \ + _wi->std.waveMacro.vScroll=-1; \ + } + #define BIND_FOR(x) getKeyName(actionKeys[x],true).c_str() // TODO: diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index b5347cbee..50fd286b8 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -4227,7 +4227,7 @@ void FurnaceGUI::drawInsEdit() { } const char* waveLabel="Waveform"; - int waveMax=(ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VERA)?3:255; + int waveMax=(ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_VERA)?3:(MAX(1,e->song.waveLen-1)); bool bitMode=false; if (ins->type==DIV_INS_C64 || ins->type==DIV_INS_AY || ins->type==DIV_INS_AY8930 || ins->type==DIV_INS_SAA1099) { bitMode=true; From ca224632a1109a960c691b0186be6f4824f7212c Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 18 Sep 2022 00:26:51 -0500 Subject: [PATCH 07/39] further polish Namco 163 doc --- papers/doc/7-systems/n163.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/papers/doc/7-systems/n163.md b/papers/doc/7-systems/n163.md index 90f432289..efdc3c506 100644 --- a/papers/doc/7-systems/n163.md +++ b/papers/doc/7-systems/n163.md @@ -2,7 +2,7 @@ This is one of Namco's NES mappers, with up to 8 wavetable channels. It has also 256 nibbles (128 bytes) of internal RAM, and both channel registers and wavetables are stored here. Wavetables are variable in size and freely allocable anywhere in RAM, it means it can use part of or continuously pre-loaded waveform and its sequences in RAM. At least 128 nibbles (64 bytes) can be dedicated to waves, with more available if not all channels are used - waveform RAM area becomes smaller as more channels are activated, since channel registers consume 8 bytes for each channel. You must avoid conflict with channel register area and waveform to avoid broken channel playback. -Namco 163 does not internally mix its channels. Because of that, only one channel can be output at the time, when multiple channels are used it will cycle between them, similarily to OPLL. Therefore, its sound quality gets more crunchy as more channels are activated. +Namco 163 uses time-division multiplexing for its output. this means that only one channel is output per sample (like OPLL and OPN2). therefore, its sound quality gets worse as more channels are activated. Furnace supports loading waveforms into RAM and waveform playback simultaneously, and channel limit is dynamically changeable with effect commands. You must load waveform to RAM first for playback, as its load behavior auto-updates when every waveform changes. From 75bcad558aa9058fbc0a4a2e27a6d3ed315a7046 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 18 Sep 2022 03:51:10 -0500 Subject: [PATCH 08/39] GUI: channel customization, part 1 --- TODO.md | 4 ++-- src/gui/gui.cpp | 32 ++++++++++++++++++++++++++++++++ src/gui/gui.h | 4 ++++ src/gui/guiConst.cpp | 2 ++ src/gui/pattern.cpp | 39 ++++++++++++++++++++++++++++++++------- src/gui/settings.cpp | 14 ++++++++------ 6 files changed, 80 insertions(+), 15 deletions(-) diff --git a/TODO.md b/TODO.md index 859ad68c2..a0da2bbdd 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,6 @@ - stereo separation control for AY - "paste with instrument" -- FM operator muting -- FM operator swap +- channel appearance settings +- auto-detect system - bug fixes diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 06fc65f08..40869c425 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -584,6 +584,38 @@ void FurnaceGUI::updateWindowTitle() { if (sdlWin!=NULL) SDL_SetWindowTitle(sdlWin,title.c_str()); } +ImVec4 FurnaceGUI::channelColor(int ch) { + switch (settings.channelColors) { + case 0: + return uiColors[GUI_COLOR_CHANNEL_BG]; + break; + case 1: + return uiColors[GUI_COLOR_CHANNEL_FM+e->getChannelType(ch)]; + break; + case 2: + return uiColors[GUI_COLOR_INSTR_STD+e->getPreferInsType(ch)]; + break; + } + // invalid + return uiColors[GUI_COLOR_TEXT]; +} + +ImVec4 FurnaceGUI::channelTextColor(int ch) { + switch (settings.channelTextColors) { + case 0: + return uiColors[GUI_COLOR_CHANNEL_FG]; + break; + case 1: + return uiColors[GUI_COLOR_CHANNEL_FM+e->getChannelType(ch)]; + break; + case 2: + return uiColors[GUI_COLOR_INSTR_STD+e->getPreferInsType(ch)]; + break; + } + // invalid + return uiColors[GUI_COLOR_TEXT]; +} + const char* defaultLayout="[Window][DockSpaceViewport_11111111]\n\ Pos=0,24\n\ Size=1280,731\n\ diff --git a/src/gui/gui.h b/src/gui/gui.h index 6499c4d19..b9784f3f6 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -161,6 +161,8 @@ enum FurnaceGUIColors { GUI_COLOR_INSTR_OPL_DRUMS, GUI_COLOR_INSTR_UNKNOWN, + GUI_COLOR_CHANNEL_BG, + GUI_COLOR_CHANNEL_FG, GUI_COLOR_CHANNEL_FM, GUI_COLOR_CHANNEL_PULSE, GUI_COLOR_CHANNEL_NOISE, @@ -1604,6 +1606,8 @@ class FurnaceGUI { void updateWindowTitle(); void prepareLayout(); + ImVec4 channelColor(int ch); + ImVec4 channelTextColor(int ch); void readOsc(); diff --git a/src/gui/guiConst.cpp b/src/gui/guiConst.cpp index e79de4106..7c987358e 100644 --- a/src/gui/guiConst.cpp +++ b/src/gui/guiConst.cpp @@ -774,6 +774,8 @@ const FurnaceGUIColorDef guiColors[GUI_COLOR_MAX]={ D(GUI_COLOR_INSTR_OPL_DRUMS,"",ImVec4(0.3f,1.0f,0.9f,1.0f)), D(GUI_COLOR_INSTR_UNKNOWN,"",ImVec4(0.3f,0.3f,0.3f,1.0f)), + D(GUI_COLOR_CHANNEL_BG,"",ImVec4(0.4f,0.6f,0.8f,1.0f)), + D(GUI_COLOR_CHANNEL_FG,"",ImVec4(1.0f,1.0f,1.0f,1.0f)), D(GUI_COLOR_CHANNEL_FM,"",ImVec4(0.2f,0.8f,1.0f,1.0f)), D(GUI_COLOR_CHANNEL_PULSE,"",ImVec4(0.4f,1.0f,0.2f,1.0f)), D(GUI_COLOR_CHANNEL_NOISE,"",ImVec4(0.8f,0.8f,0.8f,1.0f)), diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index ec65101df..e6bbc72fa 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -468,20 +468,44 @@ void FurnaceGUI::drawPattern() { snprintf(chanID,2048," %s##_CH%d",chName,i); } } + bool muted=e->isChannelMuted(i); - ImVec4 chanHead=muted?uiColors[GUI_COLOR_CHANNEL_MUTED]:uiColors[GUI_COLOR_CHANNEL_FM+e->getChannelType(i)]; + ImVec4 chanHead=muted?uiColors[GUI_COLOR_CHANNEL_MUTED]:channelColor(i); ImVec4 chanHeadActive=chanHead; ImVec4 chanHeadHover=chanHead; + if (e->keyHit[i]) { - keyHit[i]=0.2; - if (!muted) { - int note=e->getChanState(i)->note+60; - if (note>=0 && note<180) { - pianoKeyHit[note]=1.0; + if (settings.channelFeedbackStyle==1) { + keyHit[i]=0.2; + if (!muted) { + int note=e->getChanState(i)->note+60; + if (note>=0 && note<180) { + pianoKeyHit[note]=1.0; + } } } e->keyHit[i]=false; } + if (settings.channelFeedbackStyle==2 && e->isRunning()) { + float amount=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i)); + if (!e->getChanState(i)->keyOn) amount=0.0f; + keyHit[i]=amount*0.2f; + if (!muted) { + int note=e->getChanState(i)->note+60; + if (note>=0 && note<180) { + pianoKeyHit[note]=amount; + } + } + } else if (settings.channelFeedbackStyle==3 && e->isRunning()) { + bool active=e->getChanState(i)->keyOn; + keyHit[i]=active?0.2f:0.0f; + if (!muted) { + int note=e->getChanState(i)->note+60; + if (note>=0 && note<180) { + pianoKeyHit[note]=active?1.0f:0.0f; + } + } + } if (settings.guiColorsBase) { chanHead.x*=1.0-keyHit[i]; chanHead.y*=1.0-keyHit[i]; chanHead.z*=1.0-keyHit[i]; chanHeadActive.x*=0.5; chanHeadActive.y*=0.5; chanHeadActive.z*=0.5; @@ -496,6 +520,7 @@ void FurnaceGUI::drawPattern() { ImGui::PushStyleColor(ImGuiCol_Header,chanHead); ImGui::PushStyleColor(ImGuiCol_HeaderActive,chanHeadActive); ImGui::PushStyleColor(ImGuiCol_HeaderHovered,chanHeadHover); + ImGui::PushStyleColor(ImGuiCol_Text,ImGui::GetColorU32(channelTextColor(i))); ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(chanHead)); if (muted) ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_CHANNEL_MUTED]); ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); @@ -513,7 +538,7 @@ void FurnaceGUI::drawPattern() { } } if (muted) ImGui::PopStyleColor(); - ImGui::PopStyleColor(3); + ImGui::PopStyleColor(4); if (settings.soloAction!=2) if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) { inhibitMenu=true; e->toggleSolo(i); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 54da8e893..1bb946522 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1284,14 +1284,14 @@ void FurnaceGUI::drawSettings() { } ImGui::Text("Channel name colors:"); - if (ImGui::RadioButton("Single##CTC0",settings.channelColors==0)) { - settings.channelColors=0; + if (ImGui::RadioButton("Single##CTC0",settings.channelTextColors==0)) { + settings.channelTextColors=0; } - if (ImGui::RadioButton("Channel type##CTC1",settings.channelColors==1)) { - settings.channelColors=1; + if (ImGui::RadioButton("Channel type##CTC1",settings.channelTextColors==1)) { + settings.channelTextColors=1; } - if (ImGui::RadioButton("Instrument type##CTC2",settings.channelColors==2)) { - settings.channelColors=2; + if (ImGui::RadioButton("Instrument type##CTC2",settings.channelTextColors==2)) { + settings.channelTextColors=2; } ImGui::Text("Channel style:"); @@ -1659,6 +1659,8 @@ void FurnaceGUI::drawSettings() { ImGui::TreePop(); } if (ImGui::TreeNode("Channel")) { + UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_BG,"Single color (background)"); + UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_FG,"Single color (text)"); UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_FM,"FM"); UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_PULSE,"Pulse"); UI_COLOR_CONFIG(GUI_COLOR_CHANNEL_NOISE,"Noise"); From ebb939c1896d4f0c5f075b0e61920d806e1000b9 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 18 Sep 2022 04:20:08 -0500 Subject: [PATCH 09/39] GUI: add channel font option --- src/gui/gui.h | 2 ++ src/gui/pattern.cpp | 5 +++++ src/gui/settings.cpp | 12 ++++++++++++ 3 files changed, 19 insertions(+) diff --git a/src/gui/gui.h b/src/gui/gui.h index b9784f3f6..09155f9be 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1178,6 +1178,7 @@ class FurnaceGUI { int channelStyle; int channelVolStyle; int channelFeedbackStyle; + int channelFont; int maxRecentFile; unsigned int maxUndoSteps; String mainFontPath; @@ -1299,6 +1300,7 @@ class FurnaceGUI { channelStyle(0), channelVolStyle(0), channelFeedbackStyle(1), + channelFont(1), maxRecentFile(10), maxUndoSteps(100), mainFontPath(""), diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index e6bbc72fa..4fbb99977 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -523,10 +523,15 @@ void FurnaceGUI::drawPattern() { ImGui::PushStyleColor(ImGuiCol_Text,ImGui::GetColorU32(channelTextColor(i))); ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(chanHead)); if (muted) ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_CHANNEL_MUTED]); + if (settings.channelFont==0) ImGui::PushFont(mainFont); + + // TODO: appearance ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); + if (displayTooltip && ImGui::IsItemHovered()) { ImGui::SetTooltip("%s",e->getChannelName(i)); } + if (settings.channelFont==0) ImGui::PopFont(); if (ImGui::IsItemClicked(ImGuiMouseButton_Left)) { if (settings.soloAction!=1 && soloTimeout>0 && soloChan==i) { e->toggleSolo(i); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index 1bb946522..c771f6a16 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1343,6 +1343,15 @@ void FurnaceGUI::drawSettings() { settings.channelFeedbackStyle=3; } + ImGui::Text("Channel font:"); + + if (ImGui::RadioButton("Regular##CHFont0",settings.channelFont==0)) { + settings.channelFont=0; + } + if (ImGui::RadioButton("Monospace##CHFont1",settings.channelFont==1)) { + settings.channelFont=1; + } + ImGui::Separator(); bool insEditColorizeB=settings.insEditColorize; @@ -2282,6 +2291,7 @@ void FurnaceGUI::syncSettings() { settings.channelStyle=e->getConfInt("channelStyle",0); settings.channelVolStyle=e->getConfInt("channelVolStyle",0); settings.channelFeedbackStyle=e->getConfInt("channelFeedbackStyle",1); + settings.channelFont=e->getConfInt("channelFont",1); settings.maxRecentFile=e->getConfInt("maxRecentFile",10); clampSetting(settings.mainFontSize,2,96); @@ -2381,6 +2391,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.channelStyle,0,5); clampSetting(settings.channelVolStyle,0,3); clampSetting(settings.channelFeedbackStyle,0,3); + clampSetting(settings.channelFont,0,1); clampSetting(settings.maxRecentFile,0,30); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); @@ -2536,6 +2547,7 @@ void FurnaceGUI::commitSettings() { e->setConf("channelStyle",settings.channelStyle); e->setConf("channelVolStyle",settings.channelVolStyle); e->setConf("channelFeedbackStyle",settings.channelFeedbackStyle); + e->setConf("channelFont",settings.channelFont); e->setConf("maxRecentFile",settings.maxRecentFile); // colors From 3cb1571fb6c85794d19ec3c9f459f9113fb57a04 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 20 Sep 2022 01:00:31 -0500 Subject: [PATCH 10/39] GUI: implement channel style settings --- extern/imgui_patched/imgui.h | 2 + extern/imgui_patched/imgui_tables.cpp | 2 +- src/gui/pattern.cpp | 135 +++++++++++++++++++++++++- src/gui/sysEx.cpp | 1 + 4 files changed, 135 insertions(+), 5 deletions(-) diff --git a/extern/imgui_patched/imgui.h b/extern/imgui_patched/imgui.h index 7249c5402..e9ccea9b1 100644 --- a/extern/imgui_patched/imgui.h +++ b/extern/imgui_patched/imgui.h @@ -1220,6 +1220,8 @@ enum ImGuiTableFlags_ // Sorting ImGuiTableFlags_SortMulti = 1 << 26, // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1). ImGuiTableFlags_SortTristate = 1 << 27, // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0). + // tildearrow + ImGuiTableFlags_NoBordersInFrozenArea = 1 << 28, // Disable vertical borders in frozen area. // [Internal] Combinations and masks ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame diff --git a/extern/imgui_patched/imgui_tables.cpp b/extern/imgui_patched/imgui_tables.cpp index 5a21a0b13..46bf0b132 100644 --- a/extern/imgui_patched/imgui_tables.cpp +++ b/extern/imgui_patched/imgui_tables.cpp @@ -2532,7 +2532,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) // Draw inner border and resizing feedback ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); const float border_size = TABLE_BORDER_SIZE; - const float draw_y1 = table->InnerRect.Min.y; + const float draw_y1 = table->InnerRect.Min.y + ((table->Flags & ImGuiTableFlags_NoBordersInFrozenArea)?table_instance->LastFirstRowHeight:0.0f); const float draw_y2_body = table->InnerRect.Max.y; const float draw_y2_head = table->IsUsingHeaders ? ImMin(table->InnerRect.Max.y, (table->FreezeRowsCount >= 1 ? table->InnerRect.Min.y : table->WorkRect.Min.y) + table_instance->LastFirstRowHeight) : draw_y1; if (table->Flags & ImGuiTableFlags_BordersInnerV) diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index 4fbb99977..b986cedc6 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +// for suck's fake Clang extension! #define _USE_MATH_DEFINES #include "gui.h" #include "../ta-log.h" @@ -400,7 +401,7 @@ void FurnaceGUI::drawPattern() { ImGui::PushStyleColor(ImGuiCol_Header,uiColors[GUI_COLOR_PATTERN_SELECTION]); ImGui::PushStyleColor(ImGuiCol_HeaderHovered,uiColors[GUI_COLOR_PATTERN_SELECTION_HOVER]); ImGui::PushStyleColor(ImGuiCol_HeaderActive,uiColors[GUI_COLOR_PATTERN_SELECTION_ACTIVE]); - if (ImGui::BeginTable("PatternView",displayChans+2,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY|ImGuiTableFlags_NoPadInnerX)) { + if (ImGui::BeginTable("PatternView",displayChans+2,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_ScrollX|ImGuiTableFlags_ScrollY|ImGuiTableFlags_NoPadInnerX|ImGuiTableFlags_NoBordersInFrozenArea)) { ImGui::TableSetupColumn("pos",ImGuiTableColumnFlags_WidthFixed); char chanID[2048]; float lineHeight=(ImGui::GetTextLineHeight()+2*dpiScale); @@ -473,6 +474,7 @@ void FurnaceGUI::drawPattern() { ImVec4 chanHead=muted?uiColors[GUI_COLOR_CHANNEL_MUTED]:channelColor(i); ImVec4 chanHeadActive=chanHead; ImVec4 chanHeadHover=chanHead; + ImVec4 chanHeadBase=chanHead; if (e->keyHit[i]) { if (settings.channelFeedbackStyle==1) { @@ -515,18 +517,140 @@ void FurnaceGUI::drawPattern() { chanHeadActive.x*=0.8; chanHeadActive.y*=0.8; chanHeadActive.z*=0.8; chanHeadHover.x*=0.4+keyHit[i]; chanHeadHover.y*=0.4+keyHit[i]; chanHeadHover.z*=0.4+keyHit[i]; } - keyHit[i]-=0.02*60.0*ImGui::GetIO().DeltaTime; + keyHit[i]-=((settings.channelStyle==0)?0.02:0.01)*60.0*ImGui::GetIO().DeltaTime; if (keyHit[i]<0) keyHit[i]=0; ImGui::PushStyleColor(ImGuiCol_Header,chanHead); ImGui::PushStyleColor(ImGuiCol_HeaderActive,chanHeadActive); ImGui::PushStyleColor(ImGuiCol_HeaderHovered,chanHeadHover); ImGui::PushStyleColor(ImGuiCol_Text,ImGui::GetColorU32(channelTextColor(i))); - ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(chanHead)); + if (settings.channelStyle==0) ImGui::TableSetBgColor(ImGuiTableBgTarget_CellBg,ImGui::GetColorU32(chanHead)); if (muted) ImGui::PushStyleColor(ImGuiCol_Text,uiColors[GUI_COLOR_CHANNEL_MUTED]); if (settings.channelFont==0) ImGui::PushFont(mainFont); // TODO: appearance - ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); + ImGuiWindow* window=ImGui::GetCurrentWindow(); + ImVec2 size=ImVec2( + 1.0f, + lineHeight+1.0f*dpiScale+6.0*dpiScale + ); + ImDrawList* dl=ImGui::GetWindowDrawList(); + + if (settings.channelStyle==2) { + size.y+=6.0f*dpiScale; + } + + ImVec2 minArea=window->DC.CursorPos; + ImVec2 maxArea=ImVec2( + minArea.x+window->WorkRect.Max.x-window->WorkRect.Min.x, + minArea.y+size.y + ); + ImRect rect=ImRect(minArea,maxArea); + switch (settings.channelStyle) { + case 0: // classic + ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); + break; + case 1: { // line + ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID(chanID))) { + bool hovered=ImGui::ItemHoverable(rect,ImGui::GetID(chanID)); + ImU32 fadeCol0=ImGui::GetColorU32(ImVec4( + chanHeadBase.x, + chanHeadBase.y, + chanHeadBase.z, + hovered?0.25f:0.0f + )); + ImU32 fadeCol=ImGui::GetColorU32(ImVec4( + chanHeadBase.x, + chanHeadBase.y, + chanHeadBase.z, + hovered?0.5f:MIN(1.0f,chanHeadBase.w*keyHit[i]*4.0f) + )); + dl->AddRectFilledMultiColor(rect.Min,rect.Max,fadeCol0,fadeCol0,fadeCol,fadeCol); + dl->AddLine(ImVec2(rect.Min.x,rect.Max.y),ImVec2(rect.Max.x,rect.Max.y),ImGui::GetColorU32(chanHeadBase),2.0f*dpiScale); + dl->AddText(ImVec2(rect.Min.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + } + break; + } + case 2: { // round + ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID(chanID))) { + bool hovered=ImGui::ItemHoverable(rect,ImGui::GetID(chanID)); + ImU32 fadeCol0=ImGui::GetColorU32(ImVec4( + chanHeadBase.x, + chanHeadBase.y, + chanHeadBase.z, + hovered?0.5f:MIN(1.0f,0.3f+chanHeadBase.w*keyHit[i]*1.5f) + )); + ImU32 fadeCol=ImGui::GetColorU32(ImVec4( + chanHeadBase.x, + chanHeadBase.y, + chanHeadBase.z, + hovered?0.3f:MIN(1.0f,0.2f+chanHeadBase.w*keyHit[i]*1.2f) + )); + ImVec2 rMin=rect.Min; + ImVec2 rMax=rect.Max; + rMin.x+=3.0f*dpiScale; + rMin.y+=6.0f*dpiScale; + rMax.x-=3.0f*dpiScale; + rMax.y-=6.0f*dpiScale; + dl->AddRectFilledMultiColor(rMin,rMax,fadeCol0,fadeCol0,fadeCol,fadeCol,4.0f*dpiScale); + dl->AddText(ImVec2(rect.Min.x,rect.Min.y+6.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + } + break; + } + case 3: // split button + ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale)); + ImGui::TextUnformatted(chanID,strstr(chanID,"##")); + ImGui::SameLine(); + ImGui::PushFont(mainFont); + ImGui::PushID(chanID); + ImGui::SmallButton(muted?ICON_FA_VOLUME_OFF:ICON_FA_VOLUME_UP); + ImGui::PopID(); + ImGui::PopFont(); + break; + case 4: { // square border + ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID(chanID))) { + bool hovered=ImGui::ItemHoverable(rect,ImGui::GetID(chanID)); + ImU32 fadeCol=ImGui::GetColorU32(ImVec4( + chanHeadBase.x, + chanHeadBase.y, + chanHeadBase.z, + hovered?1.0f:MIN(1.0f,0.2f+chanHeadBase.w*keyHit[i]*4.0f) + )); + ImVec2 rMin=rect.Min; + ImVec2 rMax=rect.Max; + rMin.x+=2.0f*dpiScale; + rMin.y+=3.0f*dpiScale; + rMax.x-=3.0f*dpiScale; + rMax.y-=3.0f*dpiScale; + dl->AddRect(rMin,rMax,fadeCol,0.0f,2.0*dpiScale); + dl->AddText(ImVec2(rect.Min.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + } + break; + } + case 5: { // round border + ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); + if (ImGui::ItemAdd(rect,ImGui::GetID(chanID))) { + bool hovered=ImGui::ItemHoverable(rect,ImGui::GetID(chanID)); + ImU32 fadeCol=ImGui::GetColorU32(ImVec4( + chanHeadBase.x, + chanHeadBase.y, + chanHeadBase.z, + hovered?1.0f:MIN(1.0f,0.2f+chanHeadBase.w*keyHit[i]*4.0f) + )); + ImVec2 rMin=rect.Min; + ImVec2 rMax=rect.Max; + rMin.x+=2.0f*dpiScale; + rMin.y+=3.0f*dpiScale; + rMax.x-=3.0f*dpiScale; + rMax.y-=3.0f*dpiScale; + dl->AddRect(rMin,rMax,fadeCol,4.0f*dpiScale,ImDrawFlags_RoundCornersAll,2.0*dpiScale); + dl->AddText(ImVec2(rect.Min.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + } + break; + } + } if (displayTooltip && ImGui::IsItemHovered()) { ImGui::SetTooltip("%s",e->getChannelName(i)); @@ -548,6 +672,9 @@ void FurnaceGUI::drawPattern() { inhibitMenu=true; e->toggleSolo(i); } + if (settings.channelStyle==3) { + ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale)); + } if (extraChannelButtons==2) { DivPattern* pat=e->curPat[i].getPattern(e->curOrders->ord[i][ord],true); ImGui::PushFont(mainFont); diff --git a/src/gui/sysEx.cpp b/src/gui/sysEx.cpp index f8849b562..5a72649ee 100644 --- a/src/gui/sysEx.cpp +++ b/src/gui/sysEx.cpp @@ -60,6 +60,7 @@ bool FurnaceGUI::parseSysEx(unsigned char* data, size_t len) { op.rs=reader.readC(); reader.readC(); // EBS - ignore op.am=reader.readC(); + // TODO: don't ignore after I add KVS to Furnace reader.readC(); // KVS - ignore op.tl=3+((99-reader.readC())*124)/99; unsigned char freq=reader.readC(); From 1a84812a1ddfaac14be9a294d743b71c99e6b82b Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 20 Sep 2022 01:03:44 -0500 Subject: [PATCH 11/39] OPNA: fix forceIns RSS/ADPCM volume --- src/engine/platform/ym2608.cpp | 5 +++++ src/engine/platform/ym2608ext.cpp | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index ec90c1c6b..42bea41b2 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -1114,6 +1114,11 @@ void DivPlatformYM2608::forceIns() { } for (int i=9; i<16; i++) { chan[i].insChanged=true; + if (i>14) { // ADPCM-B + immWrite(0x10b,chan[i].outVol); + } else { + immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].vol)); + } } ay->forceIns(); diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index c6d7e03b6..116f6b95c 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -472,8 +472,13 @@ void DivPlatformYM2608Ext::forceIns() { chan[i].freqChanged=true; } } - for (int i=6; i<16; i++) { + for (int i=9; i<16; i++) { chan[i].insChanged=true; + if (i>14) { // ADPCM-B + immWrite(0x10b,chan[i].outVol); + } else { + immWrite(0x18+(i-9),isMuted[i]?0:((chan[i].pan<<6)|chan[i].vol)); + } } ay->forceIns(); ay->flushWrites(); From e1890173b266efa2bb95d6648eb21f4f2deaf077 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 20 Sep 2022 02:32:23 -0500 Subject: [PATCH 12/39] GUI: implement channel volume bar --- TODO.md | 1 - src/engine/platform/ay.cpp | 2 +- src/engine/platform/ay8930.cpp | 2 +- src/engine/platform/sms.cpp | 4 +-- src/gui/chanOsc.cpp | 34 +++++++++++++++++++- src/gui/gui.cpp | 8 +++++ src/gui/gui.h | 2 ++ src/gui/pattern.cpp | 58 +++++++++++++++++++++++++++++++++- src/gui/settings.cpp | 5 ++- 9 files changed, 108 insertions(+), 8 deletions(-) diff --git a/TODO.md b/TODO.md index a0da2bbdd..028f21077 100644 --- a/TODO.md +++ b/TODO.md @@ -2,6 +2,5 @@ - stereo separation control for AY - "paste with instrument" -- channel appearance settings - auto-detect system - bug fixes diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index 23f20c2a0..f475b4750 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -126,7 +126,7 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l } for (int ch=0; ch<3; ch++) { for (size_t i=0; idata[oscBuf[ch]->needle++]=ayBuf[ch][i]; + oscBuf[ch]->data[oscBuf[ch]->needle++]=ayBuf[ch][i]<<2; } } } diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index d77457d66..123dc68ac 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -111,7 +111,7 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l for (int ch=0; ch<3; ch++) { for (size_t i=0; idata[oscBuf[ch]->needle++]=ayBuf[ch][i]; + oscBuf[ch]->data[oscBuf[ch]->needle++]=ayBuf[ch][i]<<2; } } } diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index d4d77f171..e4d408f7b 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -78,7 +78,7 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_ if (isMuted[i]) { oscBuf[i]->data[oscBuf[i]->needle++]=0; } else { - oscBuf[i]->data[oscBuf[i]->needle++]=sn_nuked.vol_table[sn_nuked.volume_out[i]]; + oscBuf[i]->data[oscBuf[i]->needle++]=sn_nuked.vol_table[sn_nuked.volume_out[i]]*3; } } } @@ -104,7 +104,7 @@ void DivPlatformSMS::acquire_mame(short* bufL, short* bufR, size_t start, size_t if (isMuted[i]) { oscBuf[i]->data[oscBuf[i]->needle++]=0; } else { - oscBuf[i]->data[oscBuf[i]->needle++]=sn->get_channel_output(i); + oscBuf[i]->data[oscBuf[i]->needle++]=sn->get_channel_output(i)*3; } } } diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index 547e59a17..08174b0b6 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -69,6 +69,39 @@ float FurnaceGUI::computeGradPos(int type, int chan) { return 0.0f; } +void FurnaceGUI::calcChanOsc() { + std::vector oscBufs; + std::vector oscFFTs; + std::vector oscChans; + + int chans=e->getTotalChannelCount(); + + for (int i=0; igetOscBuffer(i); + if (buf!=NULL && e->curSubSong->chanShow[i]) { + // 30ms should be enough + int displaySize=(float)(buf->rate)*0.03f; + if (e->isRunning()) { + float minLevel=1.0f; + float maxLevel=-1.0f; + unsigned short needlePos=buf->needle; + needlePos-=displaySize; + for (unsigned short i=0; i<512; i++) { + float y=(float)buf->data[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; + if (minLevel>y) minLevel=y; + if (maxLevel1.0f) estimate=1.0f; + chanOscVol[i]=MAX(chanOscVol[i]*0.87f,estimate); + } + } else { + chanOscVol[i]=MAX(chanOscVol[i]*0.87f,0.0f); + } + if (chanOscVol[i]<0.00001f) chanOscVol[i]=0.0f; + } +} + void FurnaceGUI::drawChanOsc() { if (nextWindow==GUI_WINDOW_CHAN_OSC) { chanOscOpen=true; @@ -361,7 +394,6 @@ void FurnaceGUI::drawChanOsc() { if (maxLeveldata[(unsigned short)(needlePos+(i*displaySize/512))]/65536.0f; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 40869c425..d42ec0f88 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3471,6 +3471,8 @@ bool FurnaceGUI::loop() { ImGui::EndMainMenuBar(); } + calcChanOsc(); + if (mobileUI) { globalWinFlags=ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoMove|ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoBringToFrontOnFocus; //globalWinFlags=ImGuiWindowFlags_NoTitleBar; @@ -3546,6 +3548,12 @@ bool FurnaceGUI::loop() { drawEffectList(); } + for (int i=0; igetTotalChannelCount(); i++) { + if (e->keyHit[i]) { + e->keyHit[i]=false; + } + } + if (inspectorOpen) ImGui::ShowMetricsWindow(&inspectorOpen); if (firstFrame) { diff --git a/src/gui/gui.h b/src/gui/gui.h index 09155f9be..bbfb3cf5b 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1558,6 +1558,7 @@ class FurnaceGUI { // visualizer float keyHit[DIV_MAX_CHANS]; + float keyHit1[DIV_MAX_CHANS]; int lastIns[DIV_MAX_CHANS]; // log window @@ -1612,6 +1613,7 @@ class FurnaceGUI { ImVec4 channelTextColor(int ch); void readOsc(); + void calcChanOsc(); void pushAccentColors(const ImVec4& one, const ImVec4& two, const ImVec4& border, const ImVec4& borderShadow); void popAccentColors(); diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index b986cedc6..f35f828c0 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -486,7 +486,6 @@ void FurnaceGUI::drawPattern() { } } } - e->keyHit[i]=false; } if (settings.channelFeedbackStyle==2 && e->isRunning()) { float amount=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i)); @@ -547,6 +546,10 @@ void FurnaceGUI::drawPattern() { ImRect rect=ImRect(minArea,maxArea); switch (settings.channelStyle) { case 0: // classic + if (settings.channelVolStyle!=0) { + // sorry... + ImGui::Dummy(ImVec2(dpiScale,dpiScale)); + } ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); break; case 1: { // line @@ -672,9 +675,62 @@ void FurnaceGUI::drawPattern() { inhibitMenu=true; e->toggleSolo(i); } + if (settings.channelStyle==3) { ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale)); } + + // volume bar + if (settings.channelVolStyle!=0) { + ImVec2 sizeV=ImVec2( + 1.0f, + 6.0*dpiScale + ); + ImVec2 minAreaV=window->DC.CursorPos; + ImVec2 maxAreaV=ImVec2( + minAreaV.x+window->WorkRect.Max.x-window->WorkRect.Min.x, + minAreaV.y+sizeV.y + ); + ImRect rectV=ImRect(minAreaV,maxAreaV); + ImGui::ItemSize(sizeV,ImGui::GetStyle().FramePadding.y); + if (ImGui::ItemAdd(rectV,ImGui::GetID(chanID))) { + float xLeft=0.0f; + float xRight=1.0f; + + if (e->keyHit[i]) { + keyHit1[i]=1.0f; + } + + if (e->isRunning()) { + switch (settings.channelVolStyle) { + case 1: // simple + xRight=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.9+(keyHit1[i]*0.1f); + break; + case 2: // stereo + xRight=0.5+((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.4+(keyHit1[i]*0.1f); + xLeft=1.0-xRight; + break; + case 3: // real + xRight=chanOscVol[i]; + break; + case 4: // real (stereo) + xRight=0.5+chanOscVol[i]*0.5; + xLeft=1.0-xRight; + break; + } + + dl->AddRectFilled( + ImLerp(rectV.Min,rectV.Max,ImVec2(xLeft,0.0f)), + ImLerp(rectV.Min,rectV.Max,ImVec2(xRight,1.0f)), + ImGui::GetColorU32(chanHeadBase) + ); + } + keyHit1[i]-=0.2f; + if (keyHit1[i]<0.0f) keyHit1[i]=0.0f; + } + } + + // extra buttons if (extraChannelButtons==2) { DivPattern* pat=e->curPat[i].getPattern(e->curOrders->ord[i][ord],true); ImGui::PushFont(mainFont); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index c771f6a16..e5c609829 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1327,6 +1327,9 @@ void FurnaceGUI::drawSettings() { if (ImGui::RadioButton("Real##CHV3",settings.channelVolStyle==3)) { settings.channelVolStyle=3; } + if (ImGui::RadioButton("Real (stereo)##CHV4",settings.channelVolStyle==4)) { + settings.channelVolStyle=4; + } ImGui::Text("Channel feedback style:"); @@ -2389,7 +2392,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.channelColors,0,2); clampSetting(settings.channelTextColors,0,2); clampSetting(settings.channelStyle,0,5); - clampSetting(settings.channelVolStyle,0,3); + clampSetting(settings.channelVolStyle,0,4); clampSetting(settings.channelFeedbackStyle,0,3); clampSetting(settings.channelFont,0,1); clampSetting(settings.maxRecentFile,0,30); From a58529a49b4dcd8728d5e73472476e99e5febf27 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 20 Sep 2022 02:57:56 -0500 Subject: [PATCH 13/39] GUI: fix some thread problems with keyHit --- src/gui/chanOsc.cpp | 2 +- src/gui/gui.cpp | 9 +++------ src/gui/pattern.cpp | 3 +++ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/gui/chanOsc.cpp b/src/gui/chanOsc.cpp index 08174b0b6..89b89801b 100644 --- a/src/gui/chanOsc.cpp +++ b/src/gui/chanOsc.cpp @@ -63,7 +63,7 @@ float FurnaceGUI::computeGradPos(int type, int chan) { return chanOscBright[chan]; break; case GUI_OSCREF_NOTE_TRIGGER: - return keyHit[chan]*5.0f; + return keyHit1[chan]; break; } return 0.0f; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index d42ec0f88..a2eb9c920 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -3548,12 +3548,6 @@ bool FurnaceGUI::loop() { drawEffectList(); } - for (int i=0; igetTotalChannelCount(); i++) { - if (e->keyHit[i]) { - e->keyHit[i]=false; - } - } - if (inspectorOpen) ImGui::ShowMetricsWindow(&inspectorOpen); if (firstFrame) { @@ -5462,6 +5456,9 @@ FurnaceGUI::FurnaceGUI(): waveGenFMCon2[0]=true; waveGenFMCon3[0]=true; + memset(keyHit,0,sizeof(float)*DIV_MAX_CHANS); + memset(keyHit1,0,sizeof(float)*DIV_MAX_CHANS); + memset(pianoKeyHit,0,sizeof(float)*180); memset(pianoKeyPressed,0,sizeof(bool)*180); diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index f35f828c0..add285f64 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -477,6 +477,7 @@ void FurnaceGUI::drawPattern() { ImVec4 chanHeadBase=chanHead; if (e->keyHit[i]) { + keyHit1[i]=1.0f; if (settings.channelFeedbackStyle==1) { keyHit[i]=0.2; if (!muted) { @@ -486,6 +487,7 @@ void FurnaceGUI::drawPattern() { } } } + e->keyHit[i]=false; } if (settings.channelFeedbackStyle==2 && e->isRunning()) { float amount=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i)); @@ -699,6 +701,7 @@ void FurnaceGUI::drawPattern() { if (e->keyHit[i]) { keyHit1[i]=1.0f; + e->keyHit[i]=false; } if (e->isRunning()) { From 980f970809cd26a810f6236e30741ba2e352f0de Mon Sep 17 00:00:00 2001 From: freq-mod <32672779+freq-mod@users.noreply.github.com> Date: Tue, 20 Sep 2022 21:13:29 +0000 Subject: [PATCH 14/39] fix opll bbc micro clock, improve some presets --- src/gui/presets.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++-- src/gui/sysConf.cpp | 2 +- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index 1bd637a23..da1c4d51f 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -960,11 +960,27 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with PC-9801-86)", { // -73 also has OPNA DIV_SYSTEM_PC98, 64, 0, 1, + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), // 2x 16-bit Burr Brown DAC + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), 0 } )); cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with PC-9801-86; extended channel 3)", { // -73 also has OPNA + DIV_SYSTEM_PC98_EXT, 64, 0, 1, + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16), + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with PC-9801-73)", { + DIV_SYSTEM_PC98, 64, 0, 1, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "NEC PC-98 (with PC-9801-73; extended channel 3)", { DIV_SYSTEM_PC98_EXT, 64, 0, 1, 0 } @@ -972,6 +988,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible)", { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3, 64, 0, 0, 0 } @@ -979,6 +996,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3, 64, 0, 0, 0 } @@ -986,6 +1004,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible in drums mode)", { DIV_SYSTEM_OPN, 64, 0, 2, // 4MHz + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3_DRUMS, 64, 0, 2, 0 } @@ -993,6 +1012,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "NEC PC-98 (with Sound Blaster 16 for PC-9800 w/PC-9801-26/K compatible in drums mode; extended channel 3)", { DIV_SYSTEM_OPN_EXT, 64, 0, 2, // 4MHz + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_OPL3_DRUMS, 64, 0, 2, 0 } @@ -1092,6 +1112,20 @@ void FurnaceGUI::initSystemPresets() { 0 } )); + cat.systems.push_back(FurnaceGUISysDef( + "Atari ST", { + DIV_SYSTEM_AY8910, 64, 0, 3, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "Atari STE", { + DIV_SYSTEM_AY8910, 64, 0, 3, + DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), + DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), + 0 + } + )); cat.systems.push_back(FurnaceGUISysDef( "SAM CoupĂ©", { DIV_SYSTEM_SAA1099, 64, 0, 0, @@ -1146,17 +1180,33 @@ void FurnaceGUI::initSystemPresets() { 0 } )); - cat.systems.push_back(FurnaceGUISysDef( - "PC + AdLib/Sound Blaster", { + cat.systems.push_back(FurnaceGUISysDef( + "PC + AdLib", { DIV_SYSTEM_OPL2, 64, 0, 0, DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } + )); + cat.systems.push_back(FurnaceGUISysDef( + "PC + AdLib (drums mode)", { + DIV_SYSTEM_OPL2, 64, 0, 0, + DIV_SYSTEM_PCSPKR, 64, 0, 0, + 0 + } + )); + cat.systems.push_back(FurnaceGUISysDef( + "PC + Sound Blaster", { + DIV_SYSTEM_OPL2, 64, 0, 0, + DIV_SYSTEM_PCSPKR, 64, 0, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), + 0 + } )); cat.systems.push_back(FurnaceGUISysDef( "PC + AdLib/Sound Blaster (drums mode)", { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, DIV_SYSTEM_PCSPKR, 64, 0, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), 0 } )); @@ -1165,6 +1215,7 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPL2, 64, 0, 0, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, + DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } @@ -1174,6 +1225,7 @@ void FurnaceGUI::initSystemPresets() { DIV_SYSTEM_OPL2_DRUMS, 64, 0, 0, DIV_SYSTEM_SAA1099, 64, 0, 1, DIV_SYSTEM_SAA1099, 64, 0, 1, + DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16), DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } @@ -1182,6 +1234,7 @@ void FurnaceGUI::initSystemPresets() { "PC + Sound Blaster Pro", { DIV_SYSTEM_OPL2, 64, -127, 0, DIV_SYSTEM_OPL2, 64, 127, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16)|(1<<20), //alternatively 44.1 khz mono DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } @@ -1190,6 +1243,7 @@ void FurnaceGUI::initSystemPresets() { "PC + Sound Blaster Pro (drums mode)", { DIV_SYSTEM_OPL2_DRUMS, 64, -127, 0, DIV_SYSTEM_OPL2_DRUMS, 64, 127, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 22049|(7<<16)|(1<<20), //alternatively 44.1 khz mono DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } @@ -1197,6 +1251,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster Pro 2", { DIV_SYSTEM_OPL3, 64, 0, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } @@ -1204,6 +1259,7 @@ void FurnaceGUI::initSystemPresets() { cat.systems.push_back(FurnaceGUISysDef( "PC + Sound Blaster Pro 2 (drums mode)", { DIV_SYSTEM_OPL3_DRUMS, 64, 0, 0, + DIV_SYSTEM_PCM_DAC, 64, 0, 44099|(15<<16)|(1<<20), DIV_SYSTEM_PCSPKR, 64, 0, 0, 0 } diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index ba3ded1a6..3a0c1098e 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -217,7 +217,7 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::RadioButton("PAL (3.55MHz)",(flags&15)==1)) { copyOfFlags=(flags&(~15))|1; } - if (ImGui::RadioButton("BBC Micro (4MHz)",(flags&15)==2)) { + if (ImGui::RadioButton("Arcade (4MHz)",(flags&15)==2)) { copyOfFlags=(flags&(~15))|2; } if (ImGui::RadioButton("Half NTSC (1.79MHz)",(flags&15)==3)) { From eb0aac0f54f3cfae1a847edc65de463d5629d394 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 20 Sep 2022 19:07:17 -0500 Subject: [PATCH 15/39] GUI: more work on it --- src/gui/gui.h | 4 +- src/gui/pattern.cpp | 100 +++++++++++++++++++++++++++++-------------- src/gui/settings.cpp | 10 ++++- 3 files changed, 79 insertions(+), 35 deletions(-) diff --git a/src/gui/gui.h b/src/gui/gui.h index bbfb3cf5b..5bf8adfe7 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1179,6 +1179,7 @@ class FurnaceGUI { int channelVolStyle; int channelFeedbackStyle; int channelFont; + int channelTextCenter; int maxRecentFile; unsigned int maxUndoSteps; String mainFontPath; @@ -1297,10 +1298,11 @@ class FurnaceGUI { saveUnusedPatterns(0), channelColors(1), channelTextColors(0), - channelStyle(0), + channelStyle(1), channelVolStyle(0), channelFeedbackStyle(1), channelFont(1), + channelTextCenter(1), maxRecentFile(10), maxUndoSteps(100), mainFontPath(""), diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index add285f64..103ecbbe2 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -18,6 +18,7 @@ */ // for suck's fake Clang extension! +#include #define _USE_MATH_DEFINES #include "gui.h" #include "../ta-log.h" @@ -25,6 +26,7 @@ #include "IconsFontAwesome4.h" #include "misc/cpp/imgui_stdlib.h" #include "guiConst.h" +#include "../utfutils.h" #include inline float randRange(float min, float max) { @@ -448,27 +450,6 @@ void FurnaceGUI::drawPattern() { if (!e->curSubSong->chanShow[i]) continue; ImGui::TableNextColumn(); bool displayTooltip=false; - if (e->curSubSong->chanCollapse[i]) { - const char* chName=e->getChannelShortName(i); - if (strlen(chName)>3) { - snprintf(chanID,2048,"...##_CH%d",i); - } else { - snprintf(chanID,2048,"%s##_CH%d",chName,i); - } - displayTooltip=true; - } else { - const char* chName=e->getChannelName(i); - size_t chNameLimit=6+4*e->curPat[i].effectCols; - if (strlen(chName)>chNameLimit) { - String shortChName=chName; - shortChName.resize(chNameLimit-3); - shortChName+="..."; - snprintf(chanID,2048," %s##_CH%d",shortChName.c_str(),i); - displayTooltip=true; - } else { - snprintf(chanID,2048," %s##_CH%d",chName,i); - } - } bool muted=e->isChannelMuted(i); ImVec4 chanHead=muted?uiColors[GUI_COLOR_CHANNEL_MUTED]:channelColor(i); @@ -532,10 +513,14 @@ void FurnaceGUI::drawPattern() { ImGuiWindow* window=ImGui::GetCurrentWindow(); ImVec2 size=ImVec2( 1.0f, - lineHeight+1.0f*dpiScale+6.0*dpiScale + lineHeight+1.0f*dpiScale ); ImDrawList* dl=ImGui::GetWindowDrawList(); + if (settings.channelStyle!=0) { + size.y+=6.0f*dpiScale; + } + if (settings.channelStyle==2) { size.y+=6.0f*dpiScale; } @@ -546,13 +531,63 @@ void FurnaceGUI::drawPattern() { minArea.y+size.y ); ImRect rect=ImRect(minArea,maxArea); + float padding=ImGui::CalcTextSize("A").x; + + ImVec2 minLabelArea=minArea; + ImVec2 maxLabelArea=maxArea; + + if (e->curSubSong->chanCollapse[i]) { + const char* chName=e->getChannelShortName(i); + if (strlen(chName)>3) { + snprintf(chanID,2048,"..."); + } else { + snprintf(chanID,2048,"%s",chName); + } + displayTooltip=true; + } else { + minLabelArea.x+=padding; + maxLabelArea.x-=padding; + const char* chName=e->getChannelName(i); + float chNameLimit=maxLabelArea.x-minLabelArea.x; + if (ImGui::CalcTextSize(chName).x>chNameLimit) { + String shortChName; + float totalAdvanced=0.0f; + float ellipsisSize=ImGui::CalcTextSize("...").x; + for (const char* j=chName; *j;) { + signed char l; + int ch=decodeUTF8((const unsigned char*)j,l); + + totalAdvanced+=ImGui::GetFont()->GetCharAdvance(ch); + if (totalAdvanced>(chNameLimit-ellipsisSize)) break; + + for (int k=0; kAddRectFilled(rect.Min,rect.Max,col); + dl->AddText(ImVec2(minLabelArea.x,rect.Min.y),ImGui::GetColorU32(channelTextColor(i)),chanID); } - ImGui::Selectable(chanID,true,ImGuiSelectableFlags_NoPadWithHalfSpacing,ImVec2(0.0f,lineHeight+1.0f*dpiScale)); break; case 1: { // line ImGui::ItemSize(size,ImGui::GetStyle().FramePadding.y); @@ -572,7 +607,7 @@ void FurnaceGUI::drawPattern() { )); dl->AddRectFilledMultiColor(rect.Min,rect.Max,fadeCol0,fadeCol0,fadeCol,fadeCol); dl->AddLine(ImVec2(rect.Min.x,rect.Max.y),ImVec2(rect.Max.x,rect.Max.y),ImGui::GetColorU32(chanHeadBase),2.0f*dpiScale); - dl->AddText(ImVec2(rect.Min.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + dl->AddText(ImVec2(minLabelArea.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID); } break; } @@ -599,18 +634,16 @@ void FurnaceGUI::drawPattern() { rMax.x-=3.0f*dpiScale; rMax.y-=6.0f*dpiScale; dl->AddRectFilledMultiColor(rMin,rMax,fadeCol0,fadeCol0,fadeCol,fadeCol,4.0f*dpiScale); - dl->AddText(ImVec2(rect.Min.x,rect.Min.y+6.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + dl->AddText(ImVec2(minLabelArea.x,rect.Min.y+6.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID); } break; } case 3: // split button ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale)); - ImGui::TextUnformatted(chanID,strstr(chanID,"##")); + ImGui::TextUnformatted(chanID); ImGui::SameLine(); ImGui::PushFont(mainFont); - ImGui::PushID(chanID); ImGui::SmallButton(muted?ICON_FA_VOLUME_OFF:ICON_FA_VOLUME_UP); - ImGui::PopID(); ImGui::PopFont(); break; case 4: { // square border @@ -630,7 +663,7 @@ void FurnaceGUI::drawPattern() { rMax.x-=3.0f*dpiScale; rMax.y-=3.0f*dpiScale; dl->AddRect(rMin,rMax,fadeCol,0.0f,2.0*dpiScale); - dl->AddText(ImVec2(rect.Min.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + dl->AddText(ImVec2(minLabelArea.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID); } break; } @@ -651,11 +684,12 @@ void FurnaceGUI::drawPattern() { rMax.x-=3.0f*dpiScale; rMax.y-=3.0f*dpiScale; dl->AddRect(rMin,rMax,fadeCol,4.0f*dpiScale,ImDrawFlags_RoundCornersAll,2.0*dpiScale); - dl->AddText(ImVec2(rect.Min.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID,strstr(chanID,"##")); + dl->AddText(ImVec2(minLabelArea.x,rect.Min.y+3.0*dpiScale),ImGui::GetColorU32(channelTextColor(i)),chanID); } break; } } + ImGui::PopID(); if (displayTooltip && ImGui::IsItemHovered()) { ImGui::SetTooltip("%s",e->getChannelName(i)); diff --git a/src/gui/settings.cpp b/src/gui/settings.cpp index e5c609829..bf360daed 100644 --- a/src/gui/settings.cpp +++ b/src/gui/settings.cpp @@ -1355,6 +1355,11 @@ void FurnaceGUI::drawSettings() { settings.channelFont=1; } + bool channelTextCenterB=settings.channelTextCenter; + if (ImGui::Checkbox("Center channel name",&channelTextCenterB)) { + settings.channelTextCenter=channelTextCenterB; + } + ImGui::Separator(); bool insEditColorizeB=settings.insEditColorize; @@ -2291,10 +2296,11 @@ void FurnaceGUI::syncSettings() { settings.saveUnusedPatterns=e->getConfInt("saveUnusedPatterns",0); settings.channelColors=e->getConfInt("channelColors",1); settings.channelTextColors=e->getConfInt("channelTextColors",0); - settings.channelStyle=e->getConfInt("channelStyle",0); + settings.channelStyle=e->getConfInt("channelStyle",1); settings.channelVolStyle=e->getConfInt("channelVolStyle",0); settings.channelFeedbackStyle=e->getConfInt("channelFeedbackStyle",1); settings.channelFont=e->getConfInt("channelFont",1); + settings.channelTextCenter=e->getConfInt("channelTextCenter",1); settings.maxRecentFile=e->getConfInt("maxRecentFile",10); clampSetting(settings.mainFontSize,2,96); @@ -2395,6 +2401,7 @@ void FurnaceGUI::syncSettings() { clampSetting(settings.channelVolStyle,0,4); clampSetting(settings.channelFeedbackStyle,0,3); clampSetting(settings.channelFont,0,1); + clampSetting(settings.channelTextCenter,0,1); clampSetting(settings.maxRecentFile,0,30); settings.initialSys=e->decodeSysDesc(e->getConfString("initialSys","")); @@ -2551,6 +2558,7 @@ void FurnaceGUI::commitSettings() { e->setConf("channelVolStyle",settings.channelVolStyle); e->setConf("channelFeedbackStyle",settings.channelFeedbackStyle); e->setConf("channelFont",settings.channelFont); + e->setConf("channelTextCenter",settings.channelTextCenter); e->setConf("maxRecentFile",settings.maxRecentFile); // colors From 28d34171968dbdeff4b3221248fcff3e5a4bf6e6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Tue, 20 Sep 2022 19:41:07 -0500 Subject: [PATCH 16/39] GUI: more channel bar polishing --- src/gui/pattern.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/gui/pattern.cpp b/src/gui/pattern.cpp index 103ecbbe2..ae194925d 100644 --- a/src/gui/pattern.cpp +++ b/src/gui/pattern.cpp @@ -547,6 +547,9 @@ void FurnaceGUI::drawPattern() { } else { minLabelArea.x+=padding; maxLabelArea.x-=padding; + if (settings.channelStyle==3) { // split button + maxLabelArea.x-=ImGui::GetFrameHeightWithSpacing(); + } const char* chName=e->getChannelName(i); float chNameLimit=maxLabelArea.x-minLabelArea.x; if (ImGui::CalcTextSize(chName).x>chNameLimit) { @@ -578,6 +581,8 @@ void FurnaceGUI::drawPattern() { minLabelArea.x+=0.5f*(maxLabelArea.x-minLabelArea.x-ImGui::CalcTextSize(chanID).x); } + if (extraChannelButtons==0 || settings.channelVolStyle!=0) ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing,ImVec2(0.0f,0.0f)); + ImGui::PushID(2048+i); switch (settings.channelStyle) { case 0: // classic @@ -640,6 +645,7 @@ void FurnaceGUI::drawPattern() { } case 3: // split button ImGui::Dummy(ImVec2(1.0f,2.0f*dpiScale)); + ImGui::SetCursorPosX(minLabelArea.x); ImGui::TextUnformatted(chanID); ImGui::SameLine(); ImGui::PushFont(mainFont); @@ -691,6 +697,8 @@ void FurnaceGUI::drawPattern() { } ImGui::PopID(); + if (extraChannelButtons==0 || settings.channelVolStyle!=0) ImGui::PopStyleVar(); + if (displayTooltip && ImGui::IsItemHovered()) { ImGui::SetTooltip("%s",e->getChannelName(i)); } @@ -739,20 +747,24 @@ void FurnaceGUI::drawPattern() { } if (e->isRunning()) { + DivChannelState* cs=e->getChanState(i); + float stereoPan=(float)(e->convertPanSplitToLinearLR(cs->panL,cs->panR,256)-128)/128.0; switch (settings.channelVolStyle) { case 1: // simple xRight=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.9+(keyHit1[i]*0.1f); break; - case 2: // stereo - xRight=0.5+((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.4+(keyHit1[i]*0.1f); - xLeft=1.0-xRight; + case 2: { // stereo + float amount=((float)(e->getChanState(i)->volume>>8)/(float)e->getMaxVolumeChan(i))*0.4+(keyHit1[i]*0.1f); + xRight=0.5+amount*(1.0+MIN(0.0,stereoPan)); + xLeft=0.5-amount*(1.0-MAX(0.0,stereoPan)); break; + } case 3: // real xRight=chanOscVol[i]; break; case 4: // real (stereo) - xRight=0.5+chanOscVol[i]*0.5; - xLeft=1.0-xRight; + xRight=0.5+chanOscVol[i]*0.5*(1.0+MIN(0.0,stereoPan)); + xLeft=0.5-chanOscVol[i]*0.5*(1.0-MAX(0.0,stereoPan)); break; } From 24a40051352b5ef7b2953a8e0dc7018a65f8369f Mon Sep 17 00:00:00 2001 From: TheDuccinator <66538032+TheDuccinator@users.noreply.github.com> Date: Tue, 20 Sep 2022 18:53:48 -0700 Subject: [PATCH 17/39] Add new GB song "You're Doing Well!" --- demos/You're_Doing_Well!_GB.fur | Bin 0 -> 3855 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/You're_Doing_Well!_GB.fur diff --git a/demos/You're_Doing_Well!_GB.fur b/demos/You're_Doing_Well!_GB.fur new file mode 100644 index 0000000000000000000000000000000000000000..01cfff9d2cb81f9a3e8b9fe5f9a62e72bd2e5ff7 GIT binary patch literal 3855 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 WQ#4=iLekbwFCeJ{^0dFsE&LxqZU*oG literal 0 HcmV?d00001 From e1679e8ea68e6dd9dc56e414e1de77d0c56b824e Mon Sep 17 00:00:00 2001 From: cam900 Date: Wed, 21 Sep 2022 13:22:04 +0900 Subject: [PATCH 18/39] Fix preset Atari ST series uses YM2419 or YM3439 --- src/gui/presets.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/presets.cpp b/src/gui/presets.cpp index da1c4d51f..7d83dc3fb 100644 --- a/src/gui/presets.cpp +++ b/src/gui/presets.cpp @@ -1114,13 +1114,13 @@ void FurnaceGUI::initSystemPresets() { )); cat.systems.push_back(FurnaceGUISysDef( "Atari ST", { - DIV_SYSTEM_AY8910, 64, 0, 3, + DIV_SYSTEM_AY8910, 64, 0, 19, 0 } )); cat.systems.push_back(FurnaceGUISysDef( "Atari STE", { - DIV_SYSTEM_AY8910, 64, 0, 3, + DIV_SYSTEM_AY8910, 64, 0, 19, DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), DIV_SYSTEM_PCM_DAC, 64, 0, 50667|(7<<16), 0 From 60abdd78a1c019b3d453366318fdd1bcd68788cd Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 16:45:05 -0500 Subject: [PATCH 19/39] and yet another big endian fix --- src/engine/fileOps.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 10a4bcce9..41fc767af 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1772,14 +1772,8 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { #ifdef TA_BIG_ENDIAN // convert 16-bit samples to big-endian - if (sample->depth==DIV_SAMPLE_DEPTH_16BIT) { - unsigned char* sampleBuf=(unsigned char*)sample->getCurBuf(); - size_t sampleBufLen=sample->getCurBufLen(); - for (size_t pos=0; pos>8)|((unsigned short)data[pos]<<8); } #endif From a17f499384201e1674e556e8576d9841aa78c56d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 16:52:04 -0500 Subject: [PATCH 20/39] ... --- src/engine/fileOps.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 41fc767af..aac771e09 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1772,7 +1772,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { #ifdef TA_BIG_ENDIAN // convert 16-bit samples to big-endian - for (size_t pos=0; pos>8)|((unsigned short)data[pos]<<8); } #endif From e22d7484cb3d4344c404c58e9762a72fc5b6a5b4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 19:27:42 -0500 Subject: [PATCH 21/39] dev115 - automatic system detection --- papers/format.md | 11 ++++- src/engine/engine.h | 4 +- src/engine/fileOps.cpp | 14 ++++++- src/engine/instrument.cpp | 12 +++++- src/engine/instrument.h | 4 +- src/engine/song.h | 4 +- src/gui/gui.cpp | 87 +++++++++++++++++++++++++++++++++++++++ src/gui/gui.h | 3 +- src/gui/songInfo.cpp | 14 ++++++- src/gui/sysConf.cpp | 3 ++ src/gui/sysManager.cpp | 6 +++ 11 files changed, 150 insertions(+), 12 deletions(-) diff --git a/papers/format.md b/papers/format.md index da06488fa..acedd9945 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 115: Furnace dev115 - 114: Furnace dev114 - 113: Furnace dev113 - 112: Furnace dev112 @@ -342,7 +343,9 @@ size | description 1 | SN periods under 8 are treated as 1 (>=108) or reserved 1 | cut/delay effect policy (>=110) or reserved 1 | 0B/0D effect treatment (>=113) or reserved - 4 | reserved + 1 | automatic system name detection (>=115) or reserved + | - this one isn't a compatibility flag, but it's here for convenience... + 3 | reserved --- | **virtual tempo data** 2 | virtual tempo numerator of first song (>=96) or reserved 2 | virtual tempo denominator of first song (>=96) or reserved @@ -499,7 +502,11 @@ size | description 1 | ws 1 | ksr 1 | operator enabled (>=114) or reserved - 11 | reserved + 1 | KVS mode (>=115) or reserved + | - 0: off + | - 1: on + | - 2: auto (depending on alg) + 10 | reserved --- | **Game Boy instrument data** 1 | volume 1 | direction diff --git a/src/engine/engine.h b/src/engine/engine.h index 3047a8af7..40bbbbb90 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev114" -#define DIV_ENGINE_VERSION 114 +#define DIV_VERSION "dev115" +#define DIV_ENGINE_VERSION 115 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index aac771e09..4c213744b 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -1085,6 +1085,9 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { if (ds.version<113) { ds.jumpTreatment=1; } + if (ds.version<115) { + ds.autoSystem=false; + } ds.isDMF=false; reader.readS(); // reserved @@ -1512,7 +1515,12 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { } else { reader.readC(); } - for (int i=0; i<4; i++) { + if (ds.version>=115) { + ds.autoSystem=reader.readC(); + } else { + reader.readC(); + } + for (int i=0; i<3; i++) { reader.readC(); } } @@ -1549,6 +1557,7 @@ bool DivEngine::loadFur(unsigned char* file, size_t len) { ds.categoryJ=reader.readString(); } else { ds.systemName=getSongSystemLegacyName(ds,!getConfInt("noMultiSystem",0)); + ds.autoSystem=true; } // read subsongs @@ -3751,7 +3760,8 @@ SafeWriter* DivEngine::saveFur(bool notPrimary) { w->writeC(song.snNoLowPeriods); w->writeC(song.delayBehavior); w->writeC(song.jumpTreatment); - for (int i=0; i<4; i++) { + w->writeC(song.autoSystem); + for (int i=0; i<3; i++) { w->writeC(0); } diff --git a/src/engine/instrument.cpp b/src/engine/instrument.cpp index 22cdddf4b..3296994ba 100644 --- a/src/engine/instrument.cpp +++ b/src/engine/instrument.cpp @@ -72,9 +72,10 @@ void DivInstrument::putInsData(SafeWriter* w) { w->writeC(op.ksr); w->writeC(op.enable); + w->writeC(op.kvs); // reserved - for (int k=0; k<11; k++) { + for (int k=0; k<10; k++) { w->writeC(0); } } @@ -724,8 +725,15 @@ DivDataErrors DivInstrument::readInsData(SafeReader& reader, short version) { reader.readC(); } + if (version>=115) { + op.kvs=reader.readC(); + } else { + op.kvs=2; + reader.readC(); + } + // reserved - for (int k=0; k<11; k++) reader.readC(); + for (int k=0; k<10; k++) reader.readC(); } // GB diff --git a/src/engine/instrument.h b/src/engine/instrument.h index e5372933d..5652301f4 100644 --- a/src/engine/instrument.h +++ b/src/engine/instrument.h @@ -87,6 +87,7 @@ struct DivInstrumentFM { bool enable; unsigned char am, ar, dr, mult, rr, sl, tl, dt2, rs, dt, d2r, ssgEnv; unsigned char dam, dvb, egt, ksl, sus, vib, ws, ksr; // YMU759/OPL/OPZ + unsigned char kvs; Operator(): enable(true), am(0), @@ -108,7 +109,8 @@ struct DivInstrumentFM { sus(0), vib(0), ws(0), - ksr(0) {} + ksr(0), + kvs(2) {} } op[4]; DivInstrumentFM(): alg(0), diff --git a/src/engine/song.h b/src/engine/song.h index 493fc4125..09a89378c 100644 --- a/src/engine/song.h +++ b/src/engine/song.h @@ -511,6 +511,7 @@ struct DivSong { bool e1e2StopOnSameNote; bool brokenPortaArp; bool snNoLowPeriods; + bool autoSystem; std::vector ins; std::vector wave; @@ -614,7 +615,8 @@ struct DivSong { brokenOutVol(false), e1e2StopOnSameNote(false), brokenPortaArp(false), - snNoLowPeriods(false) { + snNoLowPeriods(false), + autoSystem(true) { for (int i=0; i<32; i++) { system[i]=DIV_SYSTEM_NULL; systemVol[i]=64; diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index a2eb9c920..2e566bb1a 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -584,6 +584,78 @@ void FurnaceGUI::updateWindowTitle() { if (sdlWin!=NULL) SDL_SetWindowTitle(sdlWin,title.c_str()); } +void FurnaceGUI::autoDetectSystem() { + std::map sysCountMap; + for (int i=0; isong.systemLen; i++) { + try { + sysCountMap.at(e->song.system[i])++; + } catch (std::exception& ex) { + sysCountMap[e->song.system[i]]=1; + } + } + + logV("sysCountMap:"); + for (std::pair k: sysCountMap) { + logV("%s: %d",e->getSystemName(k.first),k.second); + } + + bool isMatch=false; + std::map defCountMap; + for (FurnaceGUISysCategory& i: sysCategories) { + for (FurnaceGUISysDef& j: i.systems) { + defCountMap.clear(); + for (size_t k=0; k k: defCountMap) { + logV("- %s: %d",e->getSystemName(k.first),k.second); + } + for (std::pair k: defCountMap) { + try { + if (sysCountMap.at(k.first)!=k.second) { + isMatch=false; + break; + } + } catch (std::exception& ex) { + isMatch=false; + break; + } + } + if (isMatch) { + logV("match found!"); + e->song.systemName=j.name; + break; + } + } + if (isMatch) break; + } + + if (!isMatch) { + bool isFirst=true; + e->song.systemName=""; + for (std::pair k: sysCountMap) { + if (!isFirst) e->song.systemName+=" + "; + if (k.second>1) { + e->song.systemName+=fmt::sprintf("%dĂ—",k.second); + } + if (k.first==DIV_SYSTEM_N163) { + e->song.systemName+=settings.c163Name; + } else { + e->song.systemName+=e->getSystemName(k.first); + } + isFirst=false; + } + } +} + ImVec4 FurnaceGUI::channelColor(int ch) { switch (settings.channelColors) { case 0: @@ -3262,6 +3334,9 @@ bool FurnaceGUI::loop() { showError("cannot add chip! ("+e->getLastError()+")"); } ImGui::CloseCurrentPopup(); + if (e->song.autoSystem) { + autoDetectSystem(); + } updateWindowTitle(); } ImGui::EndMenu(); @@ -3282,6 +3357,9 @@ bool FurnaceGUI::loop() { DivSystem picked=systemPicker(); if (picked!=DIV_SYSTEM_NULL) { e->changeSystem(i,picked,preserveChanPos); + if (e->song.autoSystem) { + autoDetectSystem(); + } updateWindowTitle(); ImGui::CloseCurrentPopup(); } @@ -3297,6 +3375,10 @@ bool FurnaceGUI::loop() { if (!e->removeSystem(i,preserveChanPos)) { showError("cannot remove chip! ("+e->getLastError()+")"); } + if (e->song.autoSystem) { + autoDetectSystem(); + updateWindowTitle(); + } } } ImGui::EndMenu(); @@ -4415,6 +4497,10 @@ bool FurnaceGUI::loop() { case GUI_WARN_SYSTEM_DEL: if (ImGui::Button("Yes")) { e->removeSystem(sysToDelete,preserveChanPos); + if (e->song.autoSystem) { + autoDetectSystem(); + updateWindowTitle(); + } ImGui::CloseCurrentPopup(); } ImGui::SameLine(); @@ -5069,6 +5155,7 @@ FurnaceGUI::FurnaceGUI(): macroPointSize(16), waveEditStyle(0), mobileMenuPos(0.0f), + autoButtonSize(0.0f), curSysSection(NULL), pendingRawSampleDepth(8), pendingRawSampleChannels(1), diff --git a/src/gui/gui.h b/src/gui/gui.h index 5bf8adfe7..c44d4c122 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1018,7 +1018,7 @@ class FurnaceGUI { int drawHalt; int macroPointSize; int waveEditStyle; - float mobileMenuPos; + float mobileMenuPos, autoButtonSize; const int* curSysSection; String pendingRawSample; @@ -1610,6 +1610,7 @@ class FurnaceGUI { bool CWVSliderInt(const char* label, const ImVec2& size, int* v, int v_min, int v_max, const char* format="%d", ImGuiSliderFlags flags=0); void updateWindowTitle(); + void autoDetectSystem(); void prepareLayout(); ImVec4 channelColor(int ch); ImVec4 channelTextColor(int ch); diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index 44982abaf..5b113c641 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -77,11 +77,23 @@ void FurnaceGUI::drawSongInfo() { ImGui::TableNextColumn(); ImGui::Text("System"); ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(avail); + ImGui::SetNextItemWidth(MAX(16.0f*dpiScale,avail-autoButtonSize-ImGui::GetStyle().ItemSpacing.x)); if (ImGui::InputText("##SystemName",&e->song.systemName)) { MARK_MODIFIED; updateWindowTitle(); + e->song.autoSystem=false; } + ImGui::SameLine(); + pushToggleColors(e->song.autoSystem); + if (ImGui::Button("Auto")) { + e->song.autoSystem=!e->song.autoSystem; + if (e->song.autoSystem) { + autoDetectSystem(); + updateWindowTitle(); + } + } + popToggleColors(); + autoButtonSize=ImGui::GetItemRectSize().x; ImGui::EndTable(); } diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 3a0c1098e..900845a69 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -765,6 +765,9 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (copyOfFlags!=flags) { if (chan>=0) { e->setSysFlags(chan,copyOfFlags,restart); + if (e->song.autoSystem) { + autoDetectSystem(); + } updateWindowTitle(); } else { flags=copyOfFlags; diff --git a/src/gui/sysManager.cpp b/src/gui/sysManager.cpp index 98f939d0f..386d26583 100644 --- a/src/gui/sysManager.cpp +++ b/src/gui/sysManager.cpp @@ -82,6 +82,9 @@ void FurnaceGUI::drawSysManager() { DivSystem picked=systemPicker(); if (picked!=DIV_SYSTEM_NULL) { e->changeSystem(i,picked,preserveChanPos); + if (e->song.autoSystem) { + autoDetectSystem(); + } updateWindowTitle(); ImGui::CloseCurrentPopup(); } @@ -110,6 +113,9 @@ void FurnaceGUI::drawSysManager() { if (!e->addSystem(picked)) { showError("cannot add chip! ("+e->getLastError()+")"); } + if (e->song.autoSystem) { + autoDetectSystem(); + } updateWindowTitle(); ImGui::CloseCurrentPopup(); } From ad097e0526b15fa73c56cfb61aea10cfcf332f34 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 22:59:53 -0500 Subject: [PATCH 22/39] GUI: add paste with instrument like paste mix but changes the instrument --- TODO.md | 3 +-- src/gui/editing.cpp | 15 +++++++++------ src/gui/gui.cpp | 24 ++++++++++++++++++++++++ src/gui/gui.h | 6 ++++-- 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/TODO.md b/TODO.md index 028f21077..84bc08a73 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ # to-do for 0.6pre1.5 - stereo separation control for AY -- "paste with instrument" -- auto-detect system +- KVS - bug fixes diff --git a/src/gui/editing.cpp b/src/gui/editing.cpp index 201c9be26..153d70da3 100644 --- a/src/gui/editing.cpp +++ b/src/gui/editing.cpp @@ -405,7 +405,7 @@ void FurnaceGUI::doCopy(bool cut) { } } -void FurnaceGUI::doPaste(PasteMode mode) { +void FurnaceGUI::doPaste(PasteMode mode, int arg) { finishSelection(); prepareUndo(GUI_UNDO_PATTERN_PASTE); char* clipText=SDL_GetClipboardText(); @@ -481,14 +481,16 @@ void FurnaceGUI::doPaste(PasteMode mode) { continue; } - if ((mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_MIX_FG) && strcmp(note,"...")==0) { + if ((mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_MIX_FG || + mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) && strcmp(note,"...")==0) { // do nothing. } else { - if (mode!=GUI_PASTE_MODE_MIX_BG || (pat->data[j][0]==0 && pat->data[j][1]==0)) { + if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || (pat->data[j][0]==0 && pat->data[j][1]==0)) { if (!decodeNote(note,pat->data[j][0],pat->data[j][1])) { invalidData=true; break; } + if (mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) pat->data[j][2]=arg; } } } else { @@ -505,7 +507,7 @@ void FurnaceGUI::doPaste(PasteMode mode) { note[2]=0; if (iFine==1) { - if (!opMaskPaste.ins) { + if (!opMaskPaste.ins || mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG) { iFine++; continue; } @@ -527,7 +529,8 @@ void FurnaceGUI::doPaste(PasteMode mode) { } if (strcmp(note,"..")==0) { - if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_MIX_FG)) { + if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_MIX_FG || + mode==GUI_PASTE_MODE_INS_BG || mode==GUI_PASTE_MODE_INS_FG)) { pat->data[j][iFine+1]=-1; } } else { @@ -536,7 +539,7 @@ void FurnaceGUI::doPaste(PasteMode mode) { invalidData=true; break; } - if (mode!=GUI_PASTE_MODE_MIX_BG || pat->data[j][iFine+1]==-1) { + if (!(mode==GUI_PASTE_MODE_MIX_BG || mode==GUI_PASTE_MODE_INS_BG) || pat->data[j][iFine+1]==-1) { if (iFine<(3+e->curPat[iCoarse].effectCols*2)) pat->data[j][iFine+1]=val; } } diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 2e566bb1a..c374576ef 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -2180,6 +2180,30 @@ void FurnaceGUI::editOptions(bool topMenu) { if (ImGui::BeginMenu("paste special...")) { if (ImGui::MenuItem("paste mix",BIND_FOR(GUI_ACTION_PAT_PASTE_MIX))) doPaste(GUI_PASTE_MODE_MIX_FG); if (ImGui::MenuItem("paste mix (background)",BIND_FOR(GUI_ACTION_PAT_PASTE_MIX_BG))) doPaste(GUI_PASTE_MODE_MIX_BG); + if (ImGui::BeginMenu("paste with ins (foreground)")) { + if (e->song.ins.empty()) { + ImGui::Text("no instruments available"); + } + for (size_t i=0; isong.ins.size(); i++) { + snprintf(id,4095,"%.2X: %s",(int)i,e->song.ins[i]->name.c_str()); + if (ImGui::MenuItem(id)) { + doPaste(GUI_PASTE_MODE_INS_FG,i); + } + } + ImGui::EndMenu(); + } + if (ImGui::BeginMenu("paste with ins (background)")) { + if (e->song.ins.empty()) { + ImGui::Text("no instruments available"); + } + for (size_t i=0; isong.ins.size(); i++) { + snprintf(id,4095,"%.2X: %s",(int)i,e->song.ins[i]->name.c_str()); + if (ImGui::MenuItem(id)) { + doPaste(GUI_PASTE_MODE_INS_BG,i); + } + } + ImGui::EndMenu(); + } if (ImGui::MenuItem("paste flood",BIND_FOR(GUI_ACTION_PAT_PASTE_FLOOD))) doPaste(GUI_PASTE_MODE_FLOOD); if (ImGui::MenuItem("paste overflow",BIND_FOR(GUI_ACTION_PAT_PASTE_OVERFLOW))) doPaste(GUI_PASTE_MODE_OVERFLOW); ImGui::EndMenu(); diff --git a/src/gui/gui.h b/src/gui/gui.h index c44d4c122..77a127595 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -596,7 +596,9 @@ enum PasteMode { GUI_PASTE_MODE_MIX_FG, GUI_PASTE_MODE_MIX_BG, GUI_PASTE_MODE_FLOOD, - GUI_PASTE_MODE_OVERFLOW + GUI_PASTE_MODE_OVERFLOW, + GUI_PASTE_MODE_INS_FG, + GUI_PASTE_MODE_INS_BG }; #define FURKMOD_CTRL (1U<<31) @@ -1708,7 +1710,7 @@ class FurnaceGUI { void doInsert(); void doTranspose(int amount, OperationMask& mask); void doCopy(bool cut); - void doPaste(PasteMode mode=GUI_PASTE_MODE_NORMAL); + void doPaste(PasteMode mode=GUI_PASTE_MODE_NORMAL, int arg=0); void doChangeIns(int ins); void doInterpolate(); void doFade(int p0, int p1, bool mode); From 51c142169fb73d12b07cc726fd1e8f34b37c57f3 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 23:25:57 -0500 Subject: [PATCH 23/39] GUI: OPZ compact editor fixes --- src/gui/insEdit.cpp | 96 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 13 deletions(-) diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 50fd286b8..31dfdb357 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -2928,6 +2928,14 @@ void FurnaceGUI::drawInsEdit() { } } + if (ins->type==DIV_INS_OPZ) { + ImGui::SameLine(); + bool fixedOn=op.egt; + if (ImGui::Checkbox("Fixed",&fixedOn)) { PARAMETER + op.egt=fixedOn; + } + } + //52.0 controls vert scaling; default 96 drawFMEnv(op.tl&maxTl,op.ar&maxArDr,op.dr&maxArDr,(ins->type==DIV_INS_OPL || ins->type==DIV_INS_OPL_DRUMS || ins->type==DIV_INS_OPLL)?((op.rr&15)*2):op.d2r&31,op.rr&15,op.sl&15,op.sus,op.ssgEnv&8,ins->fm.alg,maxTl,maxArDr,ImVec2(ImGui::GetContentRegionAvail().x,52.0*dpiScale),ins->type); //P(CWSliderScalar(FM_NAME(FM_AR),ImGuiDataType_U8,&op.ar,&_ZERO,&_THIRTY_ONE)); rightClickable @@ -3012,23 +3020,85 @@ void FurnaceGUI::drawInsEdit() { ImGui::Text("%s",FM_NAME(FM_KSL)); } - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - P(CWSliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable - ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_MULT)); - - if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { - int detune=(op.dt&7)-(settings.unsignedDetune?0:3); + if (ins->type==DIV_INS_OPZ) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (CWSliderInt("##DT",&detune,-3,4)) { PARAMETER - op.dt=detune+(settings.unsignedDetune?0:3); - } rightClickable + P(CWSliderScalar(FM_NAME(FM_EGSHIFT),ImGuiDataType_U8,&op.ksl,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); - ImGui::Text("%s",FM_NAME(FM_DT)); + ImGui::Text("%s",FM_NAME(FM_EGSHIFT)); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar(FM_NAME(FM_REV),ImGuiDataType_U8,&op.dam,&_ZERO,&_SEVEN)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_REV)); + } + + if (ins->type==DIV_INS_OPZ) { + if (op.egt) { + int block=op.dt; + int freqNum=(op.mult<<4)|(op.dvb&15); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt(FM_NAME(FM_MULT),&block,0,7)) { PARAMETER + if (block<0) block=0; + if (block>7) block=7; + op.dt=block; + } rightClickable + ImGui::TableNextColumn(); + ImGui::Text("Block"); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt(FM_NAME(FM_FINE),&freqNum,0,255)) { PARAMETER + if (freqNum<0) freqNum=0; + if (freqNum>255) freqNum=255; + op.mult=freqNum>>4; + op.dvb=freqNum&15; + } rightClickable + ImGui::TableNextColumn(); + ImGui::Text("FreqNum"); + } else { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_MULT)); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar(FM_NAME(FM_FINE),ImGuiDataType_U8,&op.dvb,&_ZERO,&_FIFTEEN)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_FINE)); + } + } else { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + P(CWSliderScalar(FM_NAME(FM_MULT),ImGuiDataType_U8,&op.mult,&_ZERO,&_FIFTEEN)); rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_MULT)); + } + + if (ins->type==DIV_INS_FM || ins->type==DIV_INS_OPZ) { + if (!(ins->type==DIV_INS_OPZ && op.egt)) { + int detune=(op.dt&7)-(settings.unsignedDetune?0:3); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); + if (CWSliderInt("##DT",&detune,-3,4)) { PARAMETER + op.dt=detune+(settings.unsignedDetune?0:3); + } rightClickable + ImGui::TableNextColumn(); + ImGui::Text("%s",FM_NAME(FM_DT)); + } ImGui::TableNextRow(); ImGui::TableNextColumn(); From 401581e892d964afadc7573de4bc440f48879474 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 23:41:22 -0500 Subject: [PATCH 24/39] fix 116.5 --- src/engine/playback.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/playback.cpp b/src/engine/playback.cpp index 898bb2b05..f6baeb4dc 100644 --- a/src/engine/playback.cpp +++ b/src/engine/playback.cpp @@ -379,7 +379,7 @@ void DivEngine::processRow(int i, bool afterDelay) { break; case 0xed: // delay if (effectVal!=0) { - bool comparison=(song.delayBehavior==1)?(effectVal<=nextSpeed):(effectValtimeBase+1))); if (song.delayBehavior==2) comparison=true; if (comparison) { chan[i].rowDelay=effectVal+1; From 7bb7fa0c24e78c1608920179a2e68e679c6fcaa8 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Wed, 21 Sep 2022 23:45:32 -0500 Subject: [PATCH 25/39] Moon --- demos/Moon.fur | Bin 0 -> 16907 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 demos/Moon.fur diff --git a/demos/Moon.fur b/demos/Moon.fur new file mode 100644 index 0000000000000000000000000000000000000000..366de04523561f89d0767a4c274df2214e39079f GIT binary patch literal 16907 zcmb_?c|26>AOA3xsVsA=o9v^KHdIK~8B|D8A(bt+WT&iIXK3PfWr?DYAwm@0h^!OJ zT3JezWt5rh%ZzQtEa!J-ENQvF-ygs4>!oStIp=vk>+}A6-p@H#Q^xP}W5$m7*CU^t z{%k$oSKc{c^IGEd#tQ@dbq6*l^YghL71(~@H44K&S$ck2;6UBMnf2#j@(A|2BYzva{v0>9m0L)5Gfe(ArcmsOySHC^-@7Ni`k!fQ<`{{mCzFA9K^X)`*|$<& zpY0PRw5QVajD$<6{q`b~>fhG?adv%W4_P6*cebjsYAPwULC++(!b&eG*)M1QL3o3g zJ=Js6C&7nRI!hXx9>^`FPPM;|Iq2QkUQ2gLw7Ggc#jEf2mBYc)#q9>Z(-kw)SNr1W z9kau3TP)}Q?iu*JrQn4fx+QpvexDVwg1N;*)0i0H@V5lo@0Na_1u;W-z5np_Ew-Z( z6`j)mFkWvs#G*TGDG7*fh_~5B`8P4rHSkFT6F5hF>mlL~&<|-($1v~WHqshJ4lxS; zam7EA26o-r5Tf9@;6cB_ZK7~@nkX!yNgHsvN*UA-pmf$>r3lvtQWUeVQlh#8DM*K_ z?Jpwax+ex3eOhLT)Y{aPIhe@=?TpDg^gnVIn$7VJ6|M1!RXy>lm38rW^fftLNS>T6 zI$I7If|Kiu(E7Asl4><*t6BO9AK*zZxat|>5#ZV9r|C~LPt{~*r&bUxQY*;LCVe8x zMAP2zAU7kukfID*Cw=9M%|7Cu;~8R}Jyqd76WH(`CNVrE&{$242XN1iS0K3puGLRQXsY=Bkfg z>cT>J1yx?qpQ#~6Nu57H+#v1RfDU>rV-cJygQo}SeFG|Gj0lbm#;iPG zAN?t|Iixc-8(UT37_V4hIYa8zr&3xvr%Ah2=Sci=R7$rc?b)!mZN9&S?OgBs#O@wK zA_3Ww$ZtK?T&p-wijf*@UWXfLw$csA=Dy2S@{zSwa3Trd9aDop`keJ1e&) zdq#J-_WVR=eDtW#w6)r8%5$?9b{=rXKXAjE**_breG3PNp=NJO&bWUw~@gvrZ&^>vML6GjcG#> zNtD+ys-$w9ds9JG>+PZ4#-FC&W=SybXQgo z2jPzf{ro=~@YZs%lRbN5ZKcEw2C*n#oJ2#^aX}(cgU7SZn!A+nDby-x5+wy-P^p3L zh=Q^mu_e~)8<5)jW6{B`2w;|oV$F+&7U9Gj@3eRTW0kQxzgjtF9w;%U!2TTSlx;m1>Gs(k-n%o8I#^<-~+H zaALx1$L&Z30n$FV25tM)Gv6PSC-PPF*ukalfqcfFZz1^Gje*g_?GJwisE%jLcw)Ps7D0l(_{n%hZG`Z<6#eJ-6u9N z608c|$88w2^o+QkkW!c}D_nKjNXmzqpgDavpLcBPy2S?k`iD3 z{1x89sF+Y7t1so+xJKB$aah=`u~MonZk<$b95U!HBNo+3o;L09oLGP(#G$Vm8nH-s z#{lFPhXbBt8irqVQdO9l7l=ZY@PS7Mx-$5UGq%8}3I2U&)e z3c&kf&GDAc6o&%GW^vXt`N`l5mfAE`H`++~XG$&Jqq#%cz4;p&oUQ#nA(>@q=}wn+ zQ==ohJ%`HO{9g%oQ$FCHlV0Q9n@1mRom`_qxnZNvy5ORp|M}A`f@Iq*+E$Hc-Wkz7 z#O;!5v#+94e2(f1^%ZYT?EQDENvVszjrV+X#e}w`|9ogPW7=Pm)}*ISxn`t6>E5mW zY?v%r`ps1R+2lRR(zny<6uRO>!!?_}TM_uIt>~HX=!&T)lC(TOU*cq6=PmTY34IoG zK$13T;ztCkT5pvWcoYBj@FjLldJ{id_z>NZ;|)-B$1S6RiH7)V1~#ox#OIb<{5zu! zv_ql{s)FttRH17PLcCnJRc_c)TGx21hx)-_jvy1KG`YSpv~X)FvG11VFxM?jpvQnk zd0^1zZ@5i5@ZvVx0M~7VK+kRXkR#iA2ai0PKYUAK`k8_I?1;g{!h(U+RDyxjT(m(d zwa28xVV@=a@zNC)MiKcFk);lphFLndIh512)nfVOLN9*B~zB|1R-lQWAJ|v=7 znP(ld+!L>7T}rLV*JRmQ`%jRp{W~s{QHte!NYc2zJLq6v3)U#FHI0zy`;eKNKNetZ z5gp)V;ZB>&XY>V@QTU~Yn!d#NlCI#!n!L0-@8GGYELd|c*0iaTa?15dKT?ylA4vp1 zbab@D`qS_{G5mgNiZUTyLve;!6&OH?b(tmp+d0`-7&F|sJ7%Qf={(QoZr@n*YkR1e`OmAwN#7n5Aja z`i%l8r51BU%YyO7mc9@1{cc)kgZxbL0aj`cW2;u_fLws*WXl|}MsbeVW;@=93(AvI z1Z+(DC>g0i{exPxF^>QWt}lgAq$2m$*z4KT;N$rvfya+qCB8Kkx4*~gF2gtF8@;FA zF0@fA5waE4?n}(0NA7tN6Xq2Bl40){aUW-5qbFh;+)BC}lkD+)oA5uS4=sZ5cQfUL z4Fcw9A`;pjh6_6+_7=Sd#(D(?D$E6peO6>#~1bK zWtA%?VTvdiWv*dEXl!5g?KDByxuY~%$facG_j_D=peK55>^mPi1vQ;5kbs@@-=73m zW~$HUC#LxIPsLrWrpUHkY8Kva+nImKvED^RJm|iqE@!q2d$!){*_+S#A4uA(thG*S z`en83^L^WMI$i%!j%k4JKXdXSj9NN#uDSebH^iQ4ELsLpPa zBOAi99MTkk4QQAq(F=cS=y1kjZf`csAOutWA1s zAtdlbQ`~rSKr@%#WQwNrNH%QTe|lO^!S@}%&F-nv&F46}igR?`x>{HGIe+COgf}{1 z-%NUhkVk)h&*_)<9M_Nr>G#}+5BTT;K838& zEM{jFYqXBp*~aWV$?Tk^7i^^$jLz70ifxV@7#qg>&f03w3tqEa(t*z((QYSk#+kcw zbM2W@w*gU1Kyb6z{M|Dp7N2~a#BiP;ck}01NPXOX!US($HJH2Zd9P1w-#T4%13g6~ z#ww%=_o?o)GB^WfwrU3Uv{ck~Smm}#!tjG@Mv2?;3SPrss0G!cp75C)=R{MADcU3F zMP<7~Iy|PN=WOREMmq|wItkn;v1+mTdf~YU9+iCc4S9@Yzp&%!uDr)56QX7r!-*Y^ z4TA1Z3F7lF%|Th_&WqYnPN(K{_dK+fm+g~DFcBH{<;hISH(^+|! zo`KboMxFCVC1Jd2^(PAsGNz^z6{Oz$_2O8&dqzi>@*zMaYr!kq?b#fVrwyoL2Um_C~)V$l$p^0_2F!7X>BPl5fr#PPJVNd^i_4Lfs zQg^l+XxU>vC<$46ldE?p?6)xQ7IfNk5%K8^Z(HlM)^__{oYWR9W~cVP)%gQ|qA6jF zC<}1!|5KpS<_lvXIQ&46A~s$2Hg5925G7-co<}0>{s-uwI zec#3ilNTX>zCu3u?C~i)W%qD>m3rYZ=V13Kg43OP_0h+L@4yd-kFywrsNxV;HA$R% zMyFf)Z=a869qxl4(hjIJhkcK4>n#2DJ6|bRRV1q|gFOD2+6E0Hw#OWJrOLCoOyR_v zGAX$708#*UhBMotw`So5Lo(1>81^-gzfKzdp;C7TjUXT1lhgn+ScUK%0@#hxiC z&*$f9Y?16f4r|H|TKX$dM;L71`qb_3rJ3M-xeZ7$*BiLqH#^Ijvw5$Kn%+ahjx!>- zxJahjoWH7TBnLj8ldFeV0tq-~IKo(TskIkcy|lf%KS+7 zd~(aWeTcMWJ^cP2gy1DHpeTLfUmb?D8@vv1&1x<)9F%DN4|=O0qN`&uWDQV7h;p%*2%_iA5dBaIkVgY%_q# zZhmvN(6jy;FBf+$Q>&I4T+1ZKpcwA9ohSp02oGaFZjLa1szjLv1JTz`~rxpWz?0@U&E^)5XJwX!1W$&*=ViZq}=Z-MCGwzkSFhM+R?y(oejrvSP!e?bl)Pd)<#;7M@` z-Y`zwalJ~|2QA55x`^RZQt;@FmCPM&d@*lb339apLLRYg10H+QrzVroqOUq>c#{S+ zqx>sq<%xD)L_fg?$P0zjTOv)(0iOck3Nu4BM+JUvNt8$AN|z zbJ4eg5U~Ii=LTF0R)z=se4E|z->v2v=gkG9`t>3mVAPUfWL(xsMwFJC)<)QLoWe2d zP_zXz9-#Vt0y8mL)_Mre3A9HGn)i}M@0KO8OHQ@R%UmbP&GBO1u(X!!lhCKe?bjol zsD2%Ifv;YPf3SKfY-8=pGuNSB;zwDf%`lDuYFJ)F5ilz(n2|(iD5D;5rAv=xgg)J| zwEiF9H4&!pTpOxO=GUQ}oS`ywzDz$M3s`HV*Co4j(+}?OH7bMfFv=%zN<5728QV}L ztX3{`BQGkW&2i?Yiy*d=oq1qpk6s#OdD3Y`(xVqBa z?vX&DjnXIU>5Qm--2_|K{Qi%4LJk`JrUe;7D+VfiTaXhABNPj1#gAz8GaR~dAd!hi zPLK=KhVVw>8Z1zjQb-J!&ReDu;;EoFACC{;117o!gW=L4(=()yM>oTH$br|ms!!(e z@z5{YV+Jgq;9gXuGU)NAE76qPS!UkH**M5-j`^fXA*1dtiGI2n)USZ2W{4y=`kKVi zGK94)y&hnQE21kHg-n|Gg(vCg6&iM$(MQ3Y&tT7B-@X^oH8fZvc&L+~ha;61 z{<4VC6r|T04F=^U=KK&>D3{K2BofNKc>nFah@n@L`w-_*duK2&F=?N1I8X!5MbJx! z$bsxd1+)-*5jk^%4&VwHwu0;VczUT?>=nYL;G5xQ^l32AoQpbZpkX!)DfS9_!Y~0? zE|Vq-D#gB-hUKcZ`tM6w|GglMsuj}HK=ujg$>|%dni@Fr*dyq^w5n$i*!di&2erQ( zbe~J7vQrfPRQsJel)Juj7IWT+EvgR}pJLBtM40_BOjIVP(WP8kBXobXN3;f<8>&SsYdcXJZnVbLV{H{On z^`K9yTcO<0FlThgauj#ip`NmH_@``Od-6mL=Dfv!`*GsG{isC_ta-I@xtr_Fj9VSVx4(YPlhD>!?;8XNY)%EW!vcy8aKfC|0lSg=ucUi$n+Wzvz5A@HJlyOt z?$vXKlhTB!cxgFw`7o=u=Ah0_dIWEGH&Y?Dq<42tMA~_9c)aEy4YzwoSD%6tx*#ni zENncBUb3#39!_&ALz}g;MoH5nESDtUmYsI;gl!5C|F-sl=FZ*1k(AuWOk<`|KXu=C(HyLdVwe!Q`AvXP6P z`DQL&i9VUw!RyOUo}G(&ZL&Vdjj^q|v(9ABRvh^W?Z$A|;ryQ5^vYzeB@c&C4dKQ< zCs&3otXVr!zdHv=OJjBOF8$87J^|?HFpJiG4dk8Ou<-->8QO+P>_nF%syy!Es_a<$ z;p7a#Z@`i*Ed7ThbO`e*FZmibFwPCwgaW=gK?N_-Cx(#7kQ1>uw_0izE0Qe+Y}s`0 zpdeg`$7AqWKHbM$y1|&(;4z)n_h8WEIae+YbV|ZfWIn6|Kg_-fq(4~?LqM>1B)JjW z#(Cj!2O&Cx9mk;Q8NVHtIkkod4ykDp;)2J`al;HHFlp1yS)r}wzaKXJ?eO00->z*J ze-wd%z)$-ZpQQ;l4RM+%Slp zeFOw%7|4a)CWLDBS9y=>dh~nS6MrwW_xFp>JBT9m@vd8Ko|2FyjQ|r z1)@W%ZSW}uMH6$g=GO}2A5g1w7*S)3B!Oznh0R*4KD;(fhtn$JlfZ7*Kw-C>1MCz1 z^yqBpNFQRc9cl)!x^!;T_TM z7j}NO`8KF>0~xi@_;!OJ*8k5BGXm^}x=rbU3jBak*%{UAZ2TJr+ar1M+zng3u7;g% zcaGoVuqgCtkRUx(>9b+Es|tLYwoO!v{HLlAH{)xHypB5zwM+i&)b0SYGOJ~C zD!`fD^OvtZH!qCkZ~!XdE@zmfyC!pP^?yyw=33V@it^ROCM5W!|_jf zKf0^ou@Gz21}HxA(p8!)AOj-5%AOS>d0Uzl6CJ;s4 zaW5~UTP~vsm(h%tVl)L!WwE<&QH1g~YfrySJq~Zfn*+DLu*RdH)rsDXy(hr{IS`OE zWDt7_s4Pe|N;TS-$Ve`*GgXF%J#zFO>fouFxr{^Nngd5bws~pNW>V2dl%rwUMqn!j z19A?W<2!hRG~0Ep2}?@#PPK?~v+_oe`)?xaRIt&RMibE>CqdF#8{Ud?(+1d%-C~%y zEG9*!AD_$0z8cV?12sJax@QLD)+X(;e)?=)QOo8P1suEH7?u$yc7Ty7oJ6*z z$iyPu+1U`kBxo|6O@3@aXDLU0P1aVs&!y{mIq`wy!()h>?oXX#q6g5$AQh>dXVU|4 zULkwl5=ko=LI2|=>UL{IlU4pLJ_<@ThYy0g!{~oH;l981Maj>;FxAxS%2*#vZCJzEm3b=gIX0aJ zQ?oqR6j5|Y@uP8io1=2T!Z~PlWXXKX#-#NPSDppbKTzVg9mo3ywy}EOl;mfONsCQ- ze9LxbLG_TSUs!GzknS{`H|vl}3t&hW7KlNbH{;3%!90or&kLT8;V0IZ`vE@4w2!?= z)YDNUlm`h?`aSf5K;4dBbgyuZ&%7{v3=CenC`kPin4MbbBNO-u{tsnzewZ(qRPa~b z{HO-)oAEs@NjwL&3z>%=#$(lY7BY!%SoBV1S5K6rR!H25jQWCd;AJb`VF>RwguMI) z$efnT^=FxUM)yu5Y&@$^m|4l%hG$zIjBr2xrigKfX?-Nf;Gy% z3X~0+^s*B=8Y~W&e(#8!#cQcZpLsALnk&tXnK& zLDbZuYu0vNpD+q~%oO>d7s(y~k7~aC-t{2x`eM$1LicXST{0AnIo}DY&OVo^eg>4u zne{R|IT~f5P>GLK;Ki@IOLN{FCjCjaF3&kVANkB@e%Y|%`rn$sKCt=KH<7>fLf0Q) z$RX9kLMP{;&Y)y1^vDFbaqj>A=0AUXbMNnO-r$jV?UO2)&SK-yU}GZ=&SihkJs#S+ zsq%X%;!*6&uWDN>%gP_AX9C;RS(|d#Uy^LC_Ppeyy72oRIr;GAe@2nH2#Sxp-}k&matnr6FkxP0t2(Zk74ILpUSi}SD1he>c$mExynv`FcH(njq#U1jE9iH+e&72!V3#w#vYH8Cv)T;P&b5>AbtZuN_j}2xI)gh>yCayJLQJeo758P4HbIe-? z6Kw7WB+Ww8RO0}1aSmU< zz)x|tTpd@RlPsnBw%bK~H3vE%R%YKGBsG&ubF4T9*qZg_uef4KnLRl_n;p4=GwHi# zO<0zEoLpLj)g?#RW&dpDQzI~I7V+HdAq&iWRM(TAMU9;ldqRV$WZbMDy> zbxYwssq|*PO={=g{?=L9-OWDltd1P;KJ?CV5s+I!u;k(FDM4_pp1^ehM)qQKLLi!av&*+~xaKzj?OB3xwTkAnfX{1pU0Kc1a~0=;b>= z;6;5eJFTZz;MI^wL}uO071Nh0S-i!MRpxt^ELO5rNwPR&RgNsmSe+tZBeYVO z)`m81_CCfgLd#~?Y+5PaVqn4MRIpWu1G*xTf>Vpm$^<*0M|}Mc_KS2_MYkNbUo4^B zD;d31ba_`CvRG3&V6zzM#md!{{*$$1-*J3Vci*3@Zu!qbv~szwLU_RHBiZre)2cXJ zz2T-+&#PW{KinCbWJEmbe;mMbfu-pz|6+0|ub{l13Ir@d9OT0MjTV#$Yh3w5iPt+D~Kw9OaQ}qylOVAr$7exsaRI^N4JagT%`U`zPD zM`0JI)jdk<$)A#C%TNAH&-=-J+X_XwerS8tewtwy|C5Zp1!9;-yT_cRdO=k6UqXsF zJ_C(I|9{o!gQhwmv33DCq`s` zkb-|l!&O}^1Yt(Pfam35f#gP@DMhAe1re9y`g)($nQ9(2AN!^ zVE?!F6l5QZH-6{Dpu?ZoXeD6({>dp7o zbcq79SuCGAJl8Uyv&OeomzunR^C(W7j4^5&nY~db=dv?XE}Y7Z!Np4IX%< z6RD8uVrk5IC2iCWRo2GPe(=0Ww~@>h=7xk+UkbvUaA)k~<{TQzf(HV{ObAahnM=2n zoDIVgt44WX8HB;4ZPcOp((P*w1~BsN7~8n=HXylbhRD!bYN{Qh*pA5`K06?~;2~Zo zEWiw`8+X|RUM7Bx2xn#d^Lk!zx^RM~G)#4?9q>AT7bl9qa!#7Svh|b?OD*=x_(Q(T z3Z&ovlo$n}KC3%Uof!TUa*CE_$JlF%%y?xoQmD>eT{TKtx?fHddG|7-b#KVm!ORe8 zHPd5XN12_-w4_%B=YaiDlk>>o;*_becekR?gFghB$=vB$2m9}RY{?uUY&;m64vcVB@2PTP$(5<2{$4B8WmnDBp{RMD z{t%K5J7}lFFqD2;8%7P0*(=V=>I7dNlC{!?AJj7#psyE`nyNYKGc<>7fgcOKB!+Hx zICx72uBq2g4~ITz{Z|P~gdAAlQrx4N_D%XJlN)j9I{#QuKlb`oY5-IoiZzh6+WP)W z5GM9LLY&@|vrF=`HxKv-X~Ndfzm$eoE~Fvz$ifL5k=hW&%{I_`7a6E=WGPh?WA-*l;a?tyQdGOxkgO?ePX!D8F$VwaKK>p0!*D?5Rn>S7b1Gkn@dJ0)PL41Ci&AwevZNqtQpD!=tk-~?i0yQYus=D%*6iIhVb2s!8d(~w0*HZW zbP;G95CNa;+1bcynOfWy$35EZO1B$Xn@qk}_MnGqno_ofmbwvfTO2%YoP)w$>-b@$ zI@}g`@vGnLJ3AM!hq%o?ndIE6xDLiBnq)KT;;R}ayG(`*Nx2_P{Jxqj9ABs|YOKS} zT#FFDUuJIxfE$n4=sGR;L@p6&Qyu>zDopOqboQkkNegxqFIi*X{6a$$!FaA3-#c(~ zsP4suP=Nt3bHT&yyB}kQxf+$L9s!2PHE-jad4gHQUjFH^qKdCBpE3Y5vXrUD#;YM8<(y-E2BKIBV_>ubJ=iErEM0NXA8 zYD^&A8cf_=+I*%;8@28B2*KMq?xg;d_**bu=J(D$bh(Sm8t*=EQ~LNpG&3m#gj0mRnc2mE=y9lJ9M3 zESCOu=$RAh6MKVR$(BVt_jbWdFd#zOlGnads2@*rkq}$kV#E$U5XXO#jx$--iF!b-DBM;XuY@#jlIH1&Wia`#AtB`A3ba~*sb z-bY6+CSD$(W0ovf!#Q&jU&+bnYYCnWeH%B6MI;^^@`5A}sd&=bc;AGM41UtL`k3zBiXj&_;~UUsCy=6uB3bJui0*B*^WOZZDf?;9ntZp|nZ(rg z;3FDoBmO-Ra<>)p(1y7^SZjK%{HUz!2zuIp)g8`))njuh%TjIyK~U48@{2?cyY zTW@*alYqAuhKFQ|LCmM|e|U~p+A9GI;etP?f%LNd)B12-(Y&4oRZRZD}&Wa}K5 zyK~Z9y=WNLrySCYkE3`_qn$2IqfZY=@7Wm=1hLtBuvYWn7i#Ed^bUAgoPs?hJ#pvW z35j(OySH2_B|2-r%K4nRzc9Q>*36Kcv8LX`4T}T4$%wm!lidEqU zh8ceHA(X8Yf7{_#-P8DMwtJ}2=zse)SQXSOmV>WV$MIRSO5l5%YK9{3;BVM&`7b;s zD7awHono4(19FmtqL5=P@Q*@6NjJdbxNXCy_}~0d9o&&SKMAbc$2TYM3=`oo{2<1HWl ztW{Y8;-)BM&4)i5=aU82 zXikKkPJ&psI0el|u2Sf8Cc7*ihLmkUxBImVXBi)0WlC%I41JK#SO9mcoXMqRq?1-D zgS>WNwVw07b!gma=S?EM{DGcwAMExzW`;BtdPWXuS>@_FmU8&e(1IY`xnfO*v z22gAqKghGCb`Z`8V?*nseIVY3w}5Zpk|R?y3{uM*@J727L-=6p;uJ_dzG9cu4>?N0 zz>25sbN!R3ZuwshF!Sk2Lzf5SjGZ0$;rLe>(fz7P;P%bi|NLm@UZin%iQ8sm%4HT$ zIC&jDy%lxlHu!pR2Qk literal 0 HcmV?d00001 From 32cdd81919ba0aee534210791907ba999c79e9bf Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 00:01:23 -0500 Subject: [PATCH 26/39] OPL: fix chan osc in 4-op mode --- src/engine/platform/opl.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index 2dd6d1dcf..e1ad92f5f 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -1421,6 +1421,15 @@ DivMacroInt* DivPlatformOPL::getChanMacroInt(int ch) { DivDispatchOscBuffer* DivPlatformOPL::getOscBuffer(int ch) { if (ch>=18) return NULL; + if (oplType==3 && ch<12) { + if (chan[ch&(~1)].fourOp) { + if (ch&1) { + return oscBuf[ch-1]; + } else { + return oscBuf[ch+1]; + } + } + } return oscBuf[ch]; } From 9685a5c0d87f00c503a0e220e29fd3f9f92229bc Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 00:18:40 -0500 Subject: [PATCH 27/39] AY: add stereo separation slider --- src/engine/platform/ay.cpp | 5 +++-- src/engine/platform/ay.h | 1 + src/engine/platform/ay8930.cpp | 5 +++-- src/engine/platform/ay8930.h | 1 + src/gui/sysConf.cpp | 8 ++++++++ 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/engine/platform/ay.cpp b/src/engine/platform/ay.cpp index f475b4750..cf52f3d29 100644 --- a/src/engine/platform/ay.cpp +++ b/src/engine/platform/ay.cpp @@ -115,8 +115,8 @@ void DivPlatformAY8910::acquire(short* bufL, short* bufR, size_t start, size_t l ay->sound_stream_update(ayBuf,len); if (stereo) { for (size_t i=0; i>8); + bufR[i+start]=((ayBuf[0][i]*stereoSep)>>8)+ayBuf[1][i]+ayBuf[2][i]; } } else { for (size_t i=0; idevice_reset(); stereo=(flags>>6)&1; + stereoSep=(flags>>8)&255; } int DivPlatformAY8910::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { diff --git a/src/engine/platform/ay.h b/src/engine/platform/ay.h index 4b7ce1068..0537dadab 100644 --- a/src/engine/platform/ay.h +++ b/src/engine/platform/ay.h @@ -66,6 +66,7 @@ class DivPlatformAY8910: public DivDispatch { int dacPos; int dacSample; unsigned char sampleBank; + unsigned char stereoSep; int delay; diff --git a/src/engine/platform/ay8930.cpp b/src/engine/platform/ay8930.cpp index 123dc68ac..d5f01013d 100644 --- a/src/engine/platform/ay8930.cpp +++ b/src/engine/platform/ay8930.cpp @@ -99,8 +99,8 @@ void DivPlatformAY8930::acquire(short* bufL, short* bufR, size_t start, size_t l ay->sound_stream_update(ayBuf,len); if (stereo) { for (size_t i=0; i>8); + bufR[i+start]=((ayBuf[0][i]*stereoSep)>>8)+ayBuf[1][i]+ayBuf[2][i]; } } else { for (size_t i=0; i>6)&1; + stereoSep=(flags>>8)&255; } int DivPlatformAY8930::init(DivEngine* p, int channels, int sugRate, unsigned int flags) { diff --git a/src/engine/platform/ay8930.h b/src/engine/platform/ay8930.h index 81995f2de..75a5f6974 100644 --- a/src/engine/platform/ay8930.h +++ b/src/engine/platform/ay8930.h @@ -66,6 +66,7 @@ class DivPlatformAY8930: public DivDispatch { DivDispatchOscBuffer* oscBuf[3]; unsigned char regPool[32]; unsigned char ayNoiseAnd, ayNoiseOr; + unsigned char stereoSep; bool bank; int delay; diff --git a/src/gui/sysConf.cpp b/src/gui/sysConf.cpp index 900845a69..98b600286 100644 --- a/src/gui/sysConf.cpp +++ b/src/gui/sysConf.cpp @@ -358,6 +358,14 @@ void FurnaceGUI::drawSysConf(int chan, DivSystem type, unsigned int& flags, bool if (ImGui::Checkbox("Stereo##_AY_STEREO",&stereo)) { copyOfFlags=(flags&(~0x40))|(stereo?0x40:0); } + if (stereo) { + int sep=256-((flags>>8)&255); + if (CWSliderInt("Separation",&sep,1,256)) { + if (sep<1) sep=1; + if (sep>256) sep=256; + copyOfFlags=(flags&(~0xff00))|((256-sep)<<8); + } + } ImGui::EndDisabled(); bool clockSel=flags&0x80; ImGui::BeginDisabled((type==DIV_SYSTEM_AY8910) && ((flags&0x30)!=16)); From ac68419b785dc2e3a8d6ffe6c7b0b01c6ef5105e Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 01:18:41 -0500 Subject: [PATCH 28/39] implement KVS on YM2612 --- TODO.md | 4 --- src/engine/fileOps.cpp | 12 ++++++++ src/engine/platform/fmsharedbase.h | 2 ++ src/engine/platform/genesis.cpp | 16 +++++------ src/gui/gui.h | 1 + src/gui/insEdit.cpp | 46 ++++++++++++++++++++++++++++++ 6 files changed, 69 insertions(+), 12 deletions(-) diff --git a/TODO.md b/TODO.md index 84bc08a73..8b1378917 100644 --- a/TODO.md +++ b/TODO.md @@ -1,5 +1 @@ -# to-do for 0.6pre1.5 -- stereo separation control for AY -- KVS -- bug fixes diff --git a/src/engine/fileOps.cpp b/src/engine/fileOps.cpp index 4c213744b..7da21f4fa 100644 --- a/src/engine/fileOps.cpp +++ b/src/engine/fileOps.cpp @@ -196,6 +196,15 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { } */ + // Genesis detuned on Defle v10 and earlier + /*if (ds.version<19 && ds.system[0]==DIV_SYSTEM_GENESIS) { + ds.tuning=443.23; + }*/ + // C64 detuned on Defle v11 and earlier + /*if (ds.version<21 && (ds.system[0]==DIV_SYSTEM_C64_6581 || ds.system[0]==DIV_SYSTEM_C64_8580)) { + ds.tuning=433.2; + }*/ + logI("reading module data..."); if (ds.version>0x0c) { ds.subsong[0]->hilightA=reader.readC(); @@ -449,6 +458,9 @@ bool DivEngine::loadDMF(unsigned char* file, size_t len) { ins->fm.op[j].ssgEnv=reader.readC(); } } + if (ds.version<0x12) { // before version 10 all ops were responsive to volume + ins->fm.op[j].kvs=1; + } logD("OP%d: AM %d AR %d DAM %d DR %d DVB %d EGT %d KSL %d MULT %d RR %d SL %d SUS %d TL %d VIB %d WS %d RS %d DT %d D2R %d SSG-EG %d",j, ins->fm.op[j].am, diff --git a/src/engine/platform/fmsharedbase.h b/src/engine/platform/fmsharedbase.h index 640997392..15baacefa 100644 --- a/src/engine/platform/fmsharedbase.h +++ b/src/engine/platform/fmsharedbase.h @@ -23,6 +23,8 @@ #include "../dispatch.h" #include +#define KVS(x,y) ((chan[x].state.op[y].kvs==2 && isOutput[chan[x].state.alg][y]) || chan[x].state.op[y].kvs==1) + class DivPlatformFMBase: public DivDispatch { protected: const bool isOutput[8][4]={ diff --git a/src/engine/platform/genesis.cpp b/src/engine/platform/genesis.cpp index 515f0c0ae..d289a3515 100644 --- a/src/engine/platform/genesis.cpp +++ b/src/engine/platform/genesis.cpp @@ -254,7 +254,7 @@ void DivPlatformGenesis::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -327,7 +327,7 @@ void DivPlatformGenesis::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -384,7 +384,7 @@ void DivPlatformGenesis::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -501,7 +501,7 @@ void DivPlatformGenesis::muteChannel(int ch, bool mute) { if (isMuted[ch]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[ch].state.alg][j]) { + if (KVS(ch,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -614,7 +614,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -687,7 +687,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -860,7 +860,7 @@ int DivPlatformGenesis::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -1051,7 +1051,7 @@ void DivPlatformGenesis::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/gui/gui.h b/src/gui/gui.h index 77a127595..80b550401 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1603,6 +1603,7 @@ class FurnaceGUI { void drawFMEnv(unsigned char tl, unsigned char ar, unsigned char dr, unsigned char d2r, unsigned char rr, unsigned char sl, unsigned char sus, unsigned char egt, unsigned char algOrGlobalSus, float maxTl, float maxArDr, const ImVec2& size, unsigned short instType); void drawGBEnv(unsigned char vol, unsigned char len, unsigned char sLen, bool dir, const ImVec2& size); void drawSysConf(int chan, DivSystem type, unsigned int& flags, bool modifyOnChange); + void kvsConfig(DivInstrument* ins); // these ones offer ctrl-wheel fine value changes. bool CWSliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format=NULL, ImGuiSliderFlags flags=0); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index 31dfdb357..d08e276a7 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1211,6 +1211,46 @@ inline bool enBit30(const int val) { return false; } + +void FurnaceGUI::kvsConfig(DivInstrument* ins) { + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("(click to configure KVS)"); + } + int opCount=4; + if (ins->type==DIV_INS_OPLL) opCount=2; + if (ins->type==DIV_INS_OPL) opCount=(ins->fm.ops==4)?4:2; + if (ImGui::BeginPopupContextItem("IKVSOpt",ImGuiPopupFlags_MouseButtonLeft)) { + ImGui::Text("operator level changes with volume?"); + if (ImGui::BeginTable("KVSTable",4,ImGuiTableFlags_BordersInner)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthStretch); + for (int i=0; i<4; i++) { + int o=(opCount==4)?orderedOps[i]:i; + if (!(i&1)) ImGui::TableNextRow(); + const char* label="AUTO##OPKVS"; + if (ins->fm.op[o].kvs==0) { + label="NO##OPKVS"; + } else if (ins->fm.op[o].kvs==1) { + label="YES##OPKVS"; + } + ImGui::TableNextColumn(); + ImGui::Text("%d",i+1); + ImGui::TableNextColumn(); + ImGui::PushID(o); + if (ImGui::Button(label,ImVec2(ImGui::GetContentRegionAvail().x,0.0f))) { + if (++ins->fm.op[o].kvs>2) ins->fm.op[o].kvs=0; + PARAMETER; + } + ImGui::PopID(); + } + ImGui::EndTable(); + } + ImGui::EndPopup(); + } +} + void FurnaceGUI::drawMacros(std::vector& macros) { float asFloat[256]; int asInt[256]; @@ -1769,6 +1809,7 @@ void FurnaceGUI::drawInsEdit() { P(CWSliderScalar(FM_NAME(FM_AMS),ImGuiDataType_U8,&ins->fm.ams,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + kvsConfig(ins); break; case DIV_INS_OPZ: ImGui::TableNextColumn(); @@ -1781,6 +1822,8 @@ void FurnaceGUI::drawInsEdit() { P(CWSliderScalar(FM_NAME(FM_AMS2),ImGuiDataType_U8,&ins->fm.ams2,&_ZERO,&_THREE)); rightClickable ImGui::TableNextColumn(); drawAlgorithm(ins->fm.alg,FM_ALGS_4OP,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + kvsConfig(ins); + if (ImGui::Button("Request from TX81Z")) { doAction(GUI_ACTION_TX81Z_REQUEST); } @@ -1813,6 +1856,7 @@ void FurnaceGUI::drawInsEdit() { } ImGui::TableNextColumn(); drawAlgorithm(ins->fm.alg&algMax,fourOp?FM_ALGS_4OP_OPL:FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,48.0*dpiScale)); + kvsConfig(ins); break; } case DIV_INS_OPLL: { @@ -1837,6 +1881,8 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndDisabled(); ImGui::TableNextColumn(); drawAlgorithm(0,FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale)); + kvsConfig(ins); + ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); bool isPresent[4]; From 89916de0672461e8c6208cd7cd9759ea6895fce6 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 01:18:53 -0500 Subject: [PATCH 29/39] remove to-do list --- TODO.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 TODO.md diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 8b1378917..000000000 --- a/TODO.md +++ /dev/null @@ -1 +0,0 @@ - From b053d31a6dc629f2d0f3b312e7517cba0fc45441 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 01:30:51 -0500 Subject: [PATCH 30/39] implement KVS on the rest of FM chips --- src/engine/platform/arcade.cpp | 14 +++++++------- src/engine/platform/genesisext.cpp | 8 ++++---- src/engine/platform/opl.cpp | 25 ++++++++++++++++--------- src/engine/platform/tx81z.cpp | 16 ++++++++-------- src/engine/platform/ym2203.cpp | 16 ++++++++-------- src/engine/platform/ym2203ext.cpp | 2 +- src/engine/platform/ym2608.cpp | 14 +++++++------- src/engine/platform/ym2608ext.cpp | 4 ++-- src/engine/platform/ym2610.cpp | 14 +++++++------- src/engine/platform/ym2610b.cpp | 14 +++++++------- src/engine/platform/ym2610bext.cpp | 4 ++-- src/engine/platform/ym2610ext.cpp | 4 ++-- src/gui/insEdit.cpp | 1 - 13 files changed, 71 insertions(+), 65 deletions(-) diff --git a/src/engine/platform/arcade.cpp b/src/engine/platform/arcade.cpp index 6e925c9a0..c86f806e1 100644 --- a/src/engine/platform/arcade.cpp +++ b/src/engine/platform/arcade.cpp @@ -151,7 +151,7 @@ void DivPlatformArcade::tick(bool sysTick) { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -231,7 +231,7 @@ void DivPlatformArcade::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -289,7 +289,7 @@ void DivPlatformArcade::tick(bool sysTick) { } if (m.tl.had) { op.tl=127-m.tl.val; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -390,7 +390,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -448,7 +448,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -545,7 +545,7 @@ int DivPlatformArcade::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -746,7 +746,7 @@ void DivPlatformArcade::forceIns() { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/genesisext.cpp b/src/engine/platform/genesisext.cpp index a2df33c41..84b906bec 100644 --- a/src/engine/platform/genesisext.cpp +++ b/src/engine/platform/genesisext.cpp @@ -209,7 +209,7 @@ int DivPlatformGenesisExt::dispatch(DivCommand c) { op.tl=c.value2; if (isOpMuted[ch]) { rWrite(baseAddr+0x40,127); - } else if (isOutput[chan[2].state.alg][c.value]) { + } else if (KVS(2,c.value)) { rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); @@ -392,7 +392,7 @@ void DivPlatformGenesisExt::muteChannel(int ch, bool mute) { if (isOpMuted[ch-2]) { rWrite(baseAddr+0x40,127); immWrite(baseAddr+0x40,127); - } else if (isOutput[chan[2].state.alg][ordch]) { + } else if (KVS(2,ordch)) { rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127)); immWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[ch-2].vol&0x7f,127)); } else { @@ -526,7 +526,7 @@ void DivPlatformGenesisExt::forceIns() { if (i==2 && extMode) { // extended channel if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); - } else if (isOutput[chan[i].state.alg][j]) { + } else if (KVS(i,j)) { rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); @@ -535,7 +535,7 @@ void DivPlatformGenesisExt::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/opl.cpp b/src/engine/platform/opl.cpp index e1ad92f5f..65a195048 100644 --- a/src/engine/platform/opl.cpp +++ b/src/engine/platform/opl.cpp @@ -26,6 +26,8 @@ #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 KVSL(x,y) ((chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==2 && isOutputL[ops==4][chan[x].state.alg][y]) || chan[x].state.op[orderedOpsL1[ops==4][y]].kvs==1) + #define CHIP_FREQBASE chipFreqBase // N = invalid @@ -138,6 +140,11 @@ const bool isOutputL[2][4][4]={ #undef N +const int orderedOpsL1[2][4]={ + {0, 1, 0, 1}, // 2-op + {0, 2, 1, 3} // 4-op +}; + const int orderedOpsL[4]={ 0,2,1,3 }; @@ -288,7 +295,7 @@ void DivPlatformOPL::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) { + if (KVSL(i,j) || i>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -406,7 +413,7 @@ void DivPlatformOPL::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) { + if (KVSL(i,j) || i>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -610,7 +617,7 @@ void DivPlatformOPL::muteChannel(int ch, bool mute) { if (isMuted[ch]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[ch].state.alg][i] || ch>melodicChans) { + if (KVSL(ch,i) || ch>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[ch].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -783,7 +790,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) { + if (KVSL(c.chan,i) || c.chan>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -899,7 +906,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) { + if (KVSL(c.chan,i) || c.chan>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -1048,7 +1055,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[c.chan].state.alg][c.value] || c.chan>melodicChans) { + if (KVSL(c.chan,c.value) || c.chan>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -1278,7 +1285,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[c.chan].state.alg][i] || c.chan>melodicChans) { + if (KVSL(c.chan,i) || c.chan>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -1295,7 +1302,7 @@ int DivPlatformOPL::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[c.chan].state.alg][c.value] || c.chan>melodicChans) { + if (KVSL(c.chan,c.value) || c.chan>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[c.chan].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); @@ -1372,7 +1379,7 @@ void DivPlatformOPL::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_KSL_TL,63|(op.ksl<<6)); } else { - if (isOutputL[ops==4][chan[i].state.alg][j] || i>melodicChans) { + if (KVSL(i,j) || i>melodicChans) { rWrite(baseAddr+ADDR_KSL_TL,(63-VOL_SCALE_LOG(63-op.tl,chan[i].outVol&0x3f,63))|(op.ksl<<6)); } else { rWrite(baseAddr+ADDR_KSL_TL,op.tl|(op.ksl<<6)); diff --git a/src/engine/platform/tx81z.cpp b/src/engine/platform/tx81z.cpp index 1c6470fc4..fa29cda60 100644 --- a/src/engine/platform/tx81z.cpp +++ b/src/engine/platform/tx81z.cpp @@ -112,7 +112,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -179,7 +179,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -232,7 +232,7 @@ void DivPlatformTX81Z::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -324,7 +324,7 @@ void DivPlatformTX81Z::muteChannel(int ch, bool mute) { if (isMuted[ch]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[ch].state.alg][i]) { + if (KVS(ch,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -353,7 +353,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -419,7 +419,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -519,7 +519,7 @@ int DivPlatformTX81Z::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -811,7 +811,7 @@ void DivPlatformTX81Z::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2203.cpp b/src/engine/platform/ym2203.cpp index 1c3488006..13fc014d8 100644 --- a/src/engine/platform/ym2203.cpp +++ b/src/engine/platform/ym2203.cpp @@ -220,7 +220,7 @@ void DivPlatformYM2203::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -261,7 +261,7 @@ void DivPlatformYM2203::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -310,7 +310,7 @@ void DivPlatformYM2203::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -427,7 +427,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -487,7 +487,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -572,7 +572,7 @@ int DivPlatformYM2203::dispatch(DivCommand c) { if (isMuted[c.chan]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -764,7 +764,7 @@ void DivPlatformYM2203::muteChannel(int ch, bool mute) { if (isMuted[ch]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[ch].state.alg][j]) { + if (KVS(ch,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[ch].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -781,7 +781,7 @@ void DivPlatformYM2203::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2203ext.cpp b/src/engine/platform/ym2203ext.cpp index c7080d431..527a8be6b 100644 --- a/src/engine/platform/ym2203ext.cpp +++ b/src/engine/platform/ym2203ext.cpp @@ -442,7 +442,7 @@ void DivPlatformYM2203Ext::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2608.cpp b/src/engine/platform/ym2608.cpp index 42bea41b2..42a3235d9 100644 --- a/src/engine/platform/ym2608.cpp +++ b/src/engine/platform/ym2608.cpp @@ -376,7 +376,7 @@ void DivPlatformYM2608::tick(bool sysTick) { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -421,7 +421,7 @@ void DivPlatformYM2608::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -475,7 +475,7 @@ void DivPlatformYM2608::tick(bool sysTick) { } if (m.tl.had) { op.tl=127-m.tl.val; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -698,7 +698,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -779,7 +779,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -890,7 +890,7 @@ int DivPlatformYM2608::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -1093,7 +1093,7 @@ void DivPlatformYM2608::forceIns() { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2608ext.cpp b/src/engine/platform/ym2608ext.cpp index 116f6b95c..7f49ed9d6 100644 --- a/src/engine/platform/ym2608ext.cpp +++ b/src/engine/platform/ym2608ext.cpp @@ -442,7 +442,7 @@ void DivPlatformYM2608Ext::forceIns() { if (i==2) { // extended channel if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); - } else if (isOutput[chan[i].state.alg][j]) { + } else if (KVS(i,j)) { rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); @@ -451,7 +451,7 @@ void DivPlatformYM2608Ext::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2610.cpp b/src/engine/platform/ym2610.cpp index 6a8509d55..34a402e2b 100644 --- a/src/engine/platform/ym2610.cpp +++ b/src/engine/platform/ym2610.cpp @@ -417,7 +417,7 @@ void DivPlatformYM2610::tick(bool sysTick) { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -462,7 +462,7 @@ void DivPlatformYM2610::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -516,7 +516,7 @@ void DivPlatformYM2610::tick(bool sysTick) { } if (m.tl.had) { op.tl=127-m.tl.val; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -742,7 +742,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -823,7 +823,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -934,7 +934,7 @@ int DivPlatformYM2610::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -1137,7 +1137,7 @@ void DivPlatformYM2610::forceIns() { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2610b.cpp b/src/engine/platform/ym2610b.cpp index 31cd7b3ff..bbdb3c60d 100644 --- a/src/engine/platform/ym2610b.cpp +++ b/src/engine/platform/ym2610b.cpp @@ -400,7 +400,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -445,7 +445,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -499,7 +499,7 @@ void DivPlatformYM2610B::tick(bool sysTick) { } if (m.tl.had) { op.tl=127-m.tl.val; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -724,7 +724,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { if (!chan[c.chan].active || chan[c.chan].insChanged) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } @@ -805,7 +805,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { for (int i=0; i<4; i++) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[i]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[i]; - if (isOutput[chan[c.chan].state.alg][i]) { + if (KVS(c.chan,i)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -916,7 +916,7 @@ int DivPlatformYM2610B::dispatch(DivCommand c) { unsigned short baseAddr=chanOffs[c.chan]|opOffs[orderedOps[c.value]]; DivInstrumentFM::Operator& op=chan[c.chan].state.op[orderedOps[c.value]]; op.tl=c.value2; - if (isOutput[chan[c.chan].state.alg][c.value]) { + if (KVS(c.chan,c.value)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[c.chan].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); @@ -1119,7 +1119,7 @@ void DivPlatformYM2610B::forceIns() { for (int j=0; j<4; j++) { unsigned short baseAddr=chanOffs[i]|opOffs[j]; DivInstrumentFM::Operator& op=chan[i].state.op[j]; - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2610bext.cpp b/src/engine/platform/ym2610bext.cpp index f55e6561c..a13598554 100644 --- a/src/engine/platform/ym2610bext.cpp +++ b/src/engine/platform/ym2610bext.cpp @@ -442,7 +442,7 @@ void DivPlatformYM2610BExt::forceIns() { if (i==2 && extMode) { // extended channel if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); - } else if (isOutput[chan[i].state.alg][j]) { + } else if (KVS(i,j)) { rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); @@ -451,7 +451,7 @@ void DivPlatformYM2610BExt::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/engine/platform/ym2610ext.cpp b/src/engine/platform/ym2610ext.cpp index 6cee242f4..66090514f 100644 --- a/src/engine/platform/ym2610ext.cpp +++ b/src/engine/platform/ym2610ext.cpp @@ -442,7 +442,7 @@ void DivPlatformYM2610Ext::forceIns() { if (i==1 && extMode) { // extended channel if (isOpMuted[j]) { rWrite(baseAddr+0x40,127); - } else if (isOutput[chan[i].state.alg][j]) { + } else if (KVS(i,j)) { rWrite(baseAddr+0x40,127-VOL_SCALE_LOG(127-op.tl,opChan[j].vol&0x7f,127)); } else { rWrite(baseAddr+0x40,op.tl); @@ -451,7 +451,7 @@ void DivPlatformYM2610Ext::forceIns() { if (isMuted[i]) { rWrite(baseAddr+ADDR_TL,127); } else { - if (isOutput[chan[i].state.alg][j]) { + if (KVS(i,j)) { rWrite(baseAddr+ADDR_TL,127-VOL_SCALE_LOG(127-op.tl,chan[i].outVol&0x7f,127)); } else { rWrite(baseAddr+ADDR_TL,op.tl); diff --git a/src/gui/insEdit.cpp b/src/gui/insEdit.cpp index d08e276a7..08b2f509c 100644 --- a/src/gui/insEdit.cpp +++ b/src/gui/insEdit.cpp @@ -1881,7 +1881,6 @@ void FurnaceGUI::drawInsEdit() { ImGui::EndDisabled(); ImGui::TableNextColumn(); drawAlgorithm(0,FM_ALGS_2OP_OPL,ImVec2(ImGui::GetContentRegionAvail().x,24.0*dpiScale)); - kvsConfig(ins); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); From 02d207716270c9c76ef2e9889253addca461b7ba Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 02:46:55 -0500 Subject: [PATCH 31/39] MIDI out: turn notes off on reset() --- src/engine/engine.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index bb03eda18..217cc977e 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -2000,6 +2000,14 @@ void DivEngine::recalcChans() { } void DivEngine::reset() { + if (output) if (output->midiOut!=NULL) { + output->midiOut->send(TAMidiMessage(TA_MIDI_MACHINE_STOP,0,0)); + for (int i=0; i=0) { + output->midiOut->send(TAMidiMessage(0x80|(i&15),chan[i].curMidiNote,0)); + } + } + } for (int i=0; idispatch(DivCommand(DIV_CMD_GET_VOLMAX,dispatchChanOfChan[i]))<<8)|0xff; From cec31b23de970448fc9bb857f24682302d7d7bde Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 04:04:32 -0500 Subject: [PATCH 32/39] GUI: temporarily disable InputText undo/redo issue #624 --- extern/imgui_patched/imgui_widgets.cpp | 15 +++++++++--- extern/imgui_patched/imstb_textedit.h | 33 ++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/extern/imgui_patched/imgui_widgets.cpp b/extern/imgui_patched/imgui_widgets.cpp index 93dfd5343..d6ddfdb88 100644 --- a/extern/imgui_patched/imgui_widgets.cpp +++ b/extern/imgui_patched/imgui_widgets.cpp @@ -3713,7 +3713,12 @@ static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const Im { const bool is_resizable = (obj->Flags & ImGuiInputTextFlags_CallbackResize) != 0; const int text_len = obj->CurLenW; - IM_ASSERT(pos <= text_len); + if (pos > text_len) { + printf("failing STB_TEXTEDIT_INSERTCHARS assertion! oh man...\n"); + obj->Edited = true; // ??? + obj->ClearText(); + return false; + } const int new_text_len_utf8 = ImTextCountUtf8BytesFromStr(new_text, new_text + new_text_len); if (!is_resizable && (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufCapacityA)) @@ -3776,8 +3781,11 @@ static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* st state->cursor = text_len; state->has_preferred_x = 0; return; + } else { + state->cursor = 0; + printf("STB_TEXTEDIT_INSERTCHARS fail!\n"); } - IM_ASSERT(0); // Failed to insert character, normally shouldn't happen because of how we currently use stb_textedit_replace() + //IM_ASSERT(0); // Failed to insert character, normally shouldn't happen because of how we currently use stb_textedit_replace() } } // namespace ImStb @@ -3962,7 +3970,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0; const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; - const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0; + // https://github.com/tildearrow/furnace/issues/624 + const bool is_undoable = 0; //(flags & ImGuiInputTextFlags_NoUndoRedo) == 0; const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0; if (is_resizable) IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! diff --git a/extern/imgui_patched/imstb_textedit.h b/extern/imgui_patched/imstb_textedit.h index 75a159dac..d93642305 100644 --- a/extern/imgui_patched/imstb_textedit.h +++ b/extern/imgui_patched/imstb_textedit.h @@ -717,6 +717,9 @@ static int stb_textedit_paste_internal(STB_TEXTEDIT_STRING *str, STB_TexteditSta state->cursor += len; state->has_preferred_x = 0; return 1; + } else { + printf("stb_textedit_paste_internal failed.\n"); + state->cursor=0; } // note: paste failure will leave deleted selection, may be restored with an undo (see https://github.com/nothings/stb/issues/734 for details) return 0; @@ -746,6 +749,9 @@ retry: if (STB_TEXTEDIT_INSERTCHARS(str, state->cursor, &ch, 1)) { ++state->cursor; state->has_preferred_x = 0; + } else { + printf("key failed: first section.\n"); + state->cursor=0; } } else { stb_textedit_delete_selection(str,state); // implicitly clamps @@ -753,6 +759,9 @@ retry: stb_text_makeundo_insert(state, state->cursor, 1); ++state->cursor; state->has_preferred_x = 0; + } else { + printf("key failed: second section.\n"); + state->cursor=0; } } } @@ -1275,14 +1284,22 @@ static void stb_text_undo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) STB_TEXTEDIT_DELETECHARS(str, u.where, u.delete_length); } + bool steFailed=false; + // check type of recorded action: if (u.insert_length) { // easy case: was a deletion, so we need to insert n characters - STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length); + if (!STB_TEXTEDIT_INSERTCHARS(str, u.where, &s->undo_char[u.char_storage], u.insert_length)) { + printf("undo u.insert_length failed\n"); + state->cursor=0; + steFailed=true; + } s->undo_char_point -= u.insert_length; } - state->cursor = u.where + u.insert_length; + if (!steFailed) { + state->cursor = u.where + u.insert_length; + } s->undo_point--; s->redo_point--; @@ -1327,13 +1344,21 @@ static void stb_text_redo(STB_TEXTEDIT_STRING *str, STB_TexteditState *state) STB_TEXTEDIT_DELETECHARS(str, r.where, r.delete_length); } + bool steFailed=false; + if (r.insert_length) { // easy case: need to insert n characters - STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length); + if (!STB_TEXTEDIT_INSERTCHARS(str, r.where, &s->undo_char[r.char_storage], r.insert_length)) { + printf("redo insert char failed\n"); + state->cursor=0; + steFailed=true; + } s->redo_char_point += r.insert_length; } - state->cursor = r.where + r.insert_length; + if (!steFailed) { + state->cursor = r.where + r.insert_length; + } s->undo_point++; s->redo_point++; From b9d8d91ca7b7e2b8e74b877487d63b4f5bf45de1 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 04:10:12 -0500 Subject: [PATCH 33/39] GUI: I am done look I need to sleep --- extern/imgui_patched/imgui.h | 2 +- extern/imgui_patched/imgui_widgets.cpp | 3 +-- src/gui/songInfo.cpp | 8 ++++---- src/gui/songNotes.cpp | 2 +- src/gui/subSongs.cpp | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/extern/imgui_patched/imgui.h b/extern/imgui_patched/imgui.h index e9ccea9b1..3d600ea2b 100644 --- a/extern/imgui_patched/imgui.h +++ b/extern/imgui_patched/imgui.h @@ -1042,7 +1042,7 @@ enum ImGuiInputTextFlags_ ImGuiInputTextFlags_AlwaysOverwrite = 1 << 13, // Overwrite mode ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode ImGuiInputTextFlags_Password = 1 << 15, // Password mode, display all characters as '*' - ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). + ImGuiInputTextFlags_UndoRedo = 1 << 16, // Enable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID(). ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input) ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this) ImGuiInputTextFlags_CallbackEdit = 1 << 19 // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active) diff --git a/extern/imgui_patched/imgui_widgets.cpp b/extern/imgui_patched/imgui_widgets.cpp index d6ddfdb88..4579400d4 100644 --- a/extern/imgui_patched/imgui_widgets.cpp +++ b/extern/imgui_patched/imgui_widgets.cpp @@ -3970,8 +3970,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0; const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0; const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0; - // https://github.com/tildearrow/furnace/issues/624 - const bool is_undoable = 0; //(flags & ImGuiInputTextFlags_NoUndoRedo) == 0; + const bool is_undoable = (flags & ImGuiInputTextFlags_UndoRedo) != 0; const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0; if (is_resizable) IM_ASSERT(callback != NULL); // Must provide a callback if you set the ImGuiInputTextFlags_CallbackResize flag! diff --git a/src/gui/songInfo.cpp b/src/gui/songInfo.cpp index 5b113c641..8d4e0999e 100644 --- a/src/gui/songInfo.cpp +++ b/src/gui/songInfo.cpp @@ -39,7 +39,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::TableNextColumn(); float avail=ImGui::GetContentRegionAvail().x; ImGui::SetNextItemWidth(avail); - if (ImGui::InputText("##Name",&e->song.name)) { MARK_MODIFIED + if (ImGui::InputText("##Name",&e->song.name,ImGuiInputTextFlags_UndoRedo)) { MARK_MODIFIED updateWindowTitle(); } if (e->song.insLen==2) { @@ -61,7 +61,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::Text("Author"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(avail); - if (ImGui::InputText("##Author",&e->song.author)) { + if (ImGui::InputText("##Author",&e->song.author,ImGuiInputTextFlags_UndoRedo)) { MARK_MODIFIED; } @@ -70,7 +70,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::Text("Album"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(avail); - if (ImGui::InputText("##Category",&e->song.category)) { + if (ImGui::InputText("##Category",&e->song.category,ImGuiInputTextFlags_UndoRedo)) { MARK_MODIFIED; } ImGui::TableNextRow(); @@ -78,7 +78,7 @@ void FurnaceGUI::drawSongInfo() { ImGui::Text("System"); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(MAX(16.0f*dpiScale,avail-autoButtonSize-ImGui::GetStyle().ItemSpacing.x)); - if (ImGui::InputText("##SystemName",&e->song.systemName)) { + if (ImGui::InputText("##SystemName",&e->song.systemName,ImGuiInputTextFlags_UndoRedo)) { MARK_MODIFIED; updateWindowTitle(); e->song.autoSystem=false; diff --git a/src/gui/songNotes.cpp b/src/gui/songNotes.cpp index 74f4ed7ff..338c7da24 100644 --- a/src/gui/songNotes.cpp +++ b/src/gui/songNotes.cpp @@ -30,7 +30,7 @@ void FurnaceGUI::drawNotes() { } if (!notesOpen) return; if (ImGui::Begin("Song Comments",¬esOpen,globalWinFlags)) { - ImGui::InputTextMultiline("##SongNotes",&e->song.notes,ImGui::GetContentRegionAvail()); + ImGui::InputTextMultiline("##SongNotes",&e->song.notes,ImGui::GetContentRegionAvail(),ImGuiInputTextFlags_UndoRedo); } if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) curWindow=GUI_WINDOW_NOTES; ImGui::End(); diff --git a/src/gui/subSongs.cpp b/src/gui/subSongs.cpp index c56bf6405..f076298f2 100644 --- a/src/gui/subSongs.cpp +++ b/src/gui/subSongs.cpp @@ -91,7 +91,7 @@ void FurnaceGUI::drawSubSongs() { ImGui::Text("Name"); ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); - if (ImGui::InputText("##SubSongName",&e->curSubSong->name)) { + if (ImGui::InputText("##SubSongName",&e->curSubSong->name,ImGuiInputTextFlags_UndoRedo)) { MARK_MODIFIED; } } From 1ceca2a509ed31022d300ea8cf18afd20dffb20a Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 04:13:26 -0500 Subject: [PATCH 34/39] release v0.6pre1.5 --- papers/format.md | 1 + src/engine/engine.h | 4 ++-- src/gui/about.cpp | 9 +++++---- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/papers/format.md b/papers/format.md index acedd9945..1d4e7fc76 100644 --- a/papers/format.md +++ b/papers/format.md @@ -32,6 +32,7 @@ these fields are 0 in format versions prior to 100 (0.6pre1). the format versions are: +- 116: Furnace 0.6pre1.5 - 115: Furnace dev115 - 114: Furnace dev114 - 113: Furnace dev113 diff --git a/src/engine/engine.h b/src/engine/engine.h index 40bbbbb90..461c91c0b 100644 --- a/src/engine/engine.h +++ b/src/engine/engine.h @@ -46,8 +46,8 @@ #define BUSY_BEGIN_SOFT softLocked=true; isBusy.lock(); #define BUSY_END isBusy.unlock(); softLocked=false; -#define DIV_VERSION "dev115" -#define DIV_ENGINE_VERSION 115 +#define DIV_VERSION "0.6pre1.5" +#define DIV_ENGINE_VERSION 116 // for imports #define DIV_VERSION_MOD 0xff01 #define DIV_VERSION_FC 0xff02 diff --git a/src/gui/about.cpp b/src/gui/about.cpp index b763ab97c..7e5dfdf26 100644 --- a/src/gui/about.cpp +++ b/src/gui/about.cpp @@ -23,16 +23,17 @@ const char* aboutLine[]={ "tildearrow", - "is proud to present", + "is not so happy to present", "", ("Furnace " DIV_VERSION), "", "the biggest multi-system chiptune tracker!", "featuring DefleMask song compatibility.", "", - "zero disassembly.", - "just clean-room design,", - "time and dedication.", + "what a mess of a versioning scheme we have...", + "I mean it! these pre-releases are like normal releases", + "by now but only because I promised you to have SNES in", + "0.6pre2 I am doing this whole mess...", "", "> CREDITS <", "", From d354f58a7c924567e62111999888aefca8d92d8d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 04:27:18 -0500 Subject: [PATCH 35/39] really release 0.6pre1.5 --- src/gui/gui.cpp | 76 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 58 insertions(+), 18 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index c374576ef..a57ccf396 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -690,11 +690,11 @@ ImVec4 FurnaceGUI::channelTextColor(int ch) { const char* defaultLayout="[Window][DockSpaceViewport_11111111]\n\ Pos=0,24\n\ -Size=1280,731\n\ +Size=1280,776\n\ Collapsed=0\n\ \n\ [Window][Debug##Default]\n\ -Pos=54,0\n\ +Pos=54,19\n\ Size=400,400\n\ Collapsed=0\n\ \n\ @@ -705,9 +705,9 @@ Collapsed=0\n\ \n\ [Window][Song Information]\n\ Pos=978,24\n\ -Size=302,217\n\ +Size=302,179\n\ Collapsed=0\n\ -DockId=0x00000004,0\n\ +DockId=0x0000000F,0\n\ \n\ [Window][Orders]\n\ Pos=0,24\n\ @@ -719,7 +719,7 @@ DockId=0x00000007,0\n\ Pos=653,24\n\ Size=323,217\n\ Collapsed=0\n\ -DockId=0x00000006,2\n\ +DockId=0x00000006,0\n\ \n\ [Window][Wavetables]\n\ Pos=653,24\n\ @@ -731,13 +731,13 @@ DockId=0x00000006,1\n\ Pos=653,24\n\ Size=323,217\n\ Collapsed=0\n\ -DockId=0x00000006,0\n\ +DockId=0x00000006,2\n\ \n\ [Window][Pattern]\n\ Pos=0,243\n\ -Size=1246,512\n\ +Size=1246,557\n\ Collapsed=0\n\ -DockId=0x0000000B,0\n\ +DockId=0x00000013,0\n\ \n\ [Window][Instrument Editor]\n\ Pos=372,102\n\ @@ -746,7 +746,7 @@ Collapsed=0\n\ \n\ [Window][Warning]\n\ Pos=481,338\n\ -Size=346,71\n\ +Size=264,86\n\ Collapsed=0\n\ \n\ [Window][Sample Editor]\n\ @@ -779,8 +779,8 @@ Size=514,71\n\ Collapsed=0\n\ \n\ [Window][Mixer]\n\ -Pos=63,55\n\ -Size=450,215\n\ +Pos=429,198\n\ +Size=453,355\n\ Collapsed=0\n\ \n\ [Window][Oscilloscope]\n\ @@ -791,7 +791,7 @@ DockId=0x0000000E,0\n\ \n\ [Window][Volume Meter]\n\ Pos=1248,243\n\ -Size=32,512\n\ +Size=32,557\n\ Collapsed=0\n\ DockId=0x0000000C,0\n\ \n\ @@ -866,9 +866,10 @@ Size=368,449\n\ Collapsed=0\n\ \n\ [Window][Register View]\n\ -Pos=847,180\n\ -Size=417,393\n\ +Pos=829,243\n\ +Size=417,557\n\ Collapsed=0\n\ +DockId=0x00000014,0\n\ \n\ [Window][New Song]\n\ Pos=267,110\n\ @@ -887,8 +888,40 @@ Size=304,40\n\ Collapsed=0\n\ DockId=0x0000000A,0\n\ \n\ +[Window][Subsongs]\n\ +Pos=978,205\n\ +Size=302,36\n\ +Collapsed=0\n\ +DockId=0x00000010,0\n\ +\n\ +[Window][Oscilloscope (per-channel)]\n\ +Pos=1095,243\n\ +Size=151,557\n\ +Collapsed=0\n\ +DockId=0x00000012,0\n\ +\n\ +[Window][Piano]\n\ +Pos=177,669\n\ +Size=922,118\n\ +Collapsed=0\n\ +\n\ +[Window][Log Viewer]\n\ +Pos=60,60\n\ +Size=541,637\n\ +Collapsed=0\n\ +\n\ +[Window][Pattern Manager]\n\ +Pos=60,60\n\ +Size=1099,366\n\ +Collapsed=0\n\ +\n\ +[Window][Chip Manager]\n\ +Pos=60,60\n\ +Size=490,407\n\ +Collapsed=0\n\ +\n\ [Docking][Data]\n\ -DockSpace ID=0x8B93E3BD Window=0xA787BDB4 Pos=0,24 Size=1280,731 Split=Y Selected=0x6C01C512\n\ +DockSpace ID=0x8B93E3BD Window=0xA787BDB4 Pos=0,24 Size=1280,776 Split=Y Selected=0x6C01C512\n\ DockNode ID=0x00000001 Parent=0x8B93E3BD SizeRef=1280,217 Split=X Selected=0xF3094A52\n\ DockNode ID=0x00000003 Parent=0x00000001 SizeRef=976,231 Split=X Selected=0x65CC51DC\n\ DockNode ID=0x00000007 Parent=0x00000003 SizeRef=345,231 HiddenTabBar=1 Selected=0x8F5BFC9A\n\ @@ -899,10 +932,17 @@ DockSpace ID=0x8B93E3BD Window=0xA787BDB4 Pos=0,24 Size=1280,731 Spl DockNode ID=0x0000000E Parent=0x00000009 SizeRef=292,105 HiddenTabBar=1 Selected=0x6D682373\n\ DockNode ID=0x0000000A Parent=0x00000005 SizeRef=292,40 HiddenTabBar=1 Selected=0x0DE44CFF\n\ DockNode ID=0x00000006 Parent=0x00000008 SizeRef=323,406 Selected=0xD2AD486B\n\ - DockNode ID=0x00000004 Parent=0x00000001 SizeRef=302,231 Selected=0x60B9D088\n\ + DockNode ID=0x00000004 Parent=0x00000001 SizeRef=302,231 Split=Y Selected=0x60B9D088\n\ + DockNode ID=0x0000000F Parent=0x00000004 SizeRef=302,179 Selected=0x60B9D088\n\ + DockNode ID=0x00000010 Parent=0x00000004 SizeRef=302,36 HiddenTabBar=1 Selected=0x723A6369\n\ DockNode ID=0x00000002 Parent=0x8B93E3BD SizeRef=1280,512 Split=X Selected=0x6C01C512\n\ - DockNode ID=0x0000000B Parent=0x00000002 SizeRef=1246,503 CentralNode=1 HiddenTabBar=1 Selected=0xB9ADD0D5\n\ - DockNode ID=0x0000000C Parent=0x00000002 SizeRef=32,503 HiddenTabBar=1 Selected=0x644DA2C1\n\n"; + DockNode ID=0x0000000B Parent=0x00000002 SizeRef=1246,503 Split=X Selected=0xB9ADD0D5\n\ + DockNode ID=0x00000011 Parent=0x0000000B SizeRef=1093,557 Split=X Selected=0xB9ADD0D5\n\ + DockNode ID=0x00000013 Parent=0x00000011 SizeRef=827,557 CentralNode=1 HiddenTabBar=1 Selected=0xB9ADD0D5\n\ + DockNode ID=0x00000014 Parent=0x00000011 SizeRef=417,557 Selected=0x425428FB\n\ + DockNode ID=0x00000012 Parent=0x0000000B SizeRef=151,557 HiddenTabBar=1 Selected=0x4C07BC58\n\ + DockNode ID=0x0000000C Parent=0x00000002 SizeRef=32,503 HiddenTabBar=1 Selected=0x644DA2C1\n"; + void FurnaceGUI::prepareLayout() { FILE* check; From 52cd4f15de79715d96b36eeaad5a119ad998996d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 18:33:58 -0500 Subject: [PATCH 36/39] finally fix macro speed/delay issue --- src/engine/macroInt.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine/macroInt.cpp b/src/engine/macroInt.cpp index 36850818f..955481ce0 100644 --- a/src/engine/macroInt.cpp +++ b/src/engine/macroInt.cpp @@ -34,6 +34,7 @@ void DivMacroStruct::doMacro(DivInstrumentMacro& source, bool released, bool tic } if (delay>0) { delay--; + had=false; return; } if (began && source.delay>0) { From cbff5f190cca6292f7a4446540677081305baeea Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 18:43:48 -0500 Subject: [PATCH 37/39] NES: implement DPCM loop --- src/engine/platform/nes.cpp | 9 ++++++--- src/engine/platform/nes.h | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/engine/platform/nes.cpp b/src/engine/platform/nes.cpp index 50fcd5ca6..11e0fdddb 100644 --- a/src/engine/platform/nes.cpp +++ b/src/engine/platform/nes.cpp @@ -320,9 +320,10 @@ void DivPlatformNES::tick(bool sysTick) { unsigned int dpcmAddr=parent->getSample(dacSample)->offDPCM; unsigned int dpcmLen=(parent->getSample(dacSample)->lengthDPCM+15)>>4; if (dpcmLen>255) dpcmLen=255; + goingToLoop=parent->getSample(dacSample)->isLoopable(); // write DPCM rWrite(0x4015,15); - rWrite(0x4010,calcDPCMRate(dacRate)); + rWrite(0x4010,calcDPCMRate(dacRate)|(goingToLoop?0x40:0)); rWrite(0x4012,(dpcmAddr>>6)&0xff); rWrite(0x4013,dpcmLen&0xff); rWrite(0x4015,31); @@ -330,7 +331,7 @@ void DivPlatformNES::tick(bool sysTick) { } } else { if (dpcmMode) { - rWrite(0x4010,calcDPCMRate(dacRate)); + rWrite(0x4010,calcDPCMRate(dacRate)|(goingToLoop?0x40:0)); } } if (dumpWrites && !dpcmMode) addWrite(0xffff0001,dacRate); @@ -385,9 +386,10 @@ int DivPlatformNES::dispatch(DivCommand c) { unsigned int dpcmAddr=parent->getSample(dacSample)->offDPCM; unsigned int dpcmLen=(parent->getSample(dacSample)->lengthDPCM+15)>>4; if (dpcmLen>255) dpcmLen=255; + goingToLoop=parent->getSample(dacSample)->isLoopable(); // write DPCM rWrite(0x4015,15); - rWrite(0x4010,calcDPCMRate(dacRate)); + rWrite(0x4010,calcDPCMRate(dacRate)|(goingToLoop?0x40:0)); rWrite(0x4012,(dpcmAddr>>6)&0xff); rWrite(0x4013,dpcmLen&0xff); rWrite(0x4015,31); @@ -612,6 +614,7 @@ void DivPlatformNES::reset() { sampleBank=0; dpcmBank=0; dpcmMode=false; + goingToLoop=false; if (useNP) { nes1_NP->Reset(); diff --git a/src/engine/platform/nes.h b/src/engine/platform/nes.h index c00003305..85c14b0c9 100644 --- a/src/engine/platform/nes.h +++ b/src/engine/platform/nes.h @@ -73,6 +73,7 @@ class DivPlatformNES: public DivDispatch { bool dpcmMode; bool dacAntiClickOn; bool useNP; + bool goingToLoop; struct NESAPU* nes; xgm::NES_APU* nes1_NP; xgm::NES_DMC* nes2_NP; From 861b1cb9ca5d6a814cf137935a8a25502db02ca2 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 19:02:25 -0500 Subject: [PATCH 38/39] OPLL: finally fix pitch macro --- src/engine/platform/opll.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/engine/platform/opll.cpp b/src/engine/platform/opll.cpp index 9485551aa..5c6981588 100644 --- a/src/engine/platform/opll.cpp +++ b/src/engine/platform/opll.cpp @@ -243,8 +243,9 @@ void DivPlatformOPLL::tick(bool sysTick) { if (chan[i].freqChanged) { chan[i].freq=parent->calcFreq(chan[i].baseFreq,chan[i].pitch,false,octave(chan[i].baseFreq)*2,chan[i].pitch2,chipClock,CHIP_FREQBASE); if (chan[i].fixedFreq>0) chan[i].freq=chan[i].fixedFreq; - if (chan[i].freq>262143) chan[i].freq=262143; - int freqt=toFreq(chan[i].freq)+chan[i].pitch2; + if (chan[i].freq<0) chan[i].freq=0; + if (chan[i].freq>65535) chan[i].freq=65535; + int freqt=toFreq(chan[i].freq); chan[i].freqL=freqt&0xff; if (i>=6 && properDrums) { immWrite(0x10+drumSlot[i],freqt&0xff); From fa78877dfd1277f5edb68c36e4e3ef88946fb692 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 22 Sep 2022 19:12:59 -0500 Subject: [PATCH 39/39] always do UTF-8 to UTF-16 when saving layout on W indows --- extern/imgui_patched/imgui.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/imgui_patched/imgui.cpp b/extern/imgui_patched/imgui.cpp index 8b013816f..d52945d4e 100644 --- a/extern/imgui_patched/imgui.cpp +++ b/extern/imgui_patched/imgui.cpp @@ -1818,7 +1818,7 @@ ImGuiID ImHashStr(const char* data_p, size_t data_size, ImU32 seed) ImFileHandle ImFileOpen(const char* filename, const char* mode) { -#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__) +#if defined(_WIN32) // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. // Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32! const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);