diff options
author | Jean-Francois Mauguit <jfmauguit@mac.com> | 2024-09-24 09:03:25 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-24 09:03:25 -0400 |
commit | bab614c421ed7ae329d26bf028c4a3b1d2450f5a (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/mptrack/MIDIMacroDialog.cpp | |
parent | 4bde6044fddf053f31795b9eaccdd2a5a527d21f (diff) | |
parent | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (diff) | |
download | winamp-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.cpp | 503 |
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 |