12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022 |
- /*
- * AbstractVstEditor.cpp
- * ---------------------
- * Purpose: Common plugin editor interface class. This code is shared between custom and default plugin user interfaces.
- * 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.h"
- #include "Mainfrm.h"
- #include "Clipboard.h"
- #include "../soundlib/Sndfile.h"
- #include "../soundlib/mod_specifications.h"
- #include "../soundlib/plugins/PlugInterface.h"
- #include "../soundlib/plugins/PluginManager.h"
- #include "Vstplug.h"
- #include "dlg_misc.h"
- #include "AbstractVstEditor.h"
- #include "../common/mptStringBuffer.h"
- #include "MIDIMacros.h"
- #include "VstPresets.h"
- #include "../common/FileReader.h"
- #include "InputHandler.h"
- #include "dlg_misc.h"
- #include <sstream>
- #include "Globals.h"
- OPENMPT_NAMESPACE_BEGIN
- #ifndef NO_PLUGINS
- CAbstractVstEditor::WindowSizeAdjuster::WindowSizeAdjuster(CWnd &wnd)
- : m_wnd(wnd)
- {
- MENUBARINFO mbi = { sizeof(mbi) };
- if(GetMenuBarInfo(m_wnd, OBJID_MENU, 0, &mbi))
- m_menuHeight = (mbi.rcBar.bottom - mbi.rcBar.top);
- }
- CAbstractVstEditor::WindowSizeAdjuster::~WindowSizeAdjuster()
- {
- // Extend window height by the menu size if it changed
- MENUBARINFO mbi = { sizeof(mbi) };
- if(GetMenuBarInfo(m_wnd, OBJID_MENU, 0, &mbi))
- {
- CRect windowRect;
- m_wnd.GetWindowRect(&windowRect);
- windowRect.bottom += (mbi.rcBar.bottom - mbi.rcBar.top) - m_menuHeight;
- m_wnd.SetWindowPos(nullptr, 0, 0,
- windowRect.Width(), windowRect.Height(),
- SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
- }
- }
- #define PRESETS_PER_COLUMN 32
- #define PRESETS_PER_GROUP 128
- UINT CAbstractVstEditor::m_clipboardFormat = RegisterClipboardFormat(_T("VST Preset Data"));
- BEGIN_MESSAGE_MAP(CAbstractVstEditor, CDialog)
- ON_WM_CLOSE()
- ON_WM_INITMENU()
- ON_WM_MENUSELECT()
- ON_WM_ACTIVATE()
- ON_WM_DROPFILES()
- ON_WM_MOVE()
- ON_WM_NCLBUTTONDBLCLK()
- ON_COMMAND(ID_EDIT_COPY, &CAbstractVstEditor::OnCopyParameters)
- ON_COMMAND(ID_EDIT_PASTE, &CAbstractVstEditor::OnPasteParameters)
- ON_COMMAND(ID_PRESET_LOAD, &CAbstractVstEditor::OnLoadPreset)
- ON_COMMAND(ID_PLUG_BYPASS, &CAbstractVstEditor::OnBypassPlug)
- ON_COMMAND(ID_PLUG_RECORDAUTOMATION,&CAbstractVstEditor::OnRecordAutomation)
- ON_COMMAND(ID_PLUG_RECORD_MIDIOUT, &CAbstractVstEditor::OnRecordMIDIOut)
- ON_COMMAND(ID_PLUG_PASSKEYS, &CAbstractVstEditor::OnPassKeypressesToPlug)
- ON_COMMAND(ID_PRESET_SAVE, &CAbstractVstEditor::OnSavePreset)
- ON_COMMAND(ID_PRESET_RANDOM, &CAbstractVstEditor::OnRandomizePreset)
- ON_COMMAND(ID_RENAME_PLUGIN, &CAbstractVstEditor::OnRenamePlugin)
- ON_COMMAND(ID_PREVIOUSVSTPRESET, &CAbstractVstEditor::OnSetPreviousVSTPreset)
- ON_COMMAND(ID_NEXTVSTPRESET, &CAbstractVstEditor::OnSetNextVSTPreset)
- ON_COMMAND(ID_VSTPRESETBACKWARDJUMP,&CAbstractVstEditor::OnVSTPresetBackwardJump)
- ON_COMMAND(ID_VSTPRESETFORWARDJUMP, &CAbstractVstEditor::OnVSTPresetForwardJump)
- ON_COMMAND(ID_VSTPRESETNAME, &CAbstractVstEditor::OnVSTPresetRename)
- ON_COMMAND(ID_PLUGINTOINSTRUMENT, &CAbstractVstEditor::OnCreateInstrument)
- ON_COMMAND_RANGE(ID_PRESET_SET, ID_PRESET_SET + PRESETS_PER_GROUP, &CAbstractVstEditor::OnSetPreset)
- ON_MESSAGE(WM_MOD_MIDIMSG, &CAbstractVstEditor::OnMidiMsg)
- ON_MESSAGE(WM_MOD_KEYCOMMAND, &CAbstractVstEditor::OnCustomKeyMsg) //rewbs.customKeys
- ON_COMMAND_RANGE(ID_PLUGSELECT, ID_PLUGSELECT + MAX_MIXPLUGINS, &CAbstractVstEditor::OnToggleEditor) //rewbs.patPlugName
- ON_COMMAND_RANGE(ID_SELECTINST, ID_SELECTINST + MAX_INSTRUMENTS, &CAbstractVstEditor::OnSetInputInstrument) //rewbs.patPlugName
- ON_COMMAND_RANGE(ID_LEARN_MACRO_FROM_PLUGGUI, ID_LEARN_MACRO_FROM_PLUGGUI + kSFxMacros, &CAbstractVstEditor::PrepareToLearnMacro)
- END_MESSAGE_MAP()
- CAbstractVstEditor::CAbstractVstEditor(IMixPlugin &plugin)
- : m_VstPlugin(plugin)
- {
- m_Menu.LoadMenu(IDR_VSTMENU);
- m_nInstrument = GetBestInstrumentCandidate();
- }
- CAbstractVstEditor::~CAbstractVstEditor()
- {
- m_VstPlugin.m_pEditor = nullptr;
- }
- void CAbstractVstEditor::PostNcDestroy()
- {
- CDialog::PostNcDestroy();
- delete this;
- }
- void CAbstractVstEditor::OnNcLButtonDblClk(UINT nHitTest, CPoint point)
- {
- CDialog::OnNcLButtonDblClk(nHitTest, point);
- // Double click on title bar = reduce plugin window to non-client area
- if(nHitTest == HTCAPTION)
- {
- CRect rcWnd, rcClient;
- GetWindowRect(&rcWnd);
- if(!m_isMinimized)
- {
- // When minimizing, remove the client area
- GetClientRect(&rcClient);
- m_clientHeight = rcClient.Height();
- }
- m_isMinimized = !m_isMinimized;
- m_clientHeight = -m_clientHeight;
- int rcHeight = rcWnd.Height() + m_clientHeight;
- SetWindowPos(NULL, 0, 0,
- rcWnd.Width(), rcHeight,
- SWP_NOZORDER | SWP_NOMOVE);
- }
- }
- void CAbstractVstEditor::OnActivate(UINT nState, CWnd *pWndOther, BOOL bMinimized)
- {
- CDialog::OnActivate(nState, pWndOther, bMinimized);
- if(nState != WA_INACTIVE) CMainFrame::GetMainFrame()->SetMidiRecordWnd(GetSafeHwnd());
- }
- LRESULT CAbstractVstEditor::OnMidiMsg(WPARAM midiData, LPARAM sender)
- {
- CModDoc *modDoc = m_VstPlugin.GetModDoc();
- if(modDoc != nullptr && sender != reinterpret_cast<LPARAM>(&m_VstPlugin))
- {
- if(!CheckInstrument(m_nInstrument))
- m_nInstrument = GetBestInstrumentCandidate();
- modDoc->ProcessMIDI((uint32)midiData, m_nInstrument, &m_VstPlugin, kCtxVSTGUI);
- return 1;
- }
- return 0;
- }
- // Drop files from Windows
- void CAbstractVstEditor::OnDropFiles(HDROP hDropInfo)
- {
- const UINT nFiles = ::DragQueryFileW(hDropInfo, (UINT)-1, NULL, 0);
- CMainFrame::GetMainFrame()->SetForegroundWindow();
- for(UINT f = 0; f < nFiles; f++)
- {
- UINT size = ::DragQueryFile(hDropInfo, f, nullptr, 0) + 1;
- std::vector<TCHAR> fileName(size, _T('\0'));
- if(::DragQueryFile(hDropInfo, f, fileName.data(), size))
- {
- m_VstPlugin.LoadProgram(mpt::PathString::FromNative(fileName.data()));
- }
- }
- ::DragFinish(hDropInfo);
- }
- void CAbstractVstEditor::OnLoadPreset()
- {
- if(m_VstPlugin.LoadProgram())
- {
- UpdatePresetMenu(true);
- UpdatePresetField();
- }
- }
- void CAbstractVstEditor::OnSavePreset()
- {
- m_VstPlugin.SaveProgram();
- }
- void CAbstractVstEditor::OnCopyParameters()
- {
- if(CMainFrame::GetMainFrame() == nullptr) return;
- BeginWaitCursor();
- std::ostringstream f(std::ios::out | std::ios::binary);
- if(VSTPresets::SaveFile(f, m_VstPlugin, false))
- {
- const std::string data = f.str();
- Clipboard clipboard(m_clipboardFormat, data.length());
- if(auto dst = clipboard.As<char>())
- {
- memcpy(dst, data.data(), data.length());
- }
- }
- EndWaitCursor();
- }
- void CAbstractVstEditor::OnPasteParameters()
- {
- if(CMainFrame::GetMainFrame() == nullptr) return;
- BeginWaitCursor();
- Clipboard clipboard(m_clipboardFormat);
- if(auto data = clipboard.Get(); data.data())
- {
- FileReader file(data);
- VSTPresets::ErrorCode error = VSTPresets::LoadFile(file, m_VstPlugin);
- clipboard.Close();
- if(error == VSTPresets::noError)
- {
- const CSoundFile &sndFile = m_VstPlugin.GetSoundFile();
- CModDoc *pModDoc;
- if(sndFile.GetModSpecifications().supportsPlugins && (pModDoc = sndFile.GetpModDoc()) != nullptr)
- {
- pModDoc->SetModified();
- }
- UpdatePresetField();
- } else
- {
- Reporting::Error(VSTPresets::GetErrorMessage(error));
- }
- }
- EndWaitCursor();
- }
- void CAbstractVstEditor::OnRandomizePreset()
- {
- static double randomFactor = 10.0;
- CInputDlg dlg(this, _T("Input parameter randomization amount (0 = no change, 100 = completely random)"), 0.0, 100.0, randomFactor);
- if(dlg.DoModal() == IDOK)
- {
- randomFactor = dlg.resultAsDouble;
- PlugParamValue factor = PlugParamValue(randomFactor / 100.0);
- PlugParamIndex numParams = m_VstPlugin.GetNumParameters();
- for(PlugParamIndex p = 0; p < numParams; p++)
- {
- PlugParamValue val = m_VstPlugin.GetParameter(p);
- val += mpt::random(theApp.PRNG(), PlugParamValue(-1.0), PlugParamValue(1.0)) * factor;
- Limit(val, 0.0f, 1.0f);
- m_VstPlugin.SetParameter(p, val);
- }
- UpdateParamDisplays();
- }
- }
- void CAbstractVstEditor::OnRenamePlugin()
- {
- auto &sndFile = m_VstPlugin.GetSoundFile();
- auto &plugin = sndFile.m_MixPlugins[m_VstPlugin.m_nSlot];
- CInputDlg dlg(this, _T("New name for this plugin instance:"), mpt::ToCString(plugin.GetName()), static_cast<int32>(std::size(plugin.Info.szName.buf)));
- if(dlg.DoModal() == IDOK)
- {
- if(dlg.resultAsString != mpt::ToCString(plugin.GetName()))
- {
- plugin.Info.szName = mpt::ToCharset(mpt::Charset::Locale, dlg.resultAsString);
- if(auto *modDoc = sndFile.GetpModDoc(); modDoc != nullptr)
- {
- if(sndFile.GetModSpecifications().supportsPlugins)
- modDoc->SetModified();
- modDoc->UpdateAllViews(nullptr, PluginHint(m_VstPlugin.m_nSlot + 1).Info().Names(), this);
- }
- SetTitle();
- }
- }
- }
- bool CAbstractVstEditor::OpenEditor(CWnd *)
- {
- ModifyStyleEx(0, WS_EX_ACCEPTFILES);
- RestoreWindowPos();
- SetTitle();
- SetupMenu();
- ShowWindow(SW_SHOW);
- return true;
- }
- void CAbstractVstEditor::DoClose()
- {
- StoreWindowPos();
- m_presetMenuGroup.clear();
- DestroyWindow();
- }
- void CAbstractVstEditor::SetupMenu(bool force)
- {
- WindowSizeAdjuster adjuster(*this);
- SetMenu(&m_Menu);
- UpdatePresetMenu(force);
- UpdateInputMenu();
- UpdateOutputMenu();
- UpdateMacroMenu();
- UpdateOptionsMenu();
- UpdatePresetField();
- }
- void CAbstractVstEditor::UpdatePresetField()
- {
- if(m_VstPlugin.GetNumPrograms() > 0)
- {
- if(m_Menu.GetMenuItemCount() < 5)
- {
- m_Menu.AppendMenu(MF_BYPOSITION, ID_VSTPRESETBACKWARDJUMP, _T("<<"));
- m_Menu.AppendMenu(MF_BYPOSITION, ID_PREVIOUSVSTPRESET, _T("<"));
- m_Menu.AppendMenu(MF_BYPOSITION, ID_NEXTVSTPRESET, _T(">"));
- m_Menu.AppendMenu(MF_BYPOSITION, ID_VSTPRESETFORWARDJUMP, _T(">>"));
- m_Menu.AppendMenu(MF_BYPOSITION|MF_DISABLED, ID_VSTPRESETNAME, _T(""));
- }
- CString programName = m_VstPlugin.GetFormattedProgramName(m_VstPlugin.GetCurrentProgram());
- programName.Replace(_T("&"), _T("&&"));
- m_Menu.ModifyMenu(8, MF_BYPOSITION, ID_VSTPRESETNAME, programName);
- }
- DrawMenuBar();
- }
- void CAbstractVstEditor::OnSetPreset(UINT nID)
- {
- SetPreset(nID - ID_PRESET_SET + m_currentPresetMenu * PRESETS_PER_GROUP);
- }
- void CAbstractVstEditor::OnSetPreviousVSTPreset()
- {
- SetPreset(m_VstPlugin.GetCurrentProgram() - 1);
- }
- void CAbstractVstEditor::OnSetNextVSTPreset()
- {
- SetPreset(m_VstPlugin.GetCurrentProgram() + 1);
- }
- void CAbstractVstEditor::OnVSTPresetBackwardJump()
- {
- SetPreset(std::max(0, m_VstPlugin.GetCurrentProgram() - 10));
- }
- void CAbstractVstEditor::OnVSTPresetForwardJump()
- {
- SetPreset(std::min(m_VstPlugin.GetCurrentProgram() + 10, m_VstPlugin.GetNumPrograms() - 1));
- }
- void CAbstractVstEditor::SetPreset(int32 preset)
- {
- if(preset >= 0 && preset < m_VstPlugin.GetNumPrograms())
- {
- m_VstPlugin.SetCurrentProgram(preset);
- WindowSizeAdjuster adjuster(*this);
- UpdatePresetField();
- if(m_VstPlugin.GetSoundFile().GetModSpecifications().supportsPlugins)
- {
- m_VstPlugin.GetModDoc()->SetModified();
- }
- }
- }
- void CAbstractVstEditor::OnVSTPresetRename()
- {
- auto currentName = m_VstPlugin.GetCurrentProgramName();
- CInputDlg dlg(this, _T("New program name:"), currentName);
- if(dlg.DoModal() == IDOK)
- {
- m_VstPlugin.SetCurrentProgramName(dlg.resultAsString);
- if(m_VstPlugin.GetCurrentProgramName() != currentName)
- {
- m_VstPlugin.SetModified();
- WindowSizeAdjuster adjuster(*this);
- UpdatePresetField();
- UpdatePresetMenu(true);
- }
- }
- }
- void CAbstractVstEditor::OnBypassPlug()
- {
- m_VstPlugin.ToggleBypass();
- if(m_VstPlugin.GetSoundFile().GetModSpecifications().supportsPlugins)
- {
- m_VstPlugin.GetModDoc()->SetModified();
- }
- SetTitle();
- }
- void CAbstractVstEditor::OnRecordAutomation()
- {
- m_VstPlugin.m_recordAutomation = !m_VstPlugin.m_recordAutomation;
- }
- void CAbstractVstEditor::OnRecordMIDIOut()
- {
- m_VstPlugin.m_recordMIDIOut = !m_VstPlugin.m_recordMIDIOut;
- }
- void CAbstractVstEditor::OnPassKeypressesToPlug()
- {
- m_VstPlugin.m_passKeypressesToPlug = !m_VstPlugin.m_passKeypressesToPlug;
- }
- BOOL CAbstractVstEditor::PreTranslateMessage(MSG *msg)
- {
- if(msg && HandleKeyMessage(*msg))
- return TRUE;
- return CDialog::PreTranslateMessage(msg);
- }
- bool CAbstractVstEditor::HandleKeyMessage(MSG &msg)
- {
- if(m_VstPlugin.m_passKeypressesToPlug)
- return false;
- if(msg.message != WM_SYSKEYUP && msg.message != WM_KEYUP && msg.message != WM_SYSKEYDOWN && msg.message != WM_KEYDOWN)
- return false;
- CInputHandler *ih = CMainFrame::GetInputHandler();
- if(ih->IsKeyPressHandledByTextBox(static_cast<DWORD>(msg.wParam), ::GetFocus()))
- return false;
- // Translate message manually
- UINT nChar = (UINT)msg.wParam;
- UINT nRepCnt = LOWORD(msg.lParam);
- UINT nFlags = HIWORD(msg.lParam);
- KeyEventType kT = ih->GetKeyEventType(nFlags);
- // If we successfully mapped to a command and plug does not listen for keypresses, no need to pass message on.
- if(ih->KeyEvent(kCtxVSTGUI, nChar, nRepCnt, nFlags, kT, this) != kcNull)
- return true;
- // Don't forward key repeats if plug does not listen for keypresses
- // (avoids system beeps on note hold)
- if(kT == kKeyEventRepeat)
- return true;
-
- return false;
- }
- void CAbstractVstEditor::UpdateView(UpdateHint hint)
- {
- if(!hint.GetType()[HINT_PLUGINNAMES | HINT_MIXPLUGINS])
- return;
- PLUGINDEX hintPlug = hint.ToType<PluginHint>().GetPlugin();
- if(hintPlug > 0 && (hintPlug - 1) != m_VstPlugin.GetSlot())
- return;
- SetTitle();
- }
- void CAbstractVstEditor::SetTitle()
- {
- if(m_VstPlugin.m_pMixStruct)
- {
- CString title = MPT_CFORMAT("FX {}: ")(mpt::cfmt::dec0<2>(m_VstPlugin.m_nSlot + 1));
- bool hasCustomName = (m_VstPlugin.m_pMixStruct->GetName() != U_("")) && (m_VstPlugin.m_pMixStruct->GetName() != m_VstPlugin.m_pMixStruct->GetLibraryName());
- if(hasCustomName)
- title += mpt::ToCString(m_VstPlugin.m_pMixStruct->GetName()) + _T(" (");
- title += mpt::ToCString(m_VstPlugin.m_pMixStruct->GetLibraryName());
- if(hasCustomName)
- title += _T(")");
- #ifdef MPT_WITH_VST
- const CVstPlugin *vstPlugin = dynamic_cast<CVstPlugin *>(&m_VstPlugin);
- if(vstPlugin != nullptr && vstPlugin->isBridged)
- title += MPT_CFORMAT(" ({} Bridged)")(m_VstPlugin.GetPluginFactory().GetDllArchNameUser());
- #endif // MPT_WITH_VST
- if(m_VstPlugin.IsBypassed())
- title += _T(" - Bypass");
- SetWindowText(title);
- }
- }
- LRESULT CAbstractVstEditor::OnCustomKeyMsg(WPARAM wParam, LPARAM /*lParam*/)
- {
- switch(wParam)
- {
- case kcVSTGUIPrevPreset: OnSetPreviousVSTPreset(); return wParam;
- case kcVSTGUIPrevPresetJump: OnVSTPresetBackwardJump(); return wParam;
- case kcVSTGUINextPreset: OnSetNextVSTPreset(); return wParam;
- case kcVSTGUINextPresetJump: OnVSTPresetForwardJump(); return wParam;
- case kcVSTGUIRandParams: OnRandomizePreset() ; return wParam;
- case kcVSTGUIToggleRecordParams: OnRecordAutomation(); return wParam;
- case kcVSTGUIToggleSendKeysToPlug: OnPassKeypressesToPlug(); return wParam;
- case kcVSTGUIBypassPlug: OnBypassPlug(); return wParam;
- }
- if (wParam >= kcVSTGUIStartNotes && wParam <= kcVSTGUIEndNotes)
- {
- if(ValidateCurrentInstrument())
- {
- CModDoc *pModDoc = m_VstPlugin.GetModDoc();
- const ModCommand::NOTE note = pModDoc->GetNoteWithBaseOctave(static_cast<int>(wParam - kcVSTGUIStartNotes), m_nInstrument);
- if(ModCommand::IsNote(note))
- {
- pModDoc->PlayNote(PlayNoteParam(note).Instrument(m_nInstrument), &m_noteChannel);
- }
- }
- return wParam;
- }
- if (wParam >= kcVSTGUIStartNoteStops && wParam <= kcVSTGUIEndNoteStops)
- {
- if(ValidateCurrentInstrument())
- {
- CModDoc *pModDoc = m_VstPlugin.GetModDoc();
- const ModCommand::NOTE note = pModDoc->GetNoteWithBaseOctave(static_cast<int>(wParam - kcVSTGUIStartNoteStops), m_nInstrument);
- if(ModCommand::IsNote(note))
- {
- pModDoc->NoteOff(note, false, m_nInstrument, m_noteChannel[note - NOTE_MIN]);
- }
- }
- return wParam;
- }
- return kcNull;
- }
- // When trying to play a note using this plugin, but no instrument is assigned to it,
- // the user is asked whether a new instrument should be added.
- bool CAbstractVstEditor::ValidateCurrentInstrument()
- {
- if(!CheckInstrument(m_nInstrument))
- m_nInstrument = GetBestInstrumentCandidate();
- //only show messagebox if plug is able to process notes.
- if(m_nInstrument == INSTRUMENTINDEX_INVALID)
- {
- if(m_VstPlugin.CanRecieveMidiEvents())
- {
- // We might need to steal the focus from the plugin bridge. This is going to work
- // as the plugin bridge will call AllowSetForegroundWindow on key messages.
- SetForegroundWindow();
- if(!m_VstPlugin.IsInstrument() || m_VstPlugin.GetSoundFile().GetModSpecifications().instrumentsMax == 0 ||
- Reporting::Confirm(_T("You need to assign an instrument to this plugin before you can play notes from here.\nCreate a new instrument and assign this plugin to the instrument?"), false, false, this) == cnfNo)
- {
- return false;
- } else
- {
- OnCreateInstrument();
- // Return true since we don't want to trigger the note for which the instrument has been validated yet.
- // Otherwise, the note might hang forever because the key-up event will go missing.
- return false;
- }
- } else
- {
- // Can't process notes
- return false;
- }
- }
- return true;
- }
- static int GetNumSubMenus(int32 numProgs) { return (numProgs + (PRESETS_PER_GROUP - 1)) / PRESETS_PER_GROUP; }
- void CAbstractVstEditor::OnMenuSelect(UINT nItemID, UINT nFlags, HMENU hSysMenu)
- {
- if(!(nFlags & MF_POPUP))
- {
- return;
- }
- if(hSysMenu == m_Menu.m_hMenu)
- {
- // Main menu
- switch(nItemID)
- {
- case 0:
- // Grey out paste menu item.
- m_Menu.EnableMenuItem(ID_EDIT_PASTE, MF_BYCOMMAND | (IsClipboardFormatAvailable(m_clipboardFormat) ? 0 : MF_GRAYED));
- break;
- case 1:
- // If there would be only one sub menu, we add presets directly to the factory menu
- {
- const int32 numProgs = m_VstPlugin.GetNumPrograms();
- if(GetNumSubMenus(numProgs) <= 1)
- {
- GeneratePresetMenu(0, m_PresetMenu);
- }
- }
- break;
- }
- } else if(hSysMenu == m_Menu.GetSubMenu(1)->m_hMenu)
- {
- // Preset menu
- m_currentPresetMenu = nItemID;
- GeneratePresetMenu(nItemID * PRESETS_PER_GROUP, *m_presetMenuGroup[nItemID]);
- }
- }
- void CAbstractVstEditor::UpdatePresetMenu(bool force)
- {
- const int32 numProgs = m_VstPlugin.GetNumPrograms();
- const int32 curProg = m_VstPlugin.GetCurrentProgram();
- if(m_PresetMenu.m_hMenu) // We rebuild the menu from scratch, so remove any exiting menus...
- {
- if(curProg == m_nCurProg && !force) // ... unless menu exists and is accurate, in which case we are done.
- return;
- m_presetMenuGroup.clear();
- // If there were no preset groups, delete the remaining content so that it can be refilled dynamically
- while(m_PresetMenu.GetMenuItemCount() > 0)
- m_PresetMenu.RemoveMenu(0, MF_BYPOSITION);
- } else
- {
- // Create Factory preset menu
- m_PresetMenu.CreatePopupMenu();
- m_Menu.InsertMenu(1, MF_BYPOSITION | MF_POPUP, reinterpret_cast<UINT_PTR>(m_PresetMenu.m_hMenu), _T("&Presets"));
- }
- m_Menu.EnableMenuItem(1, MF_BYPOSITION | (numProgs ? 0 : MF_GRAYED));
- const int numSubMenus = GetNumSubMenus(numProgs);
- if(numSubMenus > 1)
- {
- // Depending on the plugin and its number of presets, filling the sub menus can take quite a while (e.g. Synth1),
- // so we fill the menus only on demand (when they are opened), so that the editor GUI creation doesn't take forever.
- m_presetMenuGroup.resize(numSubMenus);
- for(int bank = 0, prog = 0; bank < numSubMenus; bank++, prog += PRESETS_PER_GROUP)
- {
- m_presetMenuGroup[bank] = std::make_unique<CMenu>();
- m_presetMenuGroup[bank]->CreatePopupMenu();
- CString label;
- label.Format(_T("Bank %d (%d-%d)"), bank + 1, prog + 1, std::min(prog + PRESETS_PER_GROUP, numProgs));
- m_PresetMenu.AppendMenu(MF_POPUP
- | (bank % 32 == 0 ? MF_MENUBREAK : 0)
- | (curProg >= prog && curProg < prog + PRESETS_PER_GROUP ? MF_CHECKED : MF_UNCHECKED),
- reinterpret_cast<UINT_PTR>(m_presetMenuGroup[bank]->m_hMenu), label);
- }
- }
- m_currentPresetMenu = 0;
- m_nCurProg = curProg;
- }
- void CAbstractVstEditor::GeneratePresetMenu(int32 offset, CMenu &parent)
- {
- const int32 numProgs = m_VstPlugin.GetNumPrograms();
- const int32 curProg = m_VstPlugin.GetCurrentProgram();
- const int32 endProg = std::min(offset + PRESETS_PER_GROUP, numProgs);
- if(parent.GetMenuItemCount() != 0)
- {
- // Already generated.
- return;
- }
- m_VstPlugin.CacheProgramNames(offset, endProg);
- for(int32 p = offset, row = 0, id = 0; p < endProg; p++, row++, id++)
- {
- CString programName = m_VstPlugin.GetFormattedProgramName(p);
- programName.Replace(_T("&"), _T("&&"));
- UINT splitMenuFlag = 0;
- if(row == PRESETS_PER_COLUMN)
- {
- // Advance to next menu column
- row = 0;
- splitMenuFlag = MF_MENUBARBREAK;
- }
- parent.AppendMenu(MF_STRING | (p == curProg ? MF_CHECKED : MF_UNCHECKED) | splitMenuFlag, ID_PRESET_SET + id, programName);
- }
- }
- void CAbstractVstEditor::UpdateInputMenu()
- {
- CMenu *pInfoMenu = m_Menu.GetSubMenu(2);
- pInfoMenu->DeleteMenu(0, MF_BYPOSITION);
- const CSoundFile &sndFile = m_VstPlugin.GetSoundFile();
- if(m_InputMenu.m_hMenu)
- {
- m_InputMenu.DestroyMenu();
- }
- if(!m_InputMenu.m_hMenu)
- {
- m_InputMenu.CreatePopupMenu();
- }
- std::vector<IMixPlugin *> inputPlugs;
- m_VstPlugin.GetInputPlugList(inputPlugs);
- for(auto plug : inputPlugs)
- {
- CString name = MPT_CFORMAT("FX{}: {}")(mpt::cfmt::dec0<2>(plug->m_nSlot + 1), mpt::ToCString(plug->m_pMixStruct->GetName()));
- m_InputMenu.AppendMenu(MF_STRING, ID_PLUGSELECT + plug->m_nSlot, name);
- }
- std::vector<CHANNELINDEX> inputChannels;
- m_VstPlugin.GetInputChannelList(inputChannels);
- bool addSeparator = !inputPlugs.empty();
- for(auto chn : inputChannels)
- {
- if(addSeparator)
- {
- m_InputMenu.AppendMenu(MF_SEPARATOR);
- addSeparator = false;
- }
- CString name = MPT_CFORMAT("Chn{}: {}")(mpt::cfmt::dec0<2>(chn + 1), mpt::ToCString(sndFile.GetCharsetInternal(), sndFile.ChnSettings[chn].szName));
- m_InputMenu.AppendMenu(MF_STRING, NULL, name);
- }
- std::vector<INSTRUMENTINDEX> inputInstruments;
- m_VstPlugin.GetInputInstrumentList(inputInstruments);
- addSeparator = !inputPlugs.empty() || !inputChannels.empty();
- for(auto ins : inputInstruments)
- {
- if(addSeparator)
- {
- m_InputMenu.AppendMenu(MF_SEPARATOR);
- addSeparator = false;
- }
- CString name = MPT_CFORMAT("Ins{}: {}")(mpt::cfmt::dec0<2>(ins), mpt::ToCString(sndFile.GetCharsetInternal(), sndFile.GetInstrumentName(ins)));
- m_InputMenu.AppendMenu(MF_STRING | ((ins == m_nInstrument) ? MF_CHECKED : 0), ID_SELECTINST + ins, name);
- }
- if(inputPlugs.empty() && inputChannels.empty() && inputInstruments.empty())
- {
- m_InputMenu.AppendMenu(MF_STRING | MF_GRAYED, NULL, _T("None"));
- }
- pInfoMenu->InsertMenu(0, MF_BYPOSITION | MF_POPUP, reinterpret_cast<UINT_PTR>(m_InputMenu.m_hMenu), _T("I&nputs"));
- }
- void CAbstractVstEditor::UpdateOutputMenu()
- {
- CMenu *pInfoMenu = m_Menu.GetSubMenu(2);
- pInfoMenu->DeleteMenu(1, MF_BYPOSITION);
- if(m_OutputMenu.m_hMenu)
- {
- m_OutputMenu.DestroyMenu();
- }
- if(!m_OutputMenu.m_hMenu)
- {
- m_OutputMenu.CreatePopupMenu();
- }
- std::vector<IMixPlugin *> outputPlugs;
- m_VstPlugin.GetOutputPlugList(outputPlugs);
- CString name;
- for(auto plug : outputPlugs)
- {
- if(plug != nullptr)
- {
- name.Format(_T("FX%02d: "), plug->m_nSlot + 1);
- name += mpt::ToCString(plug->m_pMixStruct->GetName());
- m_OutputMenu.AppendMenu(MF_STRING, ID_PLUGSELECT + plug->m_nSlot, name);
- } else
- {
- name = _T("Master Output");
- m_OutputMenu.AppendMenu(MF_STRING | MF_GRAYED, NULL, name);
- }
- }
- pInfoMenu->InsertMenu(1, MF_BYPOSITION | MF_POPUP, reinterpret_cast<UINT_PTR>(m_OutputMenu.m_hMenu), _T("Ou&tputs"));
- }
- void CAbstractVstEditor::UpdateMacroMenu()
- {
- CMenu *pInfoMenu = m_Menu.GetSubMenu(2);
- pInfoMenu->DeleteMenu(2, MF_BYPOSITION);
- if(m_MacroMenu.m_hMenu)
- {
- m_MacroMenu.DestroyMenu();
- }
- if(!m_MacroMenu.m_hMenu)
- {
- m_MacroMenu.CreatePopupMenu();
- }
- CString label, macroName;
- for(int nMacro = 0; nMacro < kSFxMacros; nMacro++)
- {
- int action = 0;
- UINT greyed = MF_GRAYED;
- const MIDIMacroConfig &midiCfg = m_VstPlugin.GetSoundFile().m_MidiCfg;
- const ParameteredMacro macroType = midiCfg.GetParameteredMacroType(nMacro);
- if(macroType == kSFxUnused)
- {
- macroName = _T("Unused. Learn Param...");
- action= ID_LEARN_MACRO_FROM_PLUGGUI + nMacro;
- greyed = 0;
- } else
- {
- macroName = midiCfg.GetParameteredMacroName(nMacro, &m_VstPlugin);
- if(macroType != kSFxPlugParam || macroName.Left(3) != _T("N/A"))
- {
- greyed = 0;
- }
- }
- label.Format(_T("SF%X: "), nMacro);
- label += macroName;
- m_MacroMenu.AppendMenu(MF_STRING | greyed, action, label);
- }
- pInfoMenu->InsertMenu(2, MF_BYPOSITION | MF_POPUP, reinterpret_cast<UINT_PTR>(m_MacroMenu.m_hMenu), _T("&Macros"));
- }
- void CAbstractVstEditor::UpdateOptionsMenu()
- {
- if(m_OptionsMenu.m_hMenu)
- m_OptionsMenu.DestroyMenu();
- CInputHandler *ih = CMainFrame::GetInputHandler();
- m_OptionsMenu.CreatePopupMenu();
- //Bypass
- m_OptionsMenu.AppendMenu(MF_STRING | (m_VstPlugin.IsBypassed() ? MF_CHECKED : 0),
- ID_PLUG_BYPASS, ih->GetKeyTextFromCommand(kcVSTGUIBypassPlug, _T("&Bypass Plugin")));
- //Record Params
- m_OptionsMenu.AppendMenu(MF_STRING | (m_VstPlugin.m_recordAutomation ? MF_CHECKED : 0),
- ID_PLUG_RECORDAUTOMATION, ih->GetKeyTextFromCommand(kcVSTGUIToggleRecordParams, _T("Record &Parameter Changes")));
- //Record MIDI Out
- m_OptionsMenu.AppendMenu(MF_STRING | (m_VstPlugin.m_recordMIDIOut ? MF_CHECKED : 0),
- ID_PLUG_RECORD_MIDIOUT, ih->GetKeyTextFromCommand(kcVSTGUIToggleRecordMIDIOut, _T("Record &MIDI Out to Pattern Editor")));
- //Pass on keypresses
- m_OptionsMenu.AppendMenu(MF_STRING | (m_VstPlugin.m_passKeypressesToPlug ? MF_CHECKED : 0),
- ID_PLUG_PASSKEYS, ih->GetKeyTextFromCommand(kcVSTGUIToggleSendKeysToPlug, _T("Pass &Keys to Plugin")));
- m_Menu.DeleteMenu(3, MF_BYPOSITION);
- m_Menu.InsertMenu(3, MF_BYPOSITION | MF_POPUP, reinterpret_cast<UINT_PTR>(m_OptionsMenu.m_hMenu), _T("&Options"));
- }
- void CAbstractVstEditor::OnToggleEditor(UINT nID)
- {
- CModDoc *pModDoc = m_VstPlugin.GetModDoc();
- if(pModDoc)
- {
- pModDoc->TogglePluginEditor(nID - ID_PLUGSELECT);
- }
- }
- void CAbstractVstEditor::OnInitMenu(CMenu* /*pMenu*/)
- {
- SetupMenu();
- }
- bool CAbstractVstEditor::CheckInstrument(INSTRUMENTINDEX ins) const
- {
- const CSoundFile &sndFile = m_VstPlugin.GetSoundFile();
- if(ins != INSTRUMENTINDEX_INVALID && ins < MAX_INSTRUMENTS && sndFile.Instruments[ins] != nullptr)
- {
- return (sndFile.Instruments[ins]->nMixPlug) == (m_VstPlugin.m_nSlot + 1);
- }
- return false;
- }
- INSTRUMENTINDEX CAbstractVstEditor::GetBestInstrumentCandidate() const
- {
- // First try current instrument:
- const CModDoc *modDoc = m_VstPlugin.GetModDoc();
- POSITION pos = modDoc->GetFirstViewPosition();
- while(pos != NULL)
- {
- CModControlView *pView = dynamic_cast<CModControlView *>(modDoc->GetNextView(pos));
- if(pView != nullptr && pView->GetDocument() == modDoc)
- {
- INSTRUMENTINDEX ins = static_cast<INSTRUMENTINDEX>(pView->GetInstrumentChange());
- if(CheckInstrument(ins))
- return ins;
- }
- }
- // Just take the first instrument that points to this plug..
- return modDoc->HasInstrumentForPlugin(m_VstPlugin.m_nSlot);
- }
- void CAbstractVstEditor::OnSetInputInstrument(UINT nID)
- {
- m_nInstrument = static_cast<INSTRUMENTINDEX>(nID - ID_SELECTINST);
- }
- void CAbstractVstEditor::OnCreateInstrument()
- {
- if(m_VstPlugin.GetModDoc() != nullptr)
- {
- INSTRUMENTINDEX instr = m_VstPlugin.GetModDoc()->InsertInstrumentForPlugin(m_VstPlugin.GetSlot());
- if(instr != INSTRUMENTINDEX_INVALID) m_nInstrument = instr;
- }
- }
- void CAbstractVstEditor::PrepareToLearnMacro(UINT nID)
- {
- m_nLearnMacro = (nID-ID_LEARN_MACRO_FROM_PLUGGUI);
- //Now we wait for a param to be touched. We'll get the message from the VST Plug Manager.
- //Then pModDoc->LearnMacro(macro, param) is called
- }
- void CAbstractVstEditor::SetLearnMacro(int inMacro)
- {
- if (inMacro < kSFxMacros)
- {
- m_nLearnMacro=inMacro;
- }
- }
- int CAbstractVstEditor::GetLearnMacro()
- {
- return m_nLearnMacro;
- }
- void CAbstractVstEditor::OnMove(int, int)
- {
- if(IsWindowVisible())
- {
- StoreWindowPos();
- }
- }
- void CAbstractVstEditor::StoreWindowPos()
- {
- if(m_hWnd)
- {
- WINDOWPLACEMENT wnd;
- wnd.length = sizeof(WINDOWPLACEMENT);
- GetWindowPlacement(&wnd);
- m_VstPlugin.SetEditorPos(wnd.rcNormalPosition.left, wnd.rcNormalPosition.top);
- }
- }
- void CAbstractVstEditor::RestoreWindowPos()
- {
- // Restore previous editor position
- int32 editorX, editorY;
- m_VstPlugin.GetEditorPos(editorX, editorY);
- if(editorX != int32_min && editorY != int32_min)
- {
- WINDOWPLACEMENT wnd;
- wnd.length = sizeof(wnd);
- GetWindowPlacement(&wnd);
- wnd.showCmd = SW_SHOWNOACTIVATE;
- CRect rect = wnd.rcNormalPosition;
- rect.MoveToXY(editorX, editorY);
- wnd.rcNormalPosition = rect;
- SetWindowPlacement(&wnd);
- }
- }
- #endif // NO_PLUGINS
- OPENMPT_NAMESPACE_END
|