diff --git a/include/RemotePlugin.h b/include/RemotePlugin.h index fd3ef5e09e1..5e29b1cfc4f 100644 --- a/include/RemotePlugin.h +++ b/include/RemotePlugin.h @@ -36,7 +36,6 @@ #include #include - #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 @@ class RemotePluginClient : public RemotePluginBase sample_rate_t m_sampleRate; fpp_t m_bufferSize; - } ; #endif diff --git a/include/aeffectx.h b/include/aeffectx.h index 61597270140..7cdfcfe7d08 100644 --- a/include/aeffectx.h +++ b/include/aeffectx.h @@ -30,7 +30,11 @@ #include // Calling convention +#ifdef _WIN32 #define VST_CALL_CONV __cdecl +#else +#define VST_CALL_CONV +#endif template constexpr int32_t CCONST(T a, T b, T c, T d) diff --git a/plugins/vestige/vestige.cpp b/plugins/vestige/vestige.cpp index 97af8bc43b8..17510ac851d 100644 --- a/plugins/vestige/vestige.cpp +++ b/plugins/vestige/vestige.cpp @@ -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 ); diff --git a/plugins/vst_base/CMakeLists.txt b/plugins/vst_base/CMakeLists.txt index 873ed5f8e81..68bdb99395a 100644 --- a/plugins/vst_base/CMakeLists.txt +++ b/plugins/vst_base/CMakeLists.txt @@ -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() diff --git a/plugins/vst_base/NativeLinuxRemoteVstPlugin64.cmake b/plugins/vst_base/NativeLinuxRemoteVstPlugin64.cmake new file mode 100644 index 00000000000..dc582360429 --- /dev/null +++ b/plugins/vst_base/NativeLinuxRemoteVstPlugin64.cmake @@ -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() + diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index c949147eb41..30bb7919e3b 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -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 #endif +#ifndef NATIVE_LINUX_VST #include +#endif #endif +#ifndef NATIVE_LINUX_VST #define USE_WS_PREFIX #include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 @@ -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 @@ class RemoteVstPlugin : public RemotePluginClient } 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 @@ class RemoteVstPlugin : public RemotePluginClient 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 @@ class RemoteVstPlugin : public RemotePluginClient 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 @@ class RemoteVstPlugin : public RemotePluginClient bool m_processing; +#ifdef NATIVE_LINUX_VST + pthread_mutex_t message_mutex = PTHREAD_MUTEX_INITIALIZER; + bool m_shouldQuit = false; +#endif std::queue 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 ); } +#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( _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; - } diff --git a/plugins/vst_base/RemoteVstPlugin/CMakeLists.txt b/plugins/vst_base/RemoteVstPlugin/CMakeLists.txt index f916c694cd1..f54fbf02e73 100644 --- a/plugins/vst_base/RemoteVstPlugin/CMakeLists.txt +++ b/plugins/vst_base/RemoteVstPlugin/CMakeLists.txt @@ -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 diff --git a/plugins/vst_base/VstPlugin.cpp b/plugins/vst_base/VstPlugin.cpp index 2b14fc936f9..ed8f10eb18d 100644 --- a/plugins/vst_base/VstPlugin.cpp +++ b/plugins/vst_base/VstPlugin.cpp @@ -116,6 +116,10 @@ class FileInfo } +enum class ExecutableType +{ + Unknown, Win32, Win64, Linux64, +}; VstPlugin::VstPlugin( const QString & _plugin ) : m_plugin( PathUtil::toAbsolute(_plugin) ), @@ -128,23 +132,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(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; diff --git a/plugins/vst_base/vstbase/CMakeLists.txt b/plugins/vst_base/vstbase/CMakeLists.txt index bd5f98b561e..4e8cbd97ce4 100644 --- a/plugins/vst_base/vstbase/CMakeLists.txt +++ b/plugins/vst_base/vstbase/CMakeLists.txt @@ -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 diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index 10585b72710..053f14472d1 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -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 diff --git a/src/gui/FileBrowser.cpp b/src/gui/FileBrowser.cpp index 77a298aa556..15b8510aa9a 100644 --- a/src/gui/FileBrowser.cpp +++ b/src/gui/FileBrowser.cpp @@ -1247,7 +1247,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;