Bitwig workarounds for VST
This commit is contained in:
parent
a002b994f4
commit
d763ebde83
7 changed files with 241 additions and 142 deletions
|
|
@ -4,6 +4,8 @@ set (VSTPLUGIN_BUNDLE_NAME "${PROJECT_NAME}.vst3")
|
|||
set (VST3SDK_BASEDIR "${CMAKE_CURRENT_SOURCE_DIR}/external/VST_SDK/VST3_SDK")
|
||||
set (VST3SDK_ARCHIVE "vst-sdk_3.6.14_build-24_2019-11-29.zip")
|
||||
|
||||
file (MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/external")
|
||||
|
||||
if (NOT EXISTS "${VST3SDK_BASEDIR}")
|
||||
message (STATUS "VST3 SDK is not found, downloading")
|
||||
|
||||
|
|
@ -41,7 +43,8 @@ add_library(${VSTPLUGIN_PRJ_NAME} MODULE
|
|||
SfizzVstEditor.cpp
|
||||
SfizzVstState.cpp
|
||||
GUIComponents.cpp
|
||||
VstPluginFactory.cpp)
|
||||
VstPluginFactory.cpp
|
||||
X11RunLoop.cpp)
|
||||
|
||||
if(WIN32)
|
||||
target_sources(${VSTPLUGIN_PRJ_NAME} PRIVATE vst3.def)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#include "SfizzVstState.h"
|
||||
#include "GUIComponents.h"
|
||||
#if !defined(__APPLE__) && !defined(_WIN32)
|
||||
#include "x11runloop.h"
|
||||
#include "X11RunLoop.h"
|
||||
#endif
|
||||
|
||||
using namespace VSTGUI;
|
||||
|
|
@ -39,7 +39,9 @@ bool PLUGIN_API SfizzVstEditor::open(void* parent, const VSTGUI::PlatformType& p
|
|||
|
||||
#if !defined(__APPLE__) && !defined(_WIN32)
|
||||
X11::FrameConfig x11config;
|
||||
x11config.runLoop = VSTGUI::owned(new RunLoop(plugFrame));
|
||||
if (!_runLoop)
|
||||
_runLoop = new RunLoop(plugFrame);
|
||||
x11config.runLoop = _runLoop;
|
||||
config = &x11config;
|
||||
#endif
|
||||
|
||||
|
|
@ -58,8 +60,13 @@ void PLUGIN_API SfizzVstEditor::close()
|
|||
{
|
||||
CFrame *frame = this->frame;
|
||||
if (frame) {
|
||||
frame->forget();
|
||||
this->frame = nullptr;
|
||||
frame->removeAll();
|
||||
if (frame->getNbReference() != 1)
|
||||
frame->forget ();
|
||||
else {
|
||||
frame->close();
|
||||
this->frame = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -136,6 +143,30 @@ void SfizzVstEditor::controlEndEdit(CControl* ctl)
|
|||
enterOrLeaveEdit(ctl, false);
|
||||
}
|
||||
|
||||
CMessageResult SfizzVstEditor::notify(CBaseObject* sender, const char* message)
|
||||
{
|
||||
CMessageResult result = VSTGUIEditor::notify(sender, message);
|
||||
|
||||
if (result != kMessageNotified)
|
||||
return result;
|
||||
|
||||
#if !defined(__APPLE__) && !defined(_WIN32)
|
||||
if (message == CVSTGUITimer::kMsgTimer) {
|
||||
SharedPointer<VSTGUI::RunLoop> runLoop = RunLoop::get();
|
||||
if (runLoop) {
|
||||
// note(jpc) I don't find a reliable way to check if the host
|
||||
// notifier of X11 events is working. If there is, remove this and
|
||||
// avoid polluting Linux hosts which implement the loop correctly.
|
||||
runLoop->processSomeEvents();
|
||||
|
||||
runLoop->cleanupDeadHandlers();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void SfizzVstEditor::onStateChanged()
|
||||
{
|
||||
updateStateDisplay();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
#pragma once
|
||||
#include "SfizzVstController.h"
|
||||
#include "public.sdk/source/vst/vstguieditor.h"
|
||||
#if !defined(__APPLE__) && !defined(_WIN32)
|
||||
namespace VSTGUI { class RunLoop; }
|
||||
#endif
|
||||
|
||||
using namespace Steinberg;
|
||||
using namespace VSTGUI;
|
||||
|
|
@ -30,6 +33,9 @@ public:
|
|||
void controlBeginEdit(CControl* ctl) override;
|
||||
void controlEndEdit(CControl* ctl) override;
|
||||
|
||||
// VSTGUIEditor
|
||||
CMessageResult notify(CBaseObject* sender, const char* message) override;
|
||||
|
||||
// SfizzVstController::StateListener
|
||||
void onStateChanged() override;
|
||||
|
||||
|
|
@ -75,4 +81,8 @@ private:
|
|||
CSliderBase *_numVoicesSlider = nullptr;
|
||||
CSliderBase *_oversamplingSlider = nullptr;
|
||||
CSliderBase *_preloadSizeSlider = nullptr;
|
||||
|
||||
#if !defined(__APPLE__) && !defined(_WIN32)
|
||||
SharedPointer<RunLoop> _runLoop;
|
||||
#endif
|
||||
};
|
||||
|
|
|
|||
145
vst/X11RunLoop.cpp
Normal file
145
vst/X11RunLoop.cpp
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
// SPDX-License-Identifier: GPL-3.0
|
||||
|
||||
#if !defined(__APPLE__) && !defined(_WIN32)
|
||||
#include "X11RunLoop.h"
|
||||
#include "vstgui/lib/platform/linux/x11platform.h"
|
||||
#include "base/source/fobject.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
RunLoop::RunLoop(Steinberg::FUnknown* runLoop)
|
||||
: runLoop(runLoop)
|
||||
{
|
||||
}
|
||||
|
||||
RunLoop::~RunLoop() {}
|
||||
|
||||
SharedPointer<RunLoop> RunLoop::get()
|
||||
{
|
||||
return X11::RunLoop::get().cast<VSTGUI::RunLoop>();
|
||||
}
|
||||
|
||||
struct RunLoop::EventHandler final : Steinberg::Linux::IEventHandler, public Steinberg::FObject {
|
||||
X11::IEventHandler* handler { nullptr };
|
||||
bool alive { false };
|
||||
|
||||
void PLUGIN_API onFDIsSet(Steinberg::Linux::FileDescriptor) override
|
||||
{
|
||||
if (alive && handler)
|
||||
handler->onEvent();
|
||||
}
|
||||
|
||||
DELEGATE_REFCOUNT(Steinberg::FObject)
|
||||
DEFINE_INTERFACES
|
||||
DEF_INTERFACE(Steinberg::Linux::IEventHandler)
|
||||
END_DEFINE_INTERFACES(Steinberg::FObject)
|
||||
};
|
||||
|
||||
struct RunLoop::TimerHandler final : Steinberg::Linux::ITimerHandler, public Steinberg::FObject {
|
||||
X11::ITimerHandler* handler { nullptr };
|
||||
bool alive { false };
|
||||
|
||||
void PLUGIN_API onTimer() override
|
||||
{
|
||||
if (alive && handler)
|
||||
handler->onTimer();
|
||||
}
|
||||
|
||||
DELEGATE_REFCOUNT(Steinberg::FObject)
|
||||
DEFINE_INTERFACES
|
||||
DEF_INTERFACE(Steinberg::Linux::ITimerHandler)
|
||||
END_DEFINE_INTERFACES(Steinberg::FObject)
|
||||
};
|
||||
|
||||
|
||||
void RunLoop::processSomeEvents()
|
||||
{
|
||||
for (size_t i = 0; i < eventHandlers.size(); ++i) {
|
||||
const auto& eh = eventHandlers[i];
|
||||
if (eh->alive && eh->handler) {
|
||||
eh->handler->onEvent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RunLoop::cleanupDeadHandlers()
|
||||
{
|
||||
for (size_t i = 0; i < eventHandlers.size(); ++i) {
|
||||
const auto& eh = eventHandlers[i];
|
||||
if (!eh->alive) {
|
||||
runLoop->unregisterEventHandler(eh);
|
||||
eventHandlers.erase(eventHandlers.begin() + i--);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < timerHandlers.size(); ++i) {
|
||||
const auto& th = timerHandlers[i];
|
||||
if (!th->alive) {
|
||||
runLoop->unregisterTimer(th);
|
||||
timerHandlers.erase(timerHandlers.begin() + i--);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RunLoop::registerEventHandler(int fd, X11::IEventHandler* handler)
|
||||
{
|
||||
if (!runLoop)
|
||||
return false;
|
||||
|
||||
auto smtgHandler = Steinberg::owned(new EventHandler());
|
||||
smtgHandler->handler = handler;
|
||||
smtgHandler->alive = true;
|
||||
if (runLoop->registerEventHandler(smtgHandler, fd) == Steinberg::kResultTrue) {
|
||||
eventHandlers.push_back(smtgHandler);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RunLoop::unregisterEventHandler(X11::IEventHandler* handler)
|
||||
{
|
||||
if (!runLoop)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < eventHandlers.size(); ++i) {
|
||||
const auto& eh = eventHandlers[i];
|
||||
if (eh->alive && eh->handler == handler) {
|
||||
eh->alive = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RunLoop::registerTimer(uint64_t interval, X11::ITimerHandler* handler)
|
||||
{
|
||||
if (!runLoop)
|
||||
return false;
|
||||
|
||||
auto smtgHandler = Steinberg::owned(new TimerHandler());
|
||||
smtgHandler->handler = handler;
|
||||
smtgHandler->alive = true;
|
||||
if (runLoop->registerTimer(smtgHandler, interval) == Steinberg::kResultTrue) {
|
||||
timerHandlers.push_back(smtgHandler);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RunLoop::unregisterTimer(X11::ITimerHandler* handler)
|
||||
{
|
||||
if (!runLoop)
|
||||
return false;
|
||||
|
||||
for (size_t i = 0; i < timerHandlers.size(); ++i) {
|
||||
const auto& th = timerHandlers[i];
|
||||
if (th->alive && th->handler == handler) {
|
||||
th->alive = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace VSTGUI
|
||||
|
||||
#endif
|
||||
47
vst/X11RunLoop.h
Normal file
47
vst/X11RunLoop.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// SPDX-License-Identifier: GPL-3.0
|
||||
/*
|
||||
This is a modified version the X11 run loop from vst3editor.cpp.
|
||||
|
||||
This version is edited to add more safeguards to protect against host bugs.
|
||||
It also permits to call event processing externally in case the host has a
|
||||
defective X11 event loop notifier.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#if !defined(__APPLE__) && !defined(_WIN32)
|
||||
#include "vstgui/lib/platform/linux/x11frame.h"
|
||||
#include "pluginterfaces/gui/iplugview.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
class RunLoop final : public X11::IRunLoop, public AtomicReferenceCounted {
|
||||
public:
|
||||
explicit RunLoop(Steinberg::FUnknown* runLoop);
|
||||
~RunLoop();
|
||||
|
||||
static SharedPointer<RunLoop> get();
|
||||
|
||||
void processSomeEvents();
|
||||
void cleanupDeadHandlers();
|
||||
|
||||
// X11::IRunLoop
|
||||
bool registerEventHandler(int fd, X11::IEventHandler* handler);
|
||||
bool unregisterEventHandler(X11::IEventHandler* handler);
|
||||
bool registerTimer(uint64_t interval, X11::ITimerHandler* handler);
|
||||
bool unregisterTimer(X11::ITimerHandler* handler);
|
||||
|
||||
private:
|
||||
struct EventHandler;
|
||||
struct TimerHandler;
|
||||
|
||||
private:
|
||||
using EventHandlers = std::vector<Steinberg::IPtr<EventHandler>>;
|
||||
using TimerHandlers = std::vector<Steinberg::IPtr<TimerHandler>>;
|
||||
EventHandlers eventHandlers;
|
||||
TimerHandlers timerHandlers;
|
||||
Steinberg::FUnknownPtr<Steinberg::Linux::IRunLoop> runLoop;
|
||||
};
|
||||
|
||||
} // namespace VSTGUI
|
||||
|
||||
#endif
|
||||
27
vst/external/steinberg/LICENSE
vendored
27
vst/external/steinberg/LICENSE
vendored
|
|
@ -1,27 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// VSTGUI LICENSE
|
||||
// (c) 2018, Steinberg Media Technologies, All Rights Reserved
|
||||
//-----------------------------------------------------------------------------
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Steinberg Media Technologies nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//-----------------------------------------------------------------------------
|
||||
110
vst/external/steinberg/src/x11runloop.h
vendored
110
vst/external/steinberg/src/x11runloop.h
vendored
|
|
@ -1,110 +0,0 @@
|
|||
#include "vstgui/lib/platform/linux/x11frame.h"
|
||||
#include "pluginterfaces/gui/iplugview.h"
|
||||
#include "base/source/fstring.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
// Map Steinberg Vst Interface to VSTGUI Interface
|
||||
class RunLoop : public X11::IRunLoop, public AtomicReferenceCounted
|
||||
{
|
||||
public:
|
||||
struct EventHandler : Steinberg::Linux::IEventHandler, public Steinberg::FObject
|
||||
{
|
||||
X11::IEventHandler* handler {nullptr};
|
||||
|
||||
void PLUGIN_API onFDIsSet (Steinberg::Linux::FileDescriptor) override
|
||||
{
|
||||
if (handler)
|
||||
handler->onEvent ();
|
||||
}
|
||||
DELEGATE_REFCOUNT (Steinberg::FObject)
|
||||
DEFINE_INTERFACES
|
||||
DEF_INTERFACE (Steinberg::Linux::IEventHandler)
|
||||
END_DEFINE_INTERFACES (Steinberg::FObject)
|
||||
};
|
||||
struct TimerHandler : Steinberg::Linux::ITimerHandler, public Steinberg::FObject
|
||||
{
|
||||
X11::ITimerHandler* handler {nullptr};
|
||||
|
||||
void PLUGIN_API onTimer () final
|
||||
{
|
||||
if (handler)
|
||||
handler->onTimer ();
|
||||
}
|
||||
DELEGATE_REFCOUNT (Steinberg::FObject)
|
||||
DEFINE_INTERFACES
|
||||
DEF_INTERFACE (Steinberg::Linux::ITimerHandler)
|
||||
END_DEFINE_INTERFACES (Steinberg::FObject)
|
||||
};
|
||||
|
||||
bool registerEventHandler (int fd, X11::IEventHandler* handler) final
|
||||
{
|
||||
if(!runLoop)
|
||||
return false;
|
||||
|
||||
auto smtgHandler = Steinberg::owned (new EventHandler ());
|
||||
smtgHandler->handler = handler;
|
||||
if (runLoop->registerEventHandler (smtgHandler, fd) == Steinberg::kResultTrue)
|
||||
{
|
||||
eventHandlers.push_back (smtgHandler);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool unregisterEventHandler (X11::IEventHandler* handler) final
|
||||
{
|
||||
if(!runLoop)
|
||||
return false;
|
||||
|
||||
for (auto it = eventHandlers.begin (), end = eventHandlers.end (); it != end; ++it)
|
||||
{
|
||||
if ((*it)->handler == handler)
|
||||
{
|
||||
runLoop->unregisterEventHandler ((*it));
|
||||
eventHandlers.erase (it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool registerTimer (uint64_t interval, X11::ITimerHandler* handler) final
|
||||
{
|
||||
if(!runLoop)
|
||||
return false;
|
||||
|
||||
auto smtgHandler = Steinberg::owned (new TimerHandler ());
|
||||
smtgHandler->handler = handler;
|
||||
if (runLoop->registerTimer (smtgHandler, interval) == Steinberg::kResultTrue)
|
||||
{
|
||||
timerHandlers.push_back (smtgHandler);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool unregisterTimer (X11::ITimerHandler* handler) final
|
||||
{
|
||||
if(!runLoop)
|
||||
return false;
|
||||
|
||||
for (auto it = timerHandlers.begin (), end = timerHandlers.end (); it != end; ++it)
|
||||
{
|
||||
if ((*it)->handler == handler)
|
||||
{
|
||||
runLoop->unregisterTimer ((*it));
|
||||
timerHandlers.erase (it);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
RunLoop (Steinberg::FUnknown* runLoop) : runLoop (runLoop) {}
|
||||
private:
|
||||
using EventHandlers = std::vector<Steinberg::IPtr<EventHandler>>;
|
||||
using TimerHandlers = std::vector<Steinberg::IPtr<TimerHandler>>;
|
||||
EventHandlers eventHandlers;
|
||||
TimerHandlers timerHandlers;
|
||||
Steinberg::FUnknownPtr<Steinberg::Linux::IRunLoop> runLoop;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
Loading…
Add table
Reference in a new issue