Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2025 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "vstactionscontroller.h"
24 :
25 : #include "rcommand/actiontocommand.h"
26 :
27 : #include "../vstcommands.h"
28 : #include "../widgets/vstviewdialog_qwidget.h"
29 :
30 : #include "ivstplugininstance.h"
31 :
32 : #include "log.h"
33 :
34 : using namespace muse;
35 : using namespace muse::vst;
36 :
37 : static const char16_t* VST_EDITOR_URI = u"muse://vst/editor?instanceId=%1&modal=false&floating=true";
38 :
39 0 : void VstActionsController::init()
40 : {
41 0 : auto cd = commandDispatcher();
42 0 : cd->onRequest(this, VST_USE_OLDVIEW_COMMAND, [this]() { useView(false); return muse::make_ok(); });
43 0 : cd->onRequest(this, VST_USE_NEWVIEW_COMMAND, [this]() { useView(true); return muse::make_ok(); });
44 0 : cd->onRequest(this, VST_OPEN_FX_EDITOR_COMMAND, [this](const rcommand::Params& params) { return fxEditor(params); });
45 0 : cd->onRequest(this, VST_OPEN_INSTRUMENT_EDITOR_COMMAND, [this](const rcommand::Params& params) { return instEditor(params); });
46 :
47 : // compat
48 : {
49 : using namespace muse::rcommand;
50 : static const std::vector<ActionToCommand> actionToCommands = {
51 0 : { "vst-use-oldview", VST_USE_OLDVIEW_COMMAND, {} },
52 : { "vst-use-newview", VST_USE_NEWVIEW_COMMAND, {} }
53 0 : };
54 :
55 0 : rcommand::registerActionToCommand(this, actionToCommands, commandDispatcher(), dispatcher());
56 :
57 : static const std::vector<std::pair<actions::ActionQuery, Command> > actionQueryToCommands = {
58 0 : { actions::ActionQuery("action://vst/fx_editor"), VST_OPEN_FX_EDITOR_COMMAND },
59 0 : { actions::ActionQuery("action://vst/instrument_editor"), VST_OPEN_INSTRUMENT_EDITOR_COMMAND }
60 0 : };
61 :
62 0 : for (const auto& [actionQuery, command] : actionQueryToCommands) {
63 0 : dispatcher()->reg(this, actionQuery, [this, command](const actions::ActionQuery& aquery) {
64 0 : CommandQuery query(command);
65 0 : query.setParams(aquery.params());
66 0 : commandDispatcher()->dispatch(query);
67 0 : });
68 : }
69 : }
70 0 : }
71 :
72 0 : muse::Ret VstActionsController::fxEditor(const rcommand::Params& params)
73 : {
74 : #ifdef Q_OS_LINUX
75 0 : if (!isUsedNewView()) {
76 0 : LOGW() << "Old (QWidget) VST View not support Linux";
77 0 : return make_ret(Ret::Code::NotSupported);
78 : }
79 : #endif
80 :
81 0 : std::string resourceId = params.at("resourceId").toString();
82 0 : IF_ASSERT_FAILED(!resourceId.empty()) {
83 0 : LOGE() << "not set resourceId";
84 0 : return make_ret(Ret::Code::BadArgs);
85 : }
86 :
87 0 : int trackId = params.at("trackId", Val(-1)).toInt();
88 0 : int chainOrder = params.at("chainOrder", Val(0)).toInt();
89 0 : std::string operation = params.at("operation", Val("open")).toString();
90 0 : bool sync = params.at("sync", Val(false)).toBool();
91 :
92 0 : auto instance = instancesRegister()->fxPlugin(resourceId, trackId, chainOrder);
93 :
94 0 : if (operation == "close" && !instance) {
95 0 : return make_ret(Ret::Code::BadArgs);
96 : }
97 :
98 0 : IF_ASSERT_FAILED(instance) {
99 0 : LOGE() << "not found instance, resourceId: " << resourceId
100 0 : << ", trackId: " << trackId << ", chainOrder: " << chainOrder;
101 0 : return make_ret(Ret::Code::BadArgs);
102 : }
103 :
104 0 : editorOperation(operation, instance->id(), sync);
105 0 : return make_ok();
106 0 : }
107 :
108 0 : muse::Ret VstActionsController::instEditor(const rcommand::Params& params)
109 : {
110 : #ifdef Q_OS_LINUX
111 0 : if (!isUsedNewView()) {
112 0 : LOGW() << "Old (QWidget) VST View not support Linux";
113 0 : return make_ret(Ret::Code::NotSupported);
114 : }
115 : #endif
116 :
117 0 : std::string resourceId = params.at("resourceId").toString();
118 0 : IF_ASSERT_FAILED(!resourceId.empty()) {
119 0 : LOGE() << "not set resourceId";
120 0 : return make_ret(Ret::Code::BadArgs);
121 : }
122 :
123 0 : int trackId = params.at("trackId", Val(-1)).toInt();
124 :
125 0 : auto instance = instancesRegister()->instrumentPlugin(resourceId, trackId);
126 :
127 0 : std::string operation = params.at("operation", Val("open")).toString();
128 0 : bool sync = params.at("sync", Val(false)).toBool();
129 :
130 0 : if (operation == "close" && !instance) {
131 0 : return make_ret(Ret::Code::BadArgs);
132 : }
133 :
134 0 : IF_ASSERT_FAILED(instance) {
135 0 : LOGE() << "not found instance, resourceId: " << resourceId
136 0 : << ", trackId: " << trackId;
137 0 : return make_ret(Ret::Code::BadArgs);
138 : }
139 :
140 0 : editorOperation(operation, instance->id(), sync);
141 0 : return make_ok();
142 0 : }
143 :
144 0 : void VstActionsController::editorOperation(const std::string& operation, int instanceId, bool sync)
145 : {
146 0 : UriQuery editorUri = UriQuery(String(VST_EDITOR_URI).arg(instanceId));
147 :
148 0 : if (operation == "close") {
149 0 : if (sync) {
150 0 : interactive()->closeSync(editorUri);
151 : } else {
152 0 : interactive()->close(editorUri);
153 : }
154 0 : return;
155 : }
156 :
157 0 : if (interactive()->isOpened(editorUri).val) {
158 0 : interactive()->raise(editorUri);
159 0 : } else if (sync) {
160 0 : interactive()->openSync(editorUri);
161 : } else {
162 0 : interactive()->open(editorUri);
163 : }
164 0 : }
165 :
166 0 : void VstActionsController::setupUsedView()
167 : {
168 0 : useView(configuration()->usedVstView() == "newview");
169 0 : }
170 :
171 0 : void VstActionsController::useView(bool isNew)
172 : {
173 0 : interactiveUriRegister()->unregisterUri(Uri("muse://vst/editor"));
174 :
175 0 : if (isNew) {
176 0 : configuration()->setUsedVstView("newview");
177 0 : interactiveUriRegister()->registerQmlUri(Uri("muse://vst/editor"), "Muse.Vst", "VstEditorDialog");
178 : } else {
179 0 : configuration()->setUsedVstView("oldview");
180 0 : interactiveUriRegister()->registerWidgetUri<VstViewDialog>(Uri("muse://vst/editor"));
181 : }
182 :
183 0 : m_actionCheckedChanged.send({ "vst-use-oldview", "vst-use-newview" });
184 0 : }
185 :
186 0 : bool VstActionsController::isUsedNewView() const
187 : {
188 0 : return configuration()->usedVstView() == "newview";
189 : }
190 :
191 0 : bool VstActionsController::actionChecked(const actions::ActionCode& act) const
192 : {
193 0 : if (act == "vst-use-oldview") {
194 0 : return !isUsedNewView();
195 0 : } else if (act == "vst-use-newview") {
196 0 : return isUsedNewView();
197 : }
198 :
199 0 : return false;
200 : }
201 :
202 0 : async::Channel<actions::ActionCodeList> VstActionsController::actionCheckedChanged() const
203 : {
204 0 : return m_actionCheckedChanged;
205 : }
|