Skip to content

Commit

Permalink
Bitwig workarounds for VST
Browse files Browse the repository at this point in the history
  • Loading branch information
jpcima committed Mar 11, 2020
1 parent a002b99 commit 517a305
Show file tree
Hide file tree
Showing 7 changed files with 235 additions and 142 deletions.
5 changes: 4 additions & 1 deletion vst/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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")

Expand Down Expand Up @@ -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)
Expand Down
39 changes: 35 additions & 4 deletions vst/SfizzVstEditor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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

Expand All @@ -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;
}
}
}

Expand Down Expand Up @@ -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();
Expand Down
10 changes: 10 additions & 0 deletions vst/SfizzVstEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,6 +33,9 @@ class SfizzVstEditor : public Vst::VSTGUIEditor, public IControlListener, 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;

Expand Down Expand Up @@ -75,4 +81,8 @@ class SfizzVstEditor : public Vst::VSTGUIEditor, public IControlListener, public
CSliderBase *_numVoicesSlider = nullptr;
CSliderBase *_oversamplingSlider = nullptr;
CSliderBase *_preloadSizeSlider = nullptr;

#if !defined(__APPLE__) && !defined(_WIN32)
SharedPointer<RunLoop> _runLoop;
#endif
};
142 changes: 142 additions & 0 deletions vst/X11RunLoop.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// SPDX-License-Identifier: GPL-3.0

#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
44 changes: 44 additions & 0 deletions vst/X11RunLoop.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// 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
#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
27 changes: 0 additions & 27 deletions vst/external/steinberg/LICENSE

This file was deleted.

Loading

0 comments on commit 517a305

Please sign in to comment.