Native linux VST support (#6048)

Co-authored-by: Dominic Clark <mrdomclark@gmail.com>
This commit is contained in:
akimaze
2022-03-02 19:47:54 +01:00
committed by GitHub
parent 7db3fa94a1
commit a08e7f9029
11 changed files with 449 additions and 49 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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 );

View File

@@ -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()

View 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()

View File

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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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;