Native linux VST support (#6048)
Co-authored-by: Dominic Clark <mrdomclark@gmail.com>
This commit is contained in:
@@ -36,7 +36,6 @@
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
|
||||
#if !(defined(LMMS_HAVE_SYS_IPC_H) && defined(LMMS_HAVE_SEMAPHORE_H))
|
||||
#define SYNC_WITH_SHM_FIFO
|
||||
#define USE_QT_SEMAPHORES
|
||||
@@ -440,6 +439,7 @@ enum RemoteMessageIDs
|
||||
IdSavePresetFile,
|
||||
IdLoadPresetFile,
|
||||
IdDebugMessage,
|
||||
IdIdle,
|
||||
IdUserBase = 64
|
||||
} ;
|
||||
|
||||
@@ -1000,7 +1000,6 @@ private:
|
||||
|
||||
sample_rate_t m_sampleRate;
|
||||
fpp_t m_bufferSize;
|
||||
|
||||
} ;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,7 +30,11 @@
|
||||
#include <type_traits>
|
||||
|
||||
// Calling convention
|
||||
#ifdef _WIN32
|
||||
#define VST_CALL_CONV __cdecl
|
||||
#else
|
||||
#define VST_CALL_CONV
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
constexpr int32_t CCONST(T a, T b, T c, T d)
|
||||
|
||||
@@ -78,7 +78,11 @@ Plugin::Descriptor Q_DECL_EXPORT vestige_plugin_descriptor =
|
||||
0x0100,
|
||||
Plugin::Instrument,
|
||||
new PluginPixmapLoader( "logo" ),
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
"dll,so",
|
||||
#else
|
||||
"dll",
|
||||
#endif
|
||||
nullptr,
|
||||
} ;
|
||||
|
||||
@@ -682,6 +686,9 @@ void VestigeInstrumentView::openPlugin()
|
||||
QStringList types;
|
||||
types << tr( "DLL-files (*.dll)" )
|
||||
<< tr( "EXE-files (*.exe)" )
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
<< tr( "SO-files (*.so)" )
|
||||
#endif
|
||||
;
|
||||
ofd.setNameFilters( types );
|
||||
|
||||
|
||||
@@ -8,6 +8,10 @@ INCLUDE(ExternalProject)
|
||||
# These variables are not meant to be used normally, except packaging
|
||||
SET(REMOTE_VST_PLUGIN_FILEPATH_32 "32/RemoteVstPlugin32" CACHE STRING "Relative file path to RemoteVstPlugin32")
|
||||
SET(REMOTE_VST_PLUGIN_FILEPATH_64 "RemoteVstPlugin64" CACHE STRING "Relative file path to RemoteVstPlugin64")
|
||||
IF(LMMS_BUILD_LINUX)
|
||||
SET(NATIVE_LINUX_REMOTE_VST_PLUGIN_FILEPATH_64 "NativeLinuxRemoteVstPlugin64"
|
||||
CACHE STRING "Relative file path to NativeLinuxRemoteVstPlugin64")
|
||||
ENDIF()
|
||||
|
||||
ADD_SUBDIRECTORY(vstbase)
|
||||
|
||||
@@ -48,3 +52,7 @@ ENDIF()
|
||||
IF(WANT_VST_64)
|
||||
INCLUDE("${CMAKE_CURRENT_LIST_DIR}/RemoteVstPlugin64.cmake")
|
||||
ENDIF()
|
||||
|
||||
IF(LMMS_BUILD_LINUX)
|
||||
INCLUDE("${CMAKE_CURRENT_LIST_DIR}/NativeLinuxRemoteVstPlugin64.cmake")
|
||||
ENDIF()
|
||||
|
||||
11
plugins/vst_base/NativeLinuxRemoteVstPlugin64.cmake
Normal file
11
plugins/vst_base/NativeLinuxRemoteVstPlugin64.cmake
Normal file
@@ -0,0 +1,11 @@
|
||||
IF(LMMS_BUILD_LINUX)
|
||||
ExternalProject_Add(NativeLinuxRemoteVstPlugin64
|
||||
"${EXTERNALPROJECT_ARGS}"
|
||||
CMAKE_ARGS
|
||||
"${EXTERNALPROJECT_CMAKE_ARGS}"
|
||||
"-DCMAKE_CXX_FLAGS=-m64 -DNATIVE_LINUX_VST"
|
||||
"-DCMAKE_C_FLAGS=-DNATIVE_LINUX_VST"
|
||||
)
|
||||
INSTALL(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/../NativeLinuxRemoteVstPlugin64" DESTINATION "${PLUGIN_DIR}")
|
||||
ENDIF()
|
||||
|
||||
@@ -10,6 +10,9 @@
|
||||
* Copyright (c) 2004 Torben Hohn
|
||||
* Copyright (c) 2002 Kjetil S. Matheussen
|
||||
*
|
||||
* X11 code partly taken from https://github.com/ekenberg/vstminihost:
|
||||
* Copyright (c) 2012 Johan Ekenberg
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
@@ -52,12 +55,39 @@
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
#include <wine/exception.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
#define USE_WS_PREFIX
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xos.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/Xatom.h>
|
||||
#include <sstream>
|
||||
#include <time.h>
|
||||
|
||||
// https://stackoverflow.com/questions/22476110/c-compiling-error-including-x11-x-h-x11-xlib-h
|
||||
#undef Bool
|
||||
#undef CursorShape
|
||||
#undef Expose
|
||||
#undef KeyPress
|
||||
#undef KeyRelease
|
||||
#undef FocusIn
|
||||
#undef FocusOut
|
||||
#undef FontChange
|
||||
#undef None
|
||||
#undef Status
|
||||
#undef Unsorted
|
||||
#endif
|
||||
|
||||
#ifdef USE_MINGW_THREADS_REPLACEMENT
|
||||
# include <mingw.mutex.h>
|
||||
@@ -122,10 +152,14 @@ class RemoteVstPlugin;
|
||||
|
||||
RemoteVstPlugin * __plugin = nullptr;
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
HWND __MessageHwnd = nullptr;
|
||||
DWORD __processingThreadId = 0;
|
||||
#else
|
||||
pthread_t __processingThreadId = 0;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
|
||||
std::string GetErrorAsString(DWORD errorMessageID)
|
||||
{
|
||||
@@ -144,7 +178,7 @@ std::string GetErrorAsString(DWORD errorMessageID)
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
class RemoteVstPlugin : public RemotePluginClient
|
||||
{
|
||||
@@ -318,7 +352,13 @@ public:
|
||||
}
|
||||
|
||||
inline void queueMessage( const message & m ) {
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
pthread_mutex_lock(&message_mutex);
|
||||
#endif
|
||||
m_messageList.push( m );
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
pthread_mutex_unlock(&message_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool shouldGiveIdle() const
|
||||
@@ -333,13 +373,28 @@ public:
|
||||
|
||||
void idle();
|
||||
void processUIThreadMessages();
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
void sendX11Idle();
|
||||
#endif
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
static DWORD WINAPI processingThread( LPVOID _param );
|
||||
#else
|
||||
static void * processingThread( void * _param );
|
||||
#endif
|
||||
|
||||
static bool setupMessageWindow();
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
static DWORD WINAPI guiEventLoop();
|
||||
#else
|
||||
void guiEventLoop();
|
||||
#endif
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
static LRESULT CALLBACK wndProc( HWND hwnd, UINT uMsg,
|
||||
WPARAM wParam, LPARAM lParam );
|
||||
|
||||
#endif
|
||||
|
||||
private:
|
||||
enum GuiThreadMessages
|
||||
@@ -389,10 +444,21 @@ private:
|
||||
|
||||
std::string m_shortName;
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
HINSTANCE m_libInst;
|
||||
#else
|
||||
void* m_libInst = nullptr;
|
||||
#endif
|
||||
|
||||
AEffect * m_plugin;
|
||||
HWND m_window;
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
HWND m_window = nullptr;
|
||||
#else
|
||||
Window m_window = 0;
|
||||
Display* m_display = nullptr;
|
||||
Atom m_wmDeleteMessage;
|
||||
bool m_x11WindowVisible = false;
|
||||
#endif
|
||||
intptr_t m_windowID;
|
||||
int m_windowWidth;
|
||||
int m_windowHeight;
|
||||
@@ -402,6 +468,10 @@ private:
|
||||
|
||||
bool m_processing;
|
||||
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
pthread_mutex_t message_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
bool m_shouldQuit = false;
|
||||
#endif
|
||||
std::queue<message> m_messageList;
|
||||
bool m_shouldGiveIdle;
|
||||
|
||||
@@ -446,7 +516,6 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) :
|
||||
#endif
|
||||
m_libInst( nullptr ),
|
||||
m_plugin( nullptr ),
|
||||
m_window( nullptr ),
|
||||
m_windowID( 0 ),
|
||||
m_windowWidth( 0 ),
|
||||
m_windowHeight( 0 ),
|
||||
@@ -551,7 +620,11 @@ RemoteVstPlugin::~RemoteVstPlugin()
|
||||
|
||||
if( m_libInst != nullptr )
|
||||
{
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
FreeLibrary( m_libInst );
|
||||
#else
|
||||
dlclose(m_libInst);
|
||||
#endif
|
||||
m_libInst = nullptr;
|
||||
}
|
||||
|
||||
@@ -577,7 +650,11 @@ bool RemoteVstPlugin::processMessage( const message & _m )
|
||||
return true;
|
||||
|
||||
case IdToggleUI:
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
if( m_window && IsWindowVisible( m_window ) )
|
||||
#else
|
||||
if (m_window && m_x11WindowVisible)
|
||||
#endif
|
||||
{
|
||||
hideEditor();
|
||||
}
|
||||
@@ -585,10 +662,15 @@ bool RemoteVstPlugin::processMessage( const message & _m )
|
||||
{
|
||||
showEditor();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
case IdIsUIVisible:
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
bool visible = m_window && IsWindowVisible( m_window );
|
||||
#else
|
||||
bool visible = m_window && m_x11WindowVisible;
|
||||
#endif
|
||||
sendMessage( message( IdIsUIVisible )
|
||||
.addInt( visible ? 1 : 0 ) );
|
||||
return true;
|
||||
@@ -596,8 +678,10 @@ bool RemoteVstPlugin::processMessage( const message & _m )
|
||||
}
|
||||
else if (EMBED && _m.id == IdShowUI)
|
||||
{
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
ShowWindow( m_window, SW_SHOWNORMAL );
|
||||
UpdateWindow( m_window );
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -687,6 +771,21 @@ bool RemoteVstPlugin::processMessage( const message & _m )
|
||||
break;
|
||||
}
|
||||
|
||||
case IdIdle:
|
||||
{
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
idle();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
case IdQuit:
|
||||
{
|
||||
m_shouldQuit = true;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
return RemotePluginClient::processMessage( _m );
|
||||
}
|
||||
@@ -728,8 +827,8 @@ void RemoteVstPlugin::init( const std::string & _plugin_file )
|
||||
sendMessage( message( IdVstPluginEditorGeometry ).
|
||||
addInt( m_windowWidth ).
|
||||
addInt( m_windowHeight ) );
|
||||
|
||||
sendMessage( message( IdVstPluginName ).addString( pluginName() ) );
|
||||
debugMessage( std::string("plugin name: ") + pluginName() + "\n" );
|
||||
sendMessage( message( IdVstPluginVersion ).addInt( pluginVersion() ) );
|
||||
sendMessage( message( IdVstPluginVendorString ).
|
||||
addString( pluginVendorString() ) );
|
||||
@@ -740,6 +839,7 @@ void RemoteVstPlugin::init( const std::string & _plugin_file )
|
||||
|
||||
sendMessage( IdInitDone );
|
||||
|
||||
debugMessage( "initialization done\n" );
|
||||
m_initialized = true;
|
||||
}
|
||||
|
||||
@@ -765,7 +865,7 @@ void RemoteVstPlugin::initEditor()
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
HMODULE hInst = GetModuleHandle( nullptr );
|
||||
if( hInst == nullptr )
|
||||
{
|
||||
@@ -812,6 +912,46 @@ void RemoteVstPlugin::initEditor()
|
||||
// 64-bit versions of Windows use 32-bit handles for interoperability
|
||||
m_windowID = (intptr_t) m_window;
|
||||
#endif
|
||||
|
||||
#else
|
||||
XEvent e;
|
||||
Atom prop_atom, val_atom;
|
||||
|
||||
if (m_display == nullptr)
|
||||
{
|
||||
m_display = XOpenDisplay(nullptr);
|
||||
}
|
||||
m_window = XCreateSimpleWindow(m_display, DefaultRootWindow(m_display), 0, 0, 400, 400, 0, 0, 0);
|
||||
|
||||
m_wmDeleteMessage = XInternAtom(m_display, "WM_DELETE_WINDOW", false);
|
||||
XSetWMProtocols(m_display, m_window, &m_wmDeleteMessage, 1);
|
||||
|
||||
// make tool window
|
||||
prop_atom = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE", False);
|
||||
val_atom = XInternAtom(m_display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
||||
XChangeProperty(m_display, m_window, prop_atom, XA_ATOM, 32, PropModeReplace, (unsigned char *)&val_atom, 1);
|
||||
|
||||
// change name
|
||||
XStoreName(m_display, m_window, pluginName());
|
||||
|
||||
ERect * er;
|
||||
pluginDispatch(effEditGetRect, 0, 0, &er);
|
||||
|
||||
m_windowWidth = er->right - er->left;
|
||||
m_windowHeight = er->bottom - er->top;
|
||||
XResizeWindow(m_display, m_window, m_windowWidth, m_windowHeight);
|
||||
|
||||
XMapWindow(m_display, m_window);
|
||||
XFlush(m_display);
|
||||
|
||||
pluginDispatch(effEditOpen, 0, (intptr_t) m_display, (void*) m_window);
|
||||
|
||||
XSelectInput(m_display, m_window, SubstructureNotifyMask | ButtonPressMask | ButtonReleaseMask
|
||||
| ButtonMotionMask | ExposureMask | KeyPressMask);
|
||||
|
||||
pluginDispatch(effEditTop);
|
||||
m_x11WindowVisible = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -820,7 +960,16 @@ void RemoteVstPlugin::initEditor()
|
||||
void RemoteVstPlugin::showEditor() {
|
||||
if( !EMBED && !HEADLESS && m_window )
|
||||
{
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
ShowWindow( m_window, SW_SHOWNORMAL );
|
||||
#else
|
||||
if (!m_x11WindowVisible)
|
||||
{
|
||||
XMapWindow(m_display, m_window);
|
||||
XFlush(m_display);
|
||||
m_x11WindowVisible = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -830,7 +979,16 @@ void RemoteVstPlugin::showEditor() {
|
||||
void RemoteVstPlugin::hideEditor() {
|
||||
if( !EMBED && !HEADLESS && m_window )
|
||||
{
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
ShowWindow( m_window, SW_HIDE );
|
||||
#else
|
||||
if (m_x11WindowVisible)
|
||||
{
|
||||
XUnmapWindow(m_display, m_window);
|
||||
XFlush(m_display);
|
||||
m_x11WindowVisible = false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -839,15 +997,24 @@ void RemoteVstPlugin::hideEditor() {
|
||||
|
||||
void RemoteVstPlugin::destroyEditor()
|
||||
{
|
||||
if( m_window == nullptr )
|
||||
if( !m_window )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pluginDispatch( effEditClose );
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
// Destroying the window takes some time in Wine 1.8.5
|
||||
DestroyWindow( m_window );
|
||||
m_window = nullptr;
|
||||
#else
|
||||
if (m_display)
|
||||
{
|
||||
XCloseDisplay(m_display);
|
||||
}
|
||||
m_display = nullptr;
|
||||
m_window = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -855,15 +1022,24 @@ void RemoteVstPlugin::destroyEditor()
|
||||
|
||||
bool RemoteVstPlugin::load( const std::string & _plugin_file )
|
||||
{
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
if( ( m_libInst = LoadLibraryW( toWString(_plugin_file).c_str() ) ) == nullptr )
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
debugMessage( "LoadLibrary failed: " + GetErrorAsString(error) );
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
m_libInst = dlopen(_plugin_file.c_str(), RTLD_LAZY);
|
||||
if ( m_libInst == nullptr) {
|
||||
debugMessage( std::string("LoadLibrary failed: ") + dlerror() );
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
typedef AEffect * ( VST_CALL_CONV * mainEntryPointer )
|
||||
( audioMasterCallback );
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
mainEntryPointer mainEntry = (mainEntryPointer)
|
||||
GetProcAddress( m_libInst, "VSTPluginMain" );
|
||||
if( mainEntry == nullptr )
|
||||
@@ -876,6 +1052,14 @@ bool RemoteVstPlugin::load( const std::string & _plugin_file )
|
||||
mainEntry = (mainEntryPointer)
|
||||
GetProcAddress( m_libInst, "main" );
|
||||
}
|
||||
#else
|
||||
mainEntryPointer mainEntry = (mainEntryPointer) dlsym(m_libInst, "VSTPluginMain");
|
||||
if( mainEntry == nullptr )
|
||||
mainEntry = (mainEntryPointer) dlsym(m_libInst, "VstPluginMain");
|
||||
if( mainEntry == nullptr )
|
||||
mainEntry = (mainEntryPointer) dlsym(m_libInst, "main");
|
||||
#endif
|
||||
|
||||
if( mainEntry == nullptr )
|
||||
{
|
||||
debugMessage( "could not find entry point\n" );
|
||||
@@ -885,7 +1069,7 @@ bool RemoteVstPlugin::load( const std::string & _plugin_file )
|
||||
m_plugin = mainEntry( hostCallback );
|
||||
if( m_plugin == nullptr )
|
||||
{
|
||||
debugMessage( "mainEntry procedure returned NULL\n" );
|
||||
debugMessage( "mainEntry procedure returned nullptr\n" );
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1550,7 +1734,11 @@ int RemoteVstPlugin::updateInOutCount()
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
if( GetCurrentThreadId() == __processingThreadId )
|
||||
#else
|
||||
if( pthread_equal(pthread_self(), __processingThreadId) )
|
||||
#endif
|
||||
{
|
||||
debugMessage( "Plugin requested I/O change from processing "
|
||||
"thread. Request denied; stability may suffer.\n" );
|
||||
@@ -1643,7 +1831,11 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
|
||||
SHOW_CALLBACK ("amc: audioMasterIdle\n" );
|
||||
// call application idle routine (this will
|
||||
// call effEditIdle for all open editors too)
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
PostMessage( __MessageHwnd, WM_USER, GiveIdle, 0 );
|
||||
#else
|
||||
__plugin->sendX11Idle();
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
case audioMasterPinConnected:
|
||||
@@ -1663,7 +1855,7 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
|
||||
// items may require extensive conversions
|
||||
|
||||
// Shared memory was initialised? - see song.cpp
|
||||
//assert( __plugin->m_vstSyncData != NULL );
|
||||
//assert( __plugin->m_vstSyncData != nullptr );
|
||||
|
||||
memset( &_timeInfo, 0, sizeof( _timeInfo ) );
|
||||
_timeInfo.samplePos = __plugin->m_currentSamplePos;
|
||||
@@ -1840,6 +2032,7 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
|
||||
}
|
||||
__plugin->m_windowWidth = _index;
|
||||
__plugin->m_windowHeight = _value;
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
HWND window = __plugin->m_window;
|
||||
DWORD dwStyle = GetWindowLongPtr( window, GWL_STYLE );
|
||||
RECT windowSize = { 0, 0, (int) _index, (int) _value };
|
||||
@@ -1849,6 +2042,10 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
|
||||
windowSize.bottom - windowSize.top,
|
||||
SWP_NOACTIVATE | SWP_NOMOVE |
|
||||
SWP_NOOWNERZORDER | SWP_NOZORDER );
|
||||
#else
|
||||
XResizeWindow(__plugin->m_display, __plugin->m_window, (int) _index, (int) _value);
|
||||
XFlush(__plugin->m_display);
|
||||
#endif
|
||||
__plugin->sendMessage(
|
||||
message( IdVstPluginEditorGeometry ).
|
||||
addInt( __plugin->m_windowWidth ).
|
||||
@@ -1963,7 +2160,11 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode,
|
||||
case audioMasterUpdateDisplay:
|
||||
SHOW_CALLBACK( "amc: audioMasterUpdateDisplay\n" );
|
||||
// something has changed, update 'multi-fx' display
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
PostMessage( __MessageHwnd, WM_USER, GiveIdle, 0 );
|
||||
#else
|
||||
__plugin->sendX11Idle();
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
#if kVstVersion > 2
|
||||
@@ -2017,35 +2218,87 @@ void RemoteVstPlugin::idle()
|
||||
void RemoteVstPlugin::processUIThreadMessages()
|
||||
{
|
||||
setProcessing( true );
|
||||
while( m_messageList.size() )
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
pthread_mutex_lock(&message_mutex);
|
||||
#endif
|
||||
|
||||
size_t size = m_messageList.size();
|
||||
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
pthread_mutex_unlock(&message_mutex);
|
||||
#endif
|
||||
|
||||
while( size )
|
||||
{
|
||||
processMessage( m_messageList.front() );
|
||||
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
pthread_mutex_lock(&message_mutex);
|
||||
#endif
|
||||
|
||||
message m = m_messageList.front();
|
||||
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
pthread_mutex_unlock(&message_mutex);
|
||||
#endif
|
||||
|
||||
processMessage( m );
|
||||
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
pthread_mutex_lock(&message_mutex);
|
||||
#endif
|
||||
|
||||
m_messageList.pop();
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
pthread_mutex_unlock(&message_mutex);
|
||||
#endif
|
||||
if( shouldGiveIdle() )
|
||||
{
|
||||
pluginDispatch( effEditIdle );
|
||||
setShouldGiveIdle( false );
|
||||
}
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
pthread_mutex_lock(&message_mutex);
|
||||
#endif
|
||||
|
||||
size = m_messageList.size();
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
pthread_mutex_unlock(&message_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
setProcessing( false );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
DWORD WINAPI RemoteVstPlugin::processingThread( LPVOID _param )
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
void RemoteVstPlugin::sendX11Idle()
|
||||
{
|
||||
queueMessage(message( IdIdle ));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
DWORD WINAPI RemoteVstPlugin::processingThread( LPVOID _param )
|
||||
#else
|
||||
void * RemoteVstPlugin::processingThread(void * _param)
|
||||
#endif
|
||||
{
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
__processingThreadId = GetCurrentThreadId();
|
||||
#else
|
||||
__processingThreadId = pthread_self();
|
||||
#endif
|
||||
|
||||
RemoteVstPlugin * _this = static_cast<RemoteVstPlugin *>( _param );
|
||||
|
||||
RemotePluginClient::message m;
|
||||
while( ( m = _this->receiveMessage() ).id != IdQuit )
|
||||
{
|
||||
{
|
||||
|
||||
if( m.id == IdStartProcessing
|
||||
|| m.id == IdMidiEvent
|
||||
|| m.id == IdVstSetParameter
|
||||
|| m.id == IdVstSetTempo )
|
||||
|| m.id == IdVstSetTempo)
|
||||
{
|
||||
_this->processMessage( m );
|
||||
}
|
||||
@@ -2056,24 +2309,36 @@ DWORD WINAPI RemoteVstPlugin::processingThread( LPVOID _param )
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
PostMessage( __MessageHwnd,
|
||||
WM_USER,
|
||||
ProcessPluginMessage,
|
||||
(LPARAM) new message( m ) );
|
||||
#else
|
||||
_this->queueMessage( m );
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// notify GUI thread about shutdown
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
PostMessage( __MessageHwnd, WM_USER, ClosePlugin, 0 );
|
||||
|
||||
return 0;
|
||||
#else
|
||||
if (m.id == IdQuit)
|
||||
{
|
||||
_this->queueMessage( m );
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool RemoteVstPlugin::setupMessageWindow()
|
||||
{
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
HMODULE hInst = GetModuleHandle( nullptr );
|
||||
if( hInst == nullptr )
|
||||
{
|
||||
@@ -2087,13 +2352,14 @@ bool RemoteVstPlugin::setupMessageWindow()
|
||||
hInst, nullptr );
|
||||
// install GUI update timer
|
||||
SetTimer( __MessageHwnd, 1000, 50, nullptr );
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
DWORD WINAPI RemoteVstPlugin::guiEventLoop()
|
||||
{
|
||||
MSG msg;
|
||||
@@ -2105,10 +2371,51 @@ DWORD WINAPI RemoteVstPlugin::guiEventLoop()
|
||||
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
void RemoteVstPlugin::guiEventLoop()
|
||||
{
|
||||
struct timespec tim, tim2;
|
||||
tim.tv_sec = 0;
|
||||
tim.tv_nsec = 5000000;
|
||||
|
||||
XEvent e;
|
||||
while(true)
|
||||
{
|
||||
//if (XQLength(m_display) > 0)
|
||||
if (m_display && XPending(m_display) > 0)
|
||||
{
|
||||
XNextEvent(m_display, &e);
|
||||
|
||||
if (e.type == ClientMessage && e.xclient.data.l[0] == m_wmDeleteMessage)
|
||||
{
|
||||
hideEditor();
|
||||
}
|
||||
}
|
||||
|
||||
// needed by ZynAddSubFX UI
|
||||
if (__plugin->isInitialized())
|
||||
{
|
||||
__plugin->idle();
|
||||
}
|
||||
|
||||
if(__plugin->isInitialized() && !__plugin->isProcessing() )
|
||||
{
|
||||
__plugin->processUIThreadMessages();
|
||||
}
|
||||
|
||||
nanosleep(&tim, &tim2);
|
||||
|
||||
if (m_shouldQuit)
|
||||
{
|
||||
__plugin->hideEditor();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
LRESULT CALLBACK RemoteVstPlugin::wndProc( HWND hwnd, UINT uMsg,
|
||||
WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
@@ -2154,8 +2461,7 @@ LRESULT CALLBACK RemoteVstPlugin::wndProc( HWND hwnd, UINT uMsg,
|
||||
|
||||
return DefWindowProc( hwnd, uMsg, wParam, lParam );
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int main( int _argc, char * * _argv )
|
||||
@@ -2169,8 +2475,11 @@ int main( int _argc, char * * _argv )
|
||||
fprintf( stderr, "not enough arguments\n" );
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
OleInitialize(nullptr);
|
||||
#else
|
||||
XInitThreads();
|
||||
#endif
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
#ifdef LMMS_HAVE_SCHED_H
|
||||
// try to set realtime-priority
|
||||
@@ -2188,6 +2497,7 @@ int main( int _argc, char * * _argv )
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
HMODULE hInst = GetModuleHandle( nullptr );
|
||||
if( hInst == nullptr )
|
||||
{
|
||||
@@ -2211,6 +2521,7 @@ int main( int _argc, char * * _argv )
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
{
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
int embedMethodIndex = 3;
|
||||
@@ -2251,6 +2562,13 @@ int main( int _argc, char * * _argv )
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
if (EMBED)
|
||||
{
|
||||
cerr << "Native linux VST works only without embedding." << endl;
|
||||
}
|
||||
#endif
|
||||
|
||||
// constructor automatically will process messages until it receives
|
||||
// a IdVstLoadPlugin message and processes it
|
||||
#ifdef SYNC_WITH_SHM_FIFO
|
||||
@@ -2265,21 +2583,30 @@ int main( int _argc, char * * _argv )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
if( CreateThread( nullptr, 0, RemoteVstPlugin::processingThread,
|
||||
__plugin, 0, nullptr ) == nullptr )
|
||||
#else
|
||||
int err = 0;
|
||||
err = pthread_create(&__processingThreadId, nullptr, &RemoteVstPlugin::processingThread, __plugin);
|
||||
if (err != 0)
|
||||
#endif
|
||||
{
|
||||
__plugin->debugMessage( "could not create "
|
||||
"processingThread\n" );
|
||||
return -1;
|
||||
}
|
||||
RemoteVstPlugin::guiEventLoop();
|
||||
|
||||
__plugin->guiEventLoop();
|
||||
#ifdef NATIVE_LINUX_VST
|
||||
pthread_join(__processingThreadId, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
delete __plugin;
|
||||
|
||||
#ifndef NATIVE_LINUX_VST
|
||||
OleUninitialize();
|
||||
#endif
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -10,10 +10,6 @@ CHECK_CXX_DEFINE(IS_WIN "_WIN32")
|
||||
CHECK_CXX_DEFINE(IS_WIN64 "_WIN64")
|
||||
CHECK_CXX_DEFINE(IS_MINGW "__MINGW32__")
|
||||
|
||||
if(NOT IS_WIN)
|
||||
message(FATAL_ERROR "Toolchain used does not target windows.")
|
||||
ENDIF()
|
||||
|
||||
if(IS_WIN64 OR CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
set(BITNESS 64)
|
||||
else()
|
||||
@@ -26,12 +22,20 @@ FOREACH( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
|
||||
SET("CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG}" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
|
||||
ENDFOREACH()
|
||||
|
||||
if(NOT IS_WIN)
|
||||
set(EXE_NAME NativeLinuxRemoteVstPlugin${BITNESS})
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/")
|
||||
else()
|
||||
set(EXE_NAME RemoteVstPlugin${BITNESS})
|
||||
endif()
|
||||
add_executable(${EXE_NAME} WIN32
|
||||
../RemoteVstPlugin.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(${EXE_NAME} ole32)
|
||||
if(IS_WIN)
|
||||
target_link_libraries(${EXE_NAME} ole32)
|
||||
else()
|
||||
target_link_libraries(${EXE_NAME} pthread dl X11)
|
||||
ENDIF()
|
||||
|
||||
target_include_directories(${EXE_NAME}
|
||||
PRIVATE
|
||||
|
||||
@@ -113,6 +113,10 @@ private:
|
||||
|
||||
}
|
||||
|
||||
enum class ExecutableType
|
||||
{
|
||||
Unknown, Win32, Win64, Linux64,
|
||||
};
|
||||
|
||||
VstPlugin::VstPlugin( const QString & _plugin ) :
|
||||
m_plugin( PathUtil::toAbsolute(_plugin) ),
|
||||
@@ -125,23 +129,49 @@ VstPlugin::VstPlugin( const QString & _plugin ) :
|
||||
{
|
||||
setSplittedChannels( true );
|
||||
|
||||
PE::MachineType machineType;
|
||||
try {
|
||||
PE::FileInfo peInfo(m_plugin);
|
||||
machineType = peInfo.machineType();
|
||||
} catch (std::runtime_error& e) {
|
||||
qCritical() << "Error while determining PE file's machine type: " << e.what();
|
||||
machineType = PE::MachineType::unknown;
|
||||
auto pluginType = ExecutableType::Unknown;
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
QFileInfo fi(m_plugin);
|
||||
if (fi.suffix() == "so")
|
||||
{
|
||||
pluginType = ExecutableType::Linux64;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
try {
|
||||
PE::FileInfo peInfo(m_plugin);
|
||||
switch (peInfo.machineType())
|
||||
{
|
||||
case PE::MachineType::amd64:
|
||||
pluginType = ExecutableType::Win64;
|
||||
break;
|
||||
case PE::MachineType::i386:
|
||||
pluginType = ExecutableType::Win32;
|
||||
break;
|
||||
default:
|
||||
qWarning() << "Unknown PE machine type"
|
||||
<< QString::number(static_cast<uint16_t>(peInfo.machineType()), 16);
|
||||
break;
|
||||
}
|
||||
} catch (std::runtime_error& e) {
|
||||
qCritical() << "Error while determining PE file's machine type: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
switch(machineType)
|
||||
switch(pluginType)
|
||||
{
|
||||
case PE::MachineType::amd64:
|
||||
case ExecutableType::Win64:
|
||||
tryLoad( REMOTE_VST_PLUGIN_FILEPATH_64 ); // Default: RemoteVstPlugin64
|
||||
break;
|
||||
case PE::MachineType::i386:
|
||||
case ExecutableType::Win32:
|
||||
tryLoad( REMOTE_VST_PLUGIN_FILEPATH_32 ); // Default: 32/RemoteVstPlugin32
|
||||
break;
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
case ExecutableType::Linux64:
|
||||
tryLoad( NATIVE_LINUX_REMOTE_VST_PLUGIN_FILEPATH_64 ); // Default: NativeLinuxRemoteVstPlugin32
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
m_failed = true;
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
ADD_DEFINITIONS(-DREMOTE_VST_PLUGIN_FILEPATH_32="${REMOTE_VST_PLUGIN_FILEPATH_32}")
|
||||
ADD_DEFINITIONS(-DREMOTE_VST_PLUGIN_FILEPATH_64="${REMOTE_VST_PLUGIN_FILEPATH_64}")
|
||||
IF(LMMS_BUILD_LINUX)
|
||||
ADD_DEFINITIONS(-DNATIVE_LINUX_REMOTE_VST_PLUGIN_FILEPATH_64="${NATIVE_LINUX_REMOTE_VST_PLUGIN_FILEPATH_64}")
|
||||
ENDIF()
|
||||
|
||||
BUILD_PLUGIN(vstbase
|
||||
../vst_base.cpp ../VstPlugin.cpp ../VstPlugin.h ../communication.h
|
||||
|
||||
@@ -213,6 +213,9 @@ bool DataFile::validate( QString extension )
|
||||
( extension == "xiz" && ! getPluginFactory()->pluginSupportingExtension(extension).isNull()) ||
|
||||
extension == "sf2" || extension == "sf3" || extension == "pat" || extension == "mid" ||
|
||||
extension == "dll"
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
|| extension == "so"
|
||||
#endif
|
||||
#ifdef LMMS_HAVE_LV2
|
||||
|| extension == "lv2"
|
||||
#endif
|
||||
|
||||
@@ -1248,7 +1248,11 @@ void FileItem::determineFileType( void )
|
||||
m_type = MidiFile;
|
||||
m_handling = ImportAsProject;
|
||||
}
|
||||
else if( ext == "dll" )
|
||||
else if( ext == "dll"
|
||||
#ifdef LMMS_BUILD_LINUX
|
||||
|| ext == "so"
|
||||
#endif
|
||||
)
|
||||
{
|
||||
m_type = VstPluginFile;
|
||||
m_handling = LoadByPlugin;
|
||||
|
||||
Reference in New Issue
Block a user