aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/mptrack/MIDIMacroDialog.cpp
diff options
context:
space:
mode:
authorJean-Francois Mauguit <jfmauguit@mac.com>2024-09-24 09:03:25 -0400
committerGitHub <noreply@github.com>2024-09-24 09:03:25 -0400
commitbab614c421ed7ae329d26bf028c4a3b1d2450f5a (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/mptrack/MIDIMacroDialog.cpp
parent4bde6044fddf053f31795b9eaccdd2a5a527d21f (diff)
parent20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (diff)
downloadwinamp-bab614c421ed7ae329d26bf028c4a3b1d2450f5a.tar.gz
Merge pull request #5 from WinampDesktop/community
Merge to main
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/mptrack/MIDIMacroDialog.cpp')
-rw-r--r--Src/external_dependencies/openmpt-trunk/mptrack/MIDIMacroDialog.cpp503
1 files changed, 503 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/mptrack/MIDIMacroDialog.cpp b/Src/external_dependencies/openmpt-trunk/mptrack/MIDIMacroDialog.cpp
new file mode 100644
index 00000000..ef8bd8dc
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/mptrack/MIDIMacroDialog.cpp
@@ -0,0 +1,503 @@
+/*
+ * MIDIMacroDialog.cpp
+ * -------------------
+ * Purpose: MIDI Macro Configuration Dialog
+ * Notes : (currently none)
+ * Authors: OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "../mptrack/Reporting.h"
+#include "../common/mptStringBuffer.h"
+#include "Mainfrm.h"
+#include "Mptrack.h"
+#include "resource.h"
+#include "MIDIMacroDialog.h"
+#include "../soundlib/MIDIEvents.h"
+#include "../soundlib/plugins/PlugInterface.h"
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+BEGIN_MESSAGE_MAP(CMidiMacroSetup, CDialog)
+ ON_COMMAND(IDC_BUTTON1, &CMidiMacroSetup::OnSetAsDefault)
+ ON_COMMAND(IDC_BUTTON2, &CMidiMacroSetup::OnResetCfg)
+ ON_COMMAND(IDC_BUTTON3, &CMidiMacroSetup::OnMacroHelp)
+ ON_CBN_SELCHANGE(IDC_COMBO1, &CMidiMacroSetup::OnSFxChanged)
+ ON_CBN_SELCHANGE(IDC_COMBO2, &CMidiMacroSetup::OnSFxPresetChanged)
+ ON_CBN_SELCHANGE(IDC_COMBO3, &CMidiMacroSetup::OnZxxPresetChanged)
+ ON_CBN_SELCHANGE(IDC_COMBO4, &CMidiMacroSetup::UpdateZxxSelection)
+ ON_CBN_SELCHANGE(IDC_MACROPLUG, &CMidiMacroSetup::OnPlugChanged)
+ ON_CBN_SELCHANGE(IDC_MACROPARAM,&CMidiMacroSetup::OnPlugParamChanged)
+ ON_CBN_SELCHANGE(IDC_MACROCC, &CMidiMacroSetup::OnCCChanged)
+ ON_EN_CHANGE(IDC_EDIT1, &CMidiMacroSetup::OnSFxEditChanged)
+ ON_EN_CHANGE(IDC_EDIT2, &CMidiMacroSetup::OnZxxEditChanged)
+ ON_COMMAND_RANGE(ID_PLUGSELECT, ID_PLUGSELECT + kSFxMacros - 1, &CMidiMacroSetup::OnViewAllParams)
+ ON_COMMAND_RANGE(ID_PLUGSELECT + kSFxMacros, ID_PLUGSELECT + kSFxMacros + kSFxMacros - 1, &CMidiMacroSetup::OnSetSFx)
+END_MESSAGE_MAP()
+
+
+void CMidiMacroSetup::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ DDX_Control(pDX, IDC_COMBO1, m_CbnSFx);
+ DDX_Control(pDX, IDC_COMBO2, m_CbnSFxPreset);
+ DDX_Control(pDX, IDC_COMBO3, m_CbnZxxPreset);
+ DDX_Control(pDX, IDC_COMBO4, m_CbnZxx);
+ DDX_Control(pDX, IDC_EDIT1, m_EditSFx);
+ DDX_Control(pDX, IDC_EDIT2, m_EditZxx);
+ DDX_Control(pDX, IDC_MACROPLUG, m_CbnMacroPlug);
+ DDX_Control(pDX, IDC_MACROPARAM, m_CbnMacroParam);
+ DDX_Control(pDX, IDC_MACROCC, m_CbnMacroCC);
+}
+
+
+BOOL CMidiMacroSetup::OnInitDialog()
+{
+ CString s;
+ CDialog::OnInitDialog();
+ m_EditSFx.SetLimitText(kMacroLength - 1);
+ m_EditZxx.SetLimitText(kMacroLength - 1);
+
+ // Parametered macro selection
+ for(int i = 0; i < 16; i++)
+ {
+ s.Format(_T("%d (SF%X)"), i, i);
+ m_CbnSFx.AddString(s);
+ }
+
+ // Parametered macro presets
+ m_CbnSFx.SetCurSel(0);
+ for(int i = 0; i < kSFxMax; i++)
+ {
+ m_CbnSFxPreset.SetItemData(m_CbnSFxPreset.AddString(m_MidiCfg.GetParameteredMacroName(static_cast<ParameteredMacro>(i))), i);
+ }
+ OnSFxChanged();
+
+ // MIDI CC selection box
+ for (int cc = MIDIEvents::MIDICC_start; cc <= MIDIEvents::MIDICC_end; cc++)
+ {
+ s.Format(_T("CC %02d "), cc);
+ s += mpt::ToCString(mpt::Charset::UTF8, MIDIEvents::MidiCCNames[cc]);
+ m_CbnMacroCC.SetItemData(m_CbnMacroCC.AddString(s), cc);
+ }
+
+ // Z80...ZFF box
+ for(int zxx = 0x80; zxx <= 0xFF; zxx++)
+ {
+ s.Format(_T("Z%02X"), zxx);
+ m_CbnZxx.AddString(s);
+ }
+
+ // Fixed macro presets
+ m_CbnZxx.SetCurSel(0);
+ for(int i = 0; i < kZxxMax; i++)
+ {
+ m_CbnZxxPreset.SetItemData(m_CbnZxxPreset.AddString(m_MidiCfg.GetFixedMacroName(static_cast<FixedMacro>(i))), i);
+ }
+ m_CbnZxxPreset.SetCurSel(m_MidiCfg.GetFixedMacroType());
+
+ UpdateDialog();
+
+ auto ScalePixels = [&](auto x) { return Util::ScalePixels(x, m_hWnd); };
+ int offsetx = ScalePixels(19), offsety = ScalePixels(30), separatorx = ScalePixels(4), separatory = ScalePixels(2);
+ int height = ScalePixels(18), widthMacro = ScalePixels(30), widthVal = ScalePixels(179), widthType = ScalePixels(135), widthBtn = ScalePixels(70);
+
+ for(UINT m = 0; m < kSFxMacros; m++)
+ {
+ m_EditMacro[m].Create(_T(""), WS_CHILD | WS_VISIBLE | WS_TABSTOP,
+ CRect(offsetx, offsety + m * (separatory + height), offsetx + widthMacro, offsety + m * (separatory + height) + height), this, ID_PLUGSELECT + kSFxMacros + m);
+ m_EditMacro[m].SetFont(GetFont());
+
+ m_EditMacroType[m].Create(ES_READONLY | WS_CHILD| WS_VISIBLE | WS_TABSTOP | WS_BORDER,
+ CRect(offsetx + separatorx + widthMacro, offsety + m * (separatory + height), offsetx + widthMacro + widthType, offsety + m * (separatory + height) + height), this, ID_PLUGSELECT + kSFxMacros + m);
+ m_EditMacroType[m].SetFont(GetFont());
+
+ m_EditMacroValue[m].Create(ES_CENTER | ES_READONLY | WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_BORDER,
+ CRect(offsetx + separatorx + widthType + widthMacro, offsety + m * (separatory + height), offsetx + widthMacro + widthType + widthVal, offsety + m * (separatory + height) + height), this, ID_PLUGSELECT + kSFxMacros + m);
+ m_EditMacroValue[m].SetFont(GetFont());
+
+ m_BtnMacroShowAll[m].Create(_T("Show All..."), WS_CHILD | WS_TABSTOP | WS_VISIBLE,
+ CRect(offsetx + separatorx + widthType + widthMacro + widthVal, offsety + m * (separatory + height), offsetx + widthMacro + widthType + widthVal + widthBtn, offsety + m * (separatory + height) + height), this, ID_PLUGSELECT + m);
+ m_BtnMacroShowAll[m].SetFont(GetFont());
+ }
+ UpdateMacroList();
+
+#ifndef NO_PLUGINS
+ for(PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++)
+ {
+ const SNDMIXPLUGIN &plugin = m_SndFile.m_MixPlugins[i];
+
+ if(plugin.IsValidPlugin())
+ {
+ s.Format(_T("FX%d: "), i + 1);
+ s += mpt::ToCString(plugin.GetName());
+ m_CbnMacroPlug.SetItemData(m_CbnMacroPlug.AddString(s), i);
+ }
+ }
+ m_CbnMacroPlug.SetCurSel(0);
+ OnPlugChanged();
+#endif // NO_PLUGINS
+ return FALSE;
+}
+
+
+// macro == -1 for updating all macros at once
+void CMidiMacroSetup::UpdateMacroList(int macro)
+{
+ if(!m_EditMacro[0])
+ {
+ // GUI not yet initialized
+ return;
+ }
+
+ int start, end;
+
+ if(macro >= 0 && macro < kSFxMacros)
+ {
+ start = end = macro;
+ } else
+ {
+ start = 0;
+ end = kSFxMacros - 1;
+ }
+
+ CString s;
+ const int selectedMacro = m_CbnSFx.GetCurSel();
+
+ for(int m = start; m <= end; m++)
+ {
+ // SFx
+ s.Format(_T("SF%X"), static_cast<unsigned int>(m));
+ m_EditMacro[m].SetWindowText(s);
+
+ // Macro value:
+ m_EditMacroValue[m].SetWindowText(mpt::ToCString(mpt::Charset::ASCII, m_MidiCfg.SFx[m]));
+ m_EditMacroValue[m].SetBackColor(m == selectedMacro ? RGB(200, 200, 225) : RGB(245, 245, 245));
+
+ // Macro Type:
+ const ParameteredMacro macroType = m_MidiCfg.GetParameteredMacroType(m);
+ switch(macroType)
+ {
+ case kSFxPlugParam:
+ s.Format(_T("Control Plugin Param %u"), static_cast<unsigned int>(m_MidiCfg.MacroToPlugParam(m)));
+ break;
+
+ default:
+ s = m_MidiCfg.GetParameteredMacroName(m);
+ break;
+ }
+ m_EditMacroType[m].SetWindowText(s);
+ m_EditMacroType[m].SetBackColor(m == selectedMacro ? RGB(200,200,225) : RGB(245,245,245));
+
+ // Param details button:
+ m_BtnMacroShowAll[m].ShowWindow((macroType == kSFxPlugParam) ? SW_SHOW : SW_HIDE);
+ }
+}
+
+
+void CMidiMacroSetup::UpdateDialog()
+{
+ UINT sfx = m_CbnSFx.GetCurSel();
+ UINT sfx_preset = static_cast<UINT>(m_CbnSFxPreset.GetItemData(m_CbnSFxPreset.GetCurSel()));
+ if(sfx < m_MidiCfg.SFx.size())
+ {
+ ToggleBoxes(sfx_preset, sfx);
+ m_EditSFx.SetWindowText(mpt::ToCString(mpt::Charset::ASCII, m_MidiCfg.SFx[sfx]));
+ }
+
+ UpdateZxxSelection();
+ UpdateMacroList();
+}
+
+
+void CMidiMacroSetup::OnSetAsDefault()
+{
+ theApp.SetDefaultMidiMacro(m_MidiCfg);
+}
+
+
+void CMidiMacroSetup::OnResetCfg()
+{
+ theApp.GetDefaultMidiMacro(m_MidiCfg);
+ m_CbnZxxPreset.SetCurSel(0);
+ OnSFxChanged();
+}
+
+
+void CMidiMacroSetup::OnMacroHelp()
+{
+ Reporting::Information(_T("Valid characters in macros:\n\n"
+ "0-9, A-F - Raw hex data (4-Bit value)\n"
+ "c - MIDI channel (4-Bit value)\n"
+ "n - Note value\n\n"
+ "v - Note velocity\n"
+ "u - Computed note volume (including envelopes)\n\n"
+ "x - Note panning\n"
+ "y - Computed panning (including envelopes)\n\n"
+ "a - High byte of bank select\n"
+ "b - Low byte of bank select\n"
+ "p - Program select\n\n"
+ "h - Pattern channel\n"
+ "m - Sample loop direction\n"
+ "o - Last sample offset (Oxx / 9xx)\n"
+ "s - SysEx checksum (Roland)\n\n"
+ "z - Zxx parameter (00-7F)\n\n"
+ "Macros can be up to 31 characters long and contain multiple MIDI messages. SysEx messages are automatically terminated if not specified by the user."),
+ _T("OpenMPT MIDI Macro quick reference"));
+}
+
+
+void CMidiMacroSetup::OnSFxChanged()
+{
+ UINT sfx = m_CbnSFx.GetCurSel();
+ if (sfx < 16)
+ {
+ int preset = m_MidiCfg.GetParameteredMacroType(sfx);
+ m_CbnSFxPreset.SetCurSel(preset);
+ }
+ UpdateDialog();
+}
+
+
+void CMidiMacroSetup::OnSFxPresetChanged()
+{
+ UINT sfx = m_CbnSFx.GetCurSel();
+ ParameteredMacro sfx_preset = static_cast<ParameteredMacro>(m_CbnSFxPreset.GetItemData(m_CbnSFxPreset.GetCurSel()));
+
+ if (sfx < kSFxMacros)
+ {
+ if(sfx_preset != kSFxCustom)
+ {
+ m_MidiCfg.CreateParameteredMacro(sfx, sfx_preset);
+ }
+ UpdateDialog();
+ }
+}
+
+
+void CMidiMacroSetup::OnZxxPresetChanged()
+{
+ FixedMacro zxxPreset = static_cast<FixedMacro>(m_CbnZxxPreset.GetItemData(m_CbnZxxPreset.GetCurSel()));
+
+ if (zxxPreset != kZxxCustom)
+ {
+ m_MidiCfg.CreateFixedMacro(zxxPreset);
+ UpdateDialog();
+ }
+}
+
+
+void CMidiMacroSetup::UpdateZxxSelection()
+{
+ UINT zxx = m_CbnZxx.GetCurSel();
+ if(zxx < m_MidiCfg.Zxx.size())
+ {
+ m_EditZxx.SetWindowText(mpt::ToCString(mpt::Charset::ASCII, m_MidiCfg.Zxx[zxx]));
+ }
+}
+
+
+void CMidiMacroSetup::OnSFxEditChanged()
+{
+ UINT sfx = m_CbnSFx.GetCurSel();
+ if(sfx < m_MidiCfg.SFx.size())
+ {
+ if(ValidateMacroString(m_EditSFx, m_MidiCfg.SFx[sfx], true))
+ {
+ CString s;
+ m_EditSFx.GetWindowText(s);
+ m_MidiCfg.SFx[sfx] = mpt::ToCharset(mpt::Charset::ASCII, s);
+
+ int sfx_preset = m_MidiCfg.GetParameteredMacroType(sfx);
+ m_CbnSFxPreset.SetCurSel(sfx_preset);
+ ToggleBoxes(sfx_preset, sfx);
+ UpdateMacroList(sfx);
+ }
+ }
+}
+
+
+void CMidiMacroSetup::OnZxxEditChanged()
+{
+ UINT zxx = m_CbnZxx.GetCurSel();
+ if(zxx < m_MidiCfg.Zxx.size())
+ {
+ if(ValidateMacroString(m_EditZxx, m_MidiCfg.Zxx[zxx], false))
+ {
+ CString s;
+ m_EditZxx.GetWindowText(s);
+ m_MidiCfg.Zxx[zxx] = mpt::ToCharset(mpt::Charset::ASCII, s);
+ m_CbnZxxPreset.SetCurSel(m_MidiCfg.GetFixedMacroType());
+ }
+ }
+}
+
+void CMidiMacroSetup::OnSetSFx(UINT id)
+{
+ m_CbnSFx.SetCurSel(id - (ID_PLUGSELECT + kSFxMacros));
+ OnSFxChanged();
+}
+
+void CMidiMacroSetup::OnViewAllParams(UINT id)
+{
+#ifndef NO_PLUGINS
+ CString message, plugName;
+ int sfx = id - ID_PLUGSELECT;
+ PlugParamIndex param = m_MidiCfg.MacroToPlugParam(sfx);
+ message.Format(_T("These are the parameters that can be controlled by macro SF%X:\n\n"), sfx);
+
+ for(PLUGINDEX plug = 0; plug < MAX_MIXPLUGINS; plug++)
+ {
+ IMixPlugin *pVstPlugin = m_SndFile.m_MixPlugins[plug].pMixPlugin;
+ if(pVstPlugin && param < pVstPlugin->GetNumParameters())
+ {
+ plugName = mpt::ToCString(m_SndFile.m_MixPlugins[plug].GetName());
+ message.AppendFormat(_T("FX%d: "), plug + 1);
+ message += plugName + _T("\t") + pVstPlugin->GetFormattedParamName(param) + _T("\n");
+ }
+ }
+
+ Reporting::Notification(message, _T("Macro -> Parameters"));
+#endif // NO_PLUGINS
+}
+
+void CMidiMacroSetup::OnPlugChanged()
+{
+#ifndef NO_PLUGINS
+ DWORD_PTR plug = m_CbnMacroPlug.GetItemData(m_CbnMacroPlug.GetCurSel());
+
+ if(plug >= MAX_MIXPLUGINS)
+ return;
+
+ IMixPlugin *pVstPlugin = m_SndFile.m_MixPlugins[plug].pMixPlugin;
+ if (pVstPlugin != nullptr)
+ {
+ m_CbnMacroParam.SetRedraw(FALSE);
+ m_CbnMacroParam.Clear();
+ m_CbnMacroParam.ResetContent();
+ AddPluginParameternamesToCombobox(m_CbnMacroParam, *pVstPlugin);
+ m_CbnMacroParam.SetRedraw(TRUE);
+
+ int param = m_MidiCfg.MacroToPlugParam(m_CbnSFx.GetCurSel());
+ m_CbnMacroParam.SetCurSel(param);
+ }
+#endif // NO_PLUGINS
+}
+
+void CMidiMacroSetup::OnPlugParamChanged()
+{
+ int param = static_cast<int>(m_CbnMacroParam.GetItemData(m_CbnMacroParam.GetCurSel()));
+
+ if(param < 384)
+ {
+ const std::string macroText = m_MidiCfg.CreateParameteredMacro(kSFxPlugParam, param);
+ m_EditSFx.SetWindowText(mpt::ToCString(mpt::Charset::ASCII, macroText));
+ } else
+ {
+ Reporting::Notification("Only parameters 0 to 383 can be controlled using MIDI Macros. Use Parameter Control Events to automate higher parameters.");
+ }
+}
+
+void CMidiMacroSetup::OnCCChanged()
+{
+ int cc = static_cast<int>(m_CbnMacroCC.GetItemData(m_CbnMacroCC.GetCurSel()));
+ const std::string macroText = m_MidiCfg.CreateParameteredMacro(kSFxCC, cc);
+ m_EditSFx.SetWindowText(mpt::ToCString(mpt::Charset::ASCII, macroText));
+}
+
+void CMidiMacroSetup::ToggleBoxes(UINT sfxPreset, UINT sfx)
+{
+
+ if (sfxPreset == kSFxPlugParam)
+ {
+ m_CbnMacroCC.ShowWindow(FALSE);
+ m_CbnMacroPlug.ShowWindow(TRUE);
+ m_CbnMacroParam.ShowWindow(TRUE);
+ m_CbnMacroPlug.EnableWindow(TRUE);
+ m_CbnMacroParam.EnableWindow(TRUE);
+ SetDlgItemText(IDC_GENMACROLABEL, _T("Plugin/Param"));
+ m_CbnMacroParam.SetCurSel(m_MidiCfg.MacroToPlugParam(sfx));
+ } else
+ {
+ m_CbnMacroPlug.EnableWindow(FALSE);
+ m_CbnMacroParam.EnableWindow(FALSE);
+ }
+
+ if (sfxPreset == kSFxCC)
+ {
+ m_CbnMacroCC.EnableWindow(TRUE);
+ m_CbnMacroCC.ShowWindow(TRUE);
+ m_CbnMacroPlug.ShowWindow(FALSE);
+ m_CbnMacroParam.ShowWindow(FALSE);
+ SetDlgItemText(IDC_GENMACROLABEL, _T("MIDI CC"));
+ m_CbnMacroCC.SetCurSel(m_MidiCfg.MacroToMidiCC(sfx));
+ } else
+ {
+ m_CbnMacroCC.EnableWindow(FALSE);
+ }
+}
+
+
+bool CMidiMacroSetup::ValidateMacroString(CEdit &wnd, const MIDIMacroConfig::Macro &prevMacro, bool isParametric)
+{
+ CString macroStrT;
+ wnd.GetWindowText(macroStrT);
+ std::string macroStr = mpt::ToCharset(mpt::Charset::ASCII, macroStrT);
+
+ bool allowed = true, caseChange = false;
+ for(char &c : macroStr)
+ {
+ if(c == 'k' || c == 'K') // Previously, 'K' was used for MIDI channel
+ {
+ caseChange = true;
+ c = 'c';
+ } else if(c >= 'd' && c <= 'f') // abc have special meanings, but def can be fixed
+ {
+ caseChange = true;
+ c = c - 'a' + 'A';
+ } else if(c == 'M' || c == 'N' || c == 'O' || c == 'P' || c == 'S' || c == 'U' || c == 'V' || c == 'X' || c == 'Y' || c == 'Z')
+ {
+ caseChange = true;
+ c = c - 'A' + 'a';
+ } else if(!(
+ (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'c') ||
+ (c == 'h' || c == 'm' || c == 'n' || c == 'o' || c == 'p' || c == 's' ||c == 'u' || c == 'v' || c == 'x' || c == 'y' || c == ' ') ||
+ (c == 'z' && isParametric)))
+ {
+ allowed = false;
+ break;
+ }
+ }
+
+ if(!allowed)
+ {
+ // Replace text and keep cursor position if we just typed in an invalid character
+ if(prevMacro != std::string_view{macroStr})
+ {
+ int start, end;
+ wnd.GetSel(start, end);
+ wnd.SetWindowText(mpt::ToCString(mpt::Charset::ASCII, prevMacro));
+ wnd.SetSel(start - 1, end - 1, true);
+ MessageBeep(MB_OK);
+ }
+ return false;
+ } else
+ {
+ if(caseChange)
+ {
+ // Replace text and keep cursor position if there was a case conversion
+ int start, end;
+ wnd.GetSel(start, end);
+ wnd.SetWindowText(mpt::ToCString(mpt::Charset::ASCII, macroStr));
+ wnd.SetSel(start, end, true);
+ }
+ return true;
+ }
+}
+
+
+OPENMPT_NAMESPACE_END