123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868 |
- /*
- * SelectPluginDialog.cpp
- * ----------------------
- * Purpose: Dialog for adding plugins to a song.
- * Notes : (currently none)
- * Authors: Olivier Lapicque
- * OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
- #include "stdafx.h"
- #ifndef NO_PLUGINS
- #include "Mptrack.h"
- #include "Mainfrm.h"
- #include "InputHandler.h"
- #include "ImageLists.h"
- #include "Moddoc.h"
- #include "../common/mptStringBuffer.h"
- #include "FileDialog.h"
- #include "../soundlib/plugins/PluginManager.h"
- #include "../soundlib/plugins/PlugInterface.h"
- #include "SelectPluginDialog.h"
- #include "../pluginBridge/BridgeWrapper.h"
- #include "FolderScanner.h"
- OPENMPT_NAMESPACE_BEGIN
- /////////////////////////////////////////////////////////////////////////////////
- // Plugin selection dialog
- BEGIN_MESSAGE_MAP(CSelectPluginDlg, ResizableDialog)
- ON_NOTIFY(TVN_SELCHANGED, IDC_TREE1, &CSelectPluginDlg::OnSelChanged)
- ON_NOTIFY(NM_DBLCLK, IDC_TREE1, &CSelectPluginDlg::OnSelDblClk)
- ON_COMMAND(IDC_BUTTON1, &CSelectPluginDlg::OnAddPlugin)
- ON_COMMAND(IDC_BUTTON3, &CSelectPluginDlg::OnScanFolder)
- ON_COMMAND(IDC_BUTTON2, &CSelectPluginDlg::OnRemovePlugin)
- ON_COMMAND(IDC_CHECK1, &CSelectPluginDlg::OnSetBridge)
- ON_COMMAND(IDC_CHECK2, &CSelectPluginDlg::OnSetBridge)
- ON_COMMAND(IDC_CHECK3, &CSelectPluginDlg::OnSetBridge)
- ON_EN_CHANGE(IDC_NAMEFILTER, &CSelectPluginDlg::OnNameFilterChanged)
- ON_EN_CHANGE(IDC_PLUGINTAGS, &CSelectPluginDlg::OnPluginTagsChanged)
- END_MESSAGE_MAP()
- void CSelectPluginDlg::DoDataExchange(CDataExchange* pDX)
- {
- ResizableDialog::DoDataExchange(pDX);
- DDX_Control(pDX, IDC_TREE1, m_treePlugins);
- DDX_Control(pDX, IDC_CHECK1, m_chkBridge);
- DDX_Control(pDX, IDC_CHECK2, m_chkShare);
- DDX_Control(pDX, IDC_CHECK3, m_chkLegacyBridge);
- }
- CSelectPluginDlg::CSelectPluginDlg(CModDoc *pModDoc, PLUGINDEX pluginSlot, CWnd *parent)
- : ResizableDialog(IDD_SELECTMIXPLUGIN, parent)
- , m_pModDoc(pModDoc)
- , m_nPlugSlot(pluginSlot)
- {
- if(m_pModDoc && 0 <= m_nPlugSlot && m_nPlugSlot < MAX_MIXPLUGINS)
- {
- m_pPlugin = &(pModDoc->GetSoundFile().m_MixPlugins[m_nPlugSlot]);
- }
- CMainFrame::GetInputHandler()->Bypass(true);
- }
- CSelectPluginDlg::~CSelectPluginDlg()
- {
- CMainFrame::GetInputHandler()->Bypass(false);
- }
- BOOL CSelectPluginDlg::OnInitDialog()
- {
- DWORD dwRemove = TVS_EDITLABELS|TVS_SINGLEEXPAND;
- DWORD dwAdd = TVS_HASLINES | TVS_LINESATROOT | TVS_HASBUTTONS | TVS_SHOWSELALWAYS;
- ResizableDialog::OnInitDialog();
- m_treePlugins.ModifyStyle(dwRemove, dwAdd);
- m_treePlugins.SetImageList(&CMainFrame::GetMainFrame()->m_MiscIcons, TVSIL_NORMAL);
- if (m_pPlugin)
- {
- CString targetSlot = MPT_CFORMAT("&Put in FX{}")(mpt::cfmt::dec0<2>(m_nPlugSlot + 1));
- SetDlgItemText(IDOK, targetSlot);
- ::EnableWindow(::GetDlgItem(m_hWnd, IDOK), TRUE);
- } else
- {
- ::EnableWindow(::GetDlgItem(m_hWnd, IDOK), FALSE);
- }
- const int dpiX = Util::GetDPIx(m_hWnd);
- const int dpiY = Util::GetDPIy(m_hWnd);
- CRect rect
- (
- CPoint(MulDiv(TrackerSettings::Instance().gnPlugWindowX, dpiX, 96), MulDiv(TrackerSettings::Instance().gnPlugWindowY, dpiY, 96)),
- CSize(MulDiv(TrackerSettings::Instance().gnPlugWindowWidth, dpiX, 96), MulDiv(TrackerSettings::Instance().gnPlugWindowHeight, dpiY, 96))
- );
- ::MapWindowPoints(GetParent()->m_hWnd, HWND_DESKTOP, (CPoint *)&rect, 2);
- WINDOWPLACEMENT wnd;
- wnd.length = sizeof(wnd);
- GetWindowPlacement(&wnd);
- wnd.showCmd = SW_SHOW;
- wnd.rcNormalPosition = rect;
- SetWindowPlacement(&wnd);
- UpdatePluginsList();
- OnSelChanged(NULL, NULL);
- return TRUE;
- }
- void CSelectPluginDlg::OnOK()
- {
- if(m_pPlugin == nullptr)
- {
- ResizableDialog::OnOK();
- return;
- }
- bool changed = false;
- CVstPluginManager *pManager = theApp.GetPluginManager();
- VSTPluginLib *pNewPlug = GetSelectedPlugin();
- VSTPluginLib *pFactory = nullptr;
- IMixPlugin *pCurrentPlugin = nullptr;
- if(m_pPlugin)
- pCurrentPlugin = m_pPlugin->pMixPlugin;
- if((pManager) && (pManager->IsValidPlugin(pNewPlug)))
- pFactory = pNewPlug;
- if (pFactory)
- {
- // Plugin selected
- if ((!pCurrentPlugin) || &pCurrentPlugin->GetPluginFactory() != pFactory)
- {
- CriticalSection cs;
- // Destroy old plugin, if there was one.
- const auto oldOutput = m_pPlugin->GetOutputPlugin();
- m_pPlugin->Destroy();
- // Initialize plugin info
- MemsetZero(m_pPlugin->Info);
- if(oldOutput != PLUGINDEX_INVALID)
- m_pPlugin->SetOutputPlugin(oldOutput);
- m_pPlugin->Info.dwPluginId1 = pFactory->pluginId1;
- m_pPlugin->Info.dwPluginId2 = pFactory->pluginId2;
- m_pPlugin->editorX = m_pPlugin->editorY = int32_min;
- m_pPlugin->SetAutoSuspend(TrackerSettings::Instance().enableAutoSuspend);
- #ifdef MPT_WITH_VST
- if(m_pPlugin->Info.dwPluginId1 == Vst::kEffectMagic)
- {
- switch(m_pPlugin->Info.dwPluginId2)
- {
- // Enable drymix by default for these known plugins
- case Vst::FourCC("Scop"):
- m_pPlugin->SetWetMix();
- break;
- }
- }
- #endif // MPT_WITH_VST
- m_pPlugin->Info.szName = pFactory->libraryName.ToLocale();
- m_pPlugin->Info.szLibraryName = pFactory->libraryName.ToUTF8();
- cs.Leave();
- // Now, create the new plugin
- if(pManager && m_pModDoc)
- {
- pManager->CreateMixPlugin(*m_pPlugin, m_pModDoc->GetSoundFile());
- if (m_pPlugin->pMixPlugin)
- {
- IMixPlugin *p = m_pPlugin->pMixPlugin;
- const CString name = p->GetDefaultEffectName();
- if(!name.IsEmpty())
- {
- m_pPlugin->Info.szName = mpt::ToCharset(mpt::Charset::Locale, name);
- }
- // Check if plugin slot is already assigned to any instrument, and if not, create one.
- if(p->IsInstrument() && m_pModDoc->HasInstrumentForPlugin(m_nPlugSlot) == INSTRUMENTINDEX_INVALID)
- {
- m_pModDoc->InsertInstrumentForPlugin(m_nPlugSlot);
- }
- } else
- {
- MemsetZero(m_pPlugin->Info);
- }
- }
- changed = true;
- }
- } else if(m_pPlugin->IsValidPlugin())
- {
- // No effect
- if(m_pModDoc)
- changed = m_pModDoc->RemovePlugin(m_nPlugSlot);
- }
- //remember window size:
- SaveWindowPos();
- if(changed)
- {
- if(m_pPlugin->Info.dwPluginId2)
- TrackerSettings::Instance().gnPlugWindowLast = m_pPlugin->Info.dwPluginId2;
- if(m_pModDoc)
- {
- m_pModDoc->UpdateAllViews(nullptr, PluginHint(static_cast<PLUGINDEX>(m_nPlugSlot + 1)).Info().Names());
- }
- ResizableDialog::OnOK();
- } else
- {
- ResizableDialog::OnCancel();
- }
- }
- void CSelectPluginDlg::OnCancel()
- {
- //remember window size:
- SaveWindowPos();
- ResizableDialog::OnCancel();
- }
- VSTPluginLib* CSelectPluginDlg::GetSelectedPlugin()
- {
- HTREEITEM item = m_treePlugins.GetSelectedItem();
- if(item)
- return reinterpret_cast<VSTPluginLib *>(m_treePlugins.GetItemData(item));
- else
- return nullptr;
- }
- void CSelectPluginDlg::SaveWindowPos() const
- {
- WINDOWPLACEMENT wnd;
- wnd.length = sizeof(WINDOWPLACEMENT);
- GetWindowPlacement(&wnd);
- CRect rect = wnd.rcNormalPosition;
- ::MapWindowPoints(HWND_DESKTOP, GetParent()->m_hWnd, (CPoint *)&rect, 2);
- const int dpiX = Util::GetDPIx(m_hWnd);
- const int dpiY = Util::GetDPIy(m_hWnd);
- TrackerSettings::Instance().gnPlugWindowX = MulDiv(rect.left, 96, dpiX);
- TrackerSettings::Instance().gnPlugWindowY = MulDiv(rect.top, 96, dpiY);
- TrackerSettings::Instance().gnPlugWindowWidth = MulDiv(rect.Width(), 96, dpiY);
- TrackerSettings::Instance().gnPlugWindowHeight = MulDiv(rect.Height(), 96, dpiX);
- }
- BOOL CSelectPluginDlg::PreTranslateMessage(MSG *pMsg)
- {
- // Use up/down keys to navigate in tree view, even if search field is focussed.
- if(pMsg != nullptr && pMsg->message == WM_KEYDOWN && (pMsg->wParam == VK_UP || pMsg->wParam == VK_DOWN) && GetFocus() != &m_treePlugins)
- {
- HTREEITEM selItem = m_treePlugins.GetSelectedItem();
- if(selItem == nullptr)
- {
- selItem = m_treePlugins.GetRootItem();
- }
- while((selItem = m_treePlugins.GetNextItem(selItem, pMsg->wParam == VK_UP ? TVGN_PREVIOUSVISIBLE : TVGN_NEXTVISIBLE)) != nullptr)
- {
- int nImage, nSelectedImage;
- m_treePlugins.GetItemImage(selItem, nImage, nSelectedImage);
- if(nImage != IMAGE_FOLDER)
- {
- m_treePlugins.SelectItem(selItem);
- m_treePlugins.EnsureVisible(selItem);
- return TRUE;
- }
- }
- return TRUE;
- }
- return ResizableDialog::PreTranslateMessage(pMsg);
- }
- void CSelectPluginDlg::OnNameFilterChanged()
- {
- // Update name filter text
- m_nameFilter = mpt::ToLowerCase(GetWindowTextUnicode(*GetDlgItem(IDC_NAMEFILTER)));
- UpdatePluginsList();
- }
- void CSelectPluginDlg::UpdatePluginsList(const VSTPluginLib *forceSelect)
- {
- CVstPluginManager *pManager = theApp.GetPluginManager();
- m_treePlugins.SetRedraw(FALSE);
- m_treePlugins.DeleteAllItems();
- static constexpr struct
- {
- VSTPluginLib::PluginCategory category;
- const TCHAR *description;
- } categories[] =
- {
- { VSTPluginLib::catEffect, _T("Audio Effects") },
- { VSTPluginLib::catGenerator, _T("Tone Generators") },
- { VSTPluginLib::catRestoration, _T("Audio Restauration") },
- { VSTPluginLib::catSurroundFx, _T("Surround Effects") },
- { VSTPluginLib::catRoomFx, _T("Room Effects") },
- { VSTPluginLib::catSpacializer, _T("Spacializers") },
- { VSTPluginLib::catMastering, _T("Mastering Plugins") },
- { VSTPluginLib::catAnalysis, _T("Analysis Plugins") },
- { VSTPluginLib::catOfflineProcess, _T("Offline Processing") },
- { VSTPluginLib::catShell, _T("Shell Plugins") },
- { VSTPluginLib::catUnknown, _T("Unsorted") },
- { VSTPluginLib::catDMO, _T("DirectX Media Audio Effects") },
- { VSTPluginLib::catSynth, _T("Instrument Plugins") },
- { VSTPluginLib::catHidden, _T("Legacy Plugins") },
- };
- const HTREEITEM noPlug = AddTreeItem(_T("No plugin (empty slot)"), IMAGE_NOPLUGIN, false);
- HTREEITEM currentPlug = noPlug;
- std::bitset<VSTPluginLib::numCategories> categoryUsed;
- HTREEITEM categoryFolders[VSTPluginLib::numCategories];
- for(const auto &cat : categories)
- {
- categoryFolders[cat.category] = AddTreeItem(cat.description, IMAGE_FOLDER, false);
- }
- enum PlugMatchQuality
- {
- kNoMatch,
- kSameIdAsLast,
- kSameIdAsLastWithPlatformMatch,
- kSameIdAsCurrent,
- kFoundCurrentPlugin,
- };
- PlugMatchQuality foundPlugin = kNoMatch;
- const int32 lastPluginID = TrackerSettings::Instance().gnPlugWindowLast;
- const bool nameFilterActive = !m_nameFilter.empty();
- const auto currentTags = mpt::String::Split<mpt::ustring>(m_nameFilter, U_(" "));
- if(pManager)
- {
- bool first = true;
- for(auto p : *pManager)
- {
- MPT_ASSERT(p);
- const VSTPluginLib &plug = *p;
- if(plug.category == VSTPluginLib::catHidden && (m_pPlugin == nullptr || m_pPlugin->pMixPlugin == nullptr || &m_pPlugin->pMixPlugin->GetPluginFactory() != p))
- continue;
- if(nameFilterActive)
- {
- // Apply name filter
- bool matches = false;
- // Search in plugin names
- {
- mpt::ustring displayName = mpt::ToLowerCase(plug.libraryName.ToUnicode());
- if(displayName.find(m_nameFilter, 0) != displayName.npos)
- {
- matches = true;
- }
- }
- // Search in plugin tags
- if(!matches)
- {
- mpt::ustring tags = mpt::ToLowerCase(plug.tags);
- for(const auto &tag : currentTags)
- {
- if(!tag.empty() && tags.find(tag, 0) != tags.npos)
- {
- matches = true;
- break;
- }
- }
- }
- // Search in plugin vendors
- if(!matches)
- {
- mpt::ustring vendor = mpt::ToLowerCase(mpt::ToUnicode(plug.vendor));
- if(vendor.find(m_nameFilter, 0) != vendor.npos)
- {
- matches = true;
- }
- }
- if(!matches) continue;
- }
- CString title = plug.libraryName.ToCString();
- #ifdef MPT_WITH_VST
- if(!plug.IsNativeFromCache())
- {
- title += MPT_CFORMAT(" ({})")(plug.GetDllArchNameUser());
- }
- #endif // MPT_WITH_VST
- HTREEITEM h = AddTreeItem(title, plug.isInstrument ? IMAGE_PLUGININSTRUMENT : IMAGE_EFFECTPLUGIN, true, categoryFolders[plug.category], reinterpret_cast<LPARAM>(&plug));
- categoryUsed[plug.category] = true;
- if(nameFilterActive)
- {
- // If filter is active, expand nodes.
- m_treePlugins.EnsureVisible(h);
- if(first)
- {
- first = false;
- m_treePlugins.SelectItem(h);
- }
- }
- if(forceSelect != nullptr && &plug == forceSelect)
- {
- // Forced selection (e.g. just after add plugin)
- currentPlug = h;
- foundPlugin = kFoundCurrentPlugin;
- }
- if(m_pPlugin && foundPlugin < kFoundCurrentPlugin)
- {
- //Which plugin should be selected?
- if(m_pPlugin->pMixPlugin)
- {
- // Current slot's plugin
- IMixPlugin *pPlugin = m_pPlugin->pMixPlugin;
- if (&pPlugin->GetPluginFactory() == &plug)
- {
- currentPlug = h;
- foundPlugin = kFoundCurrentPlugin;
- }
- } else if(m_pPlugin->Info.dwPluginId1 != 0 || m_pPlugin->Info.dwPluginId2 != 0)
- {
- // Plugin with matching ID to current slot's plug
- if(plug.pluginId1 == m_pPlugin->Info.dwPluginId1
- && plug.pluginId2 == m_pPlugin->Info.dwPluginId2)
- {
- currentPlug = h;
- foundPlugin = kSameIdAsCurrent;
- }
- } else if(plug.pluginId2 == lastPluginID && foundPlugin < kSameIdAsLastWithPlatformMatch)
- {
- // Previously selected plugin
- #ifdef MPT_WITH_VST
- foundPlugin = plug.IsNativeFromCache() ? kSameIdAsLastWithPlatformMatch : kSameIdAsLast;
- #else // !MPT_WITH_VST
- foundPlugin = kSameIdAsLastWithPlatformMatch;
- #endif // MPT_WITH_VST
- currentPlug = h;
- }
- }
- }
- }
- // Remove empty categories
- for(size_t i = 0; i < std::size(categoryFolders); i++)
- {
- if(!categoryUsed[i])
- {
- m_treePlugins.DeleteItem(categoryFolders[i]);
- }
- }
- m_treePlugins.SetRedraw(TRUE);
- if(!nameFilterActive || currentPlug != noPlug)
- {
- m_treePlugins.SelectItem(currentPlug);
- }
- m_treePlugins.SetItemState(currentPlug, TVIS_BOLD, TVIS_BOLD);
- m_treePlugins.EnsureVisible(currentPlug);
- }
- HTREEITEM CSelectPluginDlg::AddTreeItem(const TCHAR *title, int image, bool sort, HTREEITEM hParent, LPARAM lParam)
- {
- return m_treePlugins.InsertItem(
- TVIF_IMAGE | TVIF_SELECTEDIMAGE | TVIF_PARAM | TVIF_TEXT,
- title,
- image, image,
- 0, 0,
- lParam,
- hParent,
- (sort ? TVI_SORT : TVI_LAST));
- }
- void CSelectPluginDlg::OnSelDblClk(NMHDR *, LRESULT *result)
- {
- if(m_pPlugin == nullptr) return;
- HTREEITEM hSel = m_treePlugins.GetSelectedItem();
- int nImage, nSelectedImage;
- m_treePlugins.GetItemImage(hSel, nImage, nSelectedImage);
- if ((hSel) && (nImage != IMAGE_FOLDER)) OnOK();
- if (result) *result = 0;
- }
- void CSelectPluginDlg::OnSelChanged(NMHDR *, LRESULT *result)
- {
- CVstPluginManager *pManager = theApp.GetPluginManager();
- VSTPluginLib *pPlug = GetSelectedPlugin();
- bool showBoxes = false;
- BOOL enableTagsTextBox = FALSE;
- BOOL enableRemoveButton = FALSE;
- if (pManager != nullptr && pManager->IsValidPlugin(pPlug))
- {
- if(pPlug->vendor.IsEmpty())
- SetDlgItemText(IDC_VENDOR, _T(""));
- else
- SetDlgItemText(IDC_VENDOR, _T("Vendor: ") + pPlug->vendor);
- if(pPlug->dllPath.empty())
- SetDlgItemText(IDC_TEXT_CURRENT_VSTPLUG, _T("Built-in plugin"));
- else
- SetDlgItemText(IDC_TEXT_CURRENT_VSTPLUG, pPlug->dllPath.ToCString());
- SetDlgItemText(IDC_PLUGINTAGS, mpt::ToCString(pPlug->tags));
- enableRemoveButton = pPlug->isBuiltIn ? FALSE : TRUE;
- #ifdef MPT_WITH_VST
- if(pPlug->pluginId1 == Vst::kEffectMagic && !pPlug->isBuiltIn)
- {
- bool isBridgeAvailable =
- ((pPlug->GetDllArch() == PluginArch_x86) && IsComponentAvailable(pluginBridge_x86))
- ||
- ((pPlug->GetDllArch() == PluginArch_x86) && IsComponentAvailable(pluginBridgeLegacy_x86))
- ||
- ((pPlug->GetDllArch() == PluginArch_amd64) && IsComponentAvailable(pluginBridge_amd64))
- ||
- ((pPlug->GetDllArch() == PluginArch_amd64) && IsComponentAvailable(pluginBridgeLegacy_amd64))
- #if defined(MPT_WITH_WINDOWS10)
- ||
- ((pPlug->GetDllArch() == PluginArch_arm) && IsComponentAvailable(pluginBridge_arm))
- ||
- ((pPlug->GetDllArch() == PluginArch_arm) && IsComponentAvailable(pluginBridgeLegacy_arm))
- ||
- ((pPlug->GetDllArch() == PluginArch_arm64) && IsComponentAvailable(pluginBridge_arm64))
- ||
- ((pPlug->GetDllArch() == PluginArch_arm64) && IsComponentAvailable(pluginBridgeLegacy_arm64))
- #endif // MPT_WITH_WINDOWS10
- ;
- if(TrackerSettings::Instance().bridgeAllPlugins || !isBridgeAvailable)
- {
- m_chkBridge.EnableWindow(FALSE);
- m_chkBridge.SetCheck(isBridgeAvailable ? BST_CHECKED : BST_UNCHECKED);
- } else
- {
- bool native = pPlug->IsNative();
- m_chkBridge.EnableWindow(native ? TRUE : FALSE);
- m_chkBridge.SetCheck((pPlug->useBridge || !native) ? BST_CHECKED : BST_UNCHECKED);
- }
- m_chkShare.SetCheck(pPlug->shareBridgeInstance ? BST_CHECKED : BST_UNCHECKED);
- m_chkShare.EnableWindow(m_chkBridge.GetCheck() != BST_UNCHECKED);
- m_chkLegacyBridge.SetCheck((!pPlug->modernBridge) ? BST_CHECKED : BST_UNCHECKED);
- m_chkLegacyBridge.EnableWindow(m_chkBridge.GetCheck() != BST_UNCHECKED);
- showBoxes = true;
- }
- enableTagsTextBox = TRUE;
- #endif // MPT_WITH_VST
- } else
- {
- SetDlgItemText(IDC_VENDOR, _T(""));
- SetDlgItemText(IDC_TEXT_CURRENT_VSTPLUG, _T(""));
- SetDlgItemText(IDC_PLUGINTAGS, _T(""));
- }
- GetDlgItem(IDC_PLUGINTAGS)->EnableWindow(enableTagsTextBox);
- GetDlgItem(IDC_BUTTON2)->EnableWindow(enableRemoveButton);
- if(!showBoxes)
- {
- m_chkBridge.EnableWindow(FALSE);
- m_chkShare.EnableWindow(FALSE);
- m_chkLegacyBridge.EnableWindow(FALSE);
- m_chkBridge.SetCheck(BST_UNCHECKED);
- m_chkShare.SetCheck(BST_UNCHECKED);
- m_chkLegacyBridge.SetCheck(BST_UNCHECKED);
- }
- if (result) *result = 0;
- }
- #ifdef MPT_WITH_VST
- namespace
- {
- // TODO: Keep these lists up-to-date.
- constexpr struct
- {
- int32 id1;
- int32 id2;
- const char *name;
- const char *problem;
- } ProblematicPlugins[] =
- {
- {Vst::kEffectMagic, Vst::FourCC("mdaC"), "MDA Degrade", "* Old versions of this plugin can crash OpenMPT.\nEnsure that you have the latest version of this plugin."},
- {Vst::kEffectMagic, Vst::FourCC("fV2s"), "Farbrausch V2", "* This plugin can cause OpenMPT to freeze if being used in a combination with various other plugins.\nIt is recommended to use V2 only through the Plugin Bridge."},
- {Vst::kEffectMagic, Vst::FourCC("frV2"), "Farbrausch V2", "* This plugin can cause OpenMPT to freeze if being used in a combination with various other plugins.\nIt is recommended to use V2 only through the Plugin Bridge."},
- {Vst::kEffectMagic, Vst::FourCC("MMID"), "MIDI Input Output", "* The MIDI Input / Output plugin is now built right into OpenMPT and should not be loaded from an external file."},
- };
- // Plugins that should always be bridged or require a specific bridge mode.
- constexpr struct
- {
- int32 id1;
- int32 id2;
- bool useBridge;
- bool shareInstance;
- bool modernBridge;
- } ForceBridgePlugins[] =
- {
- {Vst::kEffectMagic, Vst::FourCC("fV2s"), true, false, false}, // V2 freezes on shutdown if there's more than one instance per process
- {Vst::kEffectMagic, Vst::FourCC("frV2"), true, false, false}, // ditto
- {Vst::kEffectMagic, Vst::FourCC("SKV3"), false, true, false}, // SideKick v3 always has to run in a shared instance
- {Vst::kEffectMagic, Vst::FourCC("YWS!"), false, true, false}, // You Wa Shock ! always has to run in a shared instance
- {Vst::kEffectMagic, Vst::FourCC("S1Vs"), mpt::arch_bits == 64, true, false}, // Synth1 64-bit has an issue with pointers using the high 32 bits, hence must use the legacy bridge without high-entropy heap
- };
- } // namespace
- #endif // MPT_WITH_VST
- bool CSelectPluginDlg::VerifyPlugin(VSTPluginLib *plug, CWnd *parent)
- {
- #ifdef MPT_WITH_VST
- for(const auto &p : ProblematicPlugins)
- {
- if(p.id2 == plug->pluginId2 && p.id1 == plug->pluginId1)
- {
- std::string s = MPT_AFORMAT("WARNING: This plugin has been identified as {},\nwhich is known to have the following problem with OpenMPT:\n\n{}\n\nWould you still like to add this plugin to the library?")(p.name, p.problem);
- if(Reporting::Confirm(s, false, false, parent) == cnfNo)
- {
- return false;
- }
- break;
- }
- }
- for(const auto &p : ForceBridgePlugins)
- {
- if(p.id2 == plug->pluginId2 && p.id1 == plug->pluginId1)
- {
- plug->useBridge = p.useBridge;
- plug->shareBridgeInstance = p.shareInstance;
- if(!p.modernBridge)
- plug->modernBridge = false;
- plug->WriteToCache();
- break;
- }
- }
- #else // !MPT_WITH_VST
- MPT_UNREFERENCED_PARAMETER(plug);
- MPT_UNREFERENCED_PARAMETER(parent);
- #endif // MPT_WITH_VST
- return true;
- }
- void CSelectPluginDlg::OnAddPlugin()
- {
- FileDialog dlg = OpenFileDialog()
- .AllowMultiSelect()
- .DefaultExtension("dll")
- .ExtensionFilter("VST Plugins|*.dll;*.vst3||")
- .WorkingDirectory(TrackerSettings::Instance().PathPlugins.GetWorkingDir());
- if(!dlg.Show(this)) return;
- TrackerSettings::Instance().PathPlugins.SetWorkingDir(dlg.GetWorkingDirectory());
- CVstPluginManager *plugManager = theApp.GetPluginManager();
- if(!plugManager)
- return;
- VSTPluginLib *plugLib = nullptr;
- bool update = false;
- for(const auto &file : dlg.GetFilenames())
- {
- VSTPluginLib *lib = plugManager->AddPlugin(file, TrackerSettings::Instance().BrokenPluginsWorkaroundVSTMaskAllCrashes, mpt::ustring(), false);
- if(lib != nullptr)
- {
- update = true;
- if(!VerifyPlugin(lib, this))
- {
- plugManager->RemovePlugin(lib);
- } else
- {
- plugLib = lib;
- // If this plugin was missing anywhere, try loading it
- ReloadMissingPlugins(lib);
- }
- }
- }
- if(update)
- {
- // Force selection to last added plug.
- UpdatePluginsList(plugLib);
- } else
- {
- Reporting::Error("No valid VST Plugin was selected.");
- }
- }
- void CSelectPluginDlg::OnScanFolder()
- {
- BrowseForFolder dlg(TrackerSettings::Instance().PathPlugins.GetWorkingDir(), _T("Select a folder that should be scanned for VST plugins (including sub-folders)"));
- if(!dlg.Show(this)) return;
- TrackerSettings::Instance().PathPlugins.SetWorkingDir(dlg.GetDirectory());
- VSTPluginLib *plugLib = ScanPlugins(dlg.GetDirectory(), this);
- UpdatePluginsList(plugLib);
- // If any of the plugins was missing anywhere, try loading it
- for(auto p : *theApp.GetPluginManager())
- {
- ReloadMissingPlugins(p);
- }
- }
- VSTPluginLib *CSelectPluginDlg::ScanPlugins(const mpt::PathString &path, CWnd *parent)
- {
- CVstPluginManager *pManager = theApp.GetPluginManager();
- VSTPluginLib *plugLib = nullptr;
- bool update = false;
- CDialog pluginScanDlg;
- pluginScanDlg.Create(IDD_SCANPLUGINS, parent);
- pluginScanDlg.CenterWindow(parent);
- pluginScanDlg.ModifyStyle(0, WS_SYSMENU, WS_SYSMENU);
- pluginScanDlg.ShowWindow(SW_SHOW);
- FolderScanner scan(path, FolderScanner::kOnlyFiles | FolderScanner::kFindInSubDirectories);
- bool maskCrashes = TrackerSettings::Instance().BrokenPluginsWorkaroundVSTMaskAllCrashes;
- mpt::PathString fileName;
- int files = 0;
- while(scan.Next(fileName) && pluginScanDlg.IsWindowVisible())
- {
- if(!mpt::PathString::CompareNoCase(fileName.GetFileExt(), P_(".dll")))
- {
- CWnd *text = pluginScanDlg.GetDlgItem(IDC_SCANTEXT);
- CString scanStr = _T("Scanning Plugin...\n") + fileName.ToCString();
- text->SetWindowText(scanStr);
- MSG msg;
- while(::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
- {
- ::TranslateMessage(&msg);
- ::DispatchMessage(&msg);
- }
- VSTPluginLib *lib = pManager->AddPlugin(fileName, maskCrashes, mpt::ustring(), false);
- if(lib)
- {
- update = true;
- if(!VerifyPlugin(lib, parent))
- {
- pManager->RemovePlugin(lib);
- } else
- {
- plugLib = lib;
- files++;
- }
- }
- }
- }
- if(update)
- {
- // Force selection to last added plug.
- Reporting::Information(MPT_AFORMAT("Found {} plugin{}.")(files, files == 1 ? "" : "s").c_str(), parent);
- return plugLib;
- } else
- {
- Reporting::Error("Could not find any valid VST plugins.");
- return nullptr;
- }
- }
- // After adding new plugins, check if they were missing in any open songs.
- void CSelectPluginDlg::ReloadMissingPlugins(const VSTPluginLib *lib) const
- {
- CVstPluginManager *plugManager = theApp.GetPluginManager();
- auto docs = theApp.GetOpenDocuments();
- for(auto &modDoc : docs)
- {
- CSoundFile &sndFile = modDoc->GetSoundFile();
- bool updateDoc = false;
- for(auto &plugin : sndFile.m_MixPlugins)
- {
- if(plugin.pMixPlugin == nullptr
- && plugin.Info.dwPluginId1 == lib->pluginId1
- && plugin.Info.dwPluginId2 == lib->pluginId2)
- {
- updateDoc = true;
- plugManager->CreateMixPlugin(plugin, sndFile);
- if(plugin.pMixPlugin)
- {
- plugin.pMixPlugin->RestoreAllParameters(plugin.defaultProgram);
- }
- }
- }
- if(updateDoc)
- {
- modDoc->UpdateAllViews(nullptr, PluginHint().Info().Names());
- CMainFrame::GetMainFrame()->UpdateTree(modDoc, PluginHint().Info().Names());
- }
- }
- }
- void CSelectPluginDlg::OnRemovePlugin()
- {
- const HTREEITEM pluginToDelete = m_treePlugins.GetSelectedItem();
- VSTPluginLib *plugin = GetSelectedPlugin();
- CVstPluginManager *plugManager = theApp.GetPluginManager();
- if(plugManager && plugin)
- {
- if(plugManager->RemovePlugin(plugin))
- {
- m_treePlugins.DeleteItem(pluginToDelete);
- }
- }
- }
- void CSelectPluginDlg::OnSetBridge()
- {
- VSTPluginLib *plug = GetSelectedPlugin();
- if(plug)
- {
- if(m_chkBridge.IsWindowEnabled())
- {
- // Only update this setting if the current setting isn't an enforced setting (e.g. because plugin isn't native).
- // This has the advantage that plugins don't get force-checked when switching between 32-bit and 64-bit versions of OpenMPT.
- plug->useBridge = m_chkBridge.GetCheck() != BST_UNCHECKED;
- }
- m_chkShare.EnableWindow(m_chkBridge.GetCheck() != BST_UNCHECKED);
- m_chkLegacyBridge.EnableWindow(m_chkBridge.GetCheck() != BST_UNCHECKED);
- plug->shareBridgeInstance = m_chkShare.GetCheck() != BST_UNCHECKED;
- plug->modernBridge = m_chkLegacyBridge.GetCheck() == BST_UNCHECKED;
- plug->WriteToCache();
- }
- }
- void CSelectPluginDlg::OnPluginTagsChanged()
- {
- VSTPluginLib *plug = GetSelectedPlugin();
- if (plug)
- {
- plug->tags = GetWindowTextUnicode(*GetDlgItem(IDC_PLUGINTAGS));
- }
- }
- OPENMPT_NAMESPACE_END
- #endif // NO_PLUGINS
|