diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b51857402e2..007842b82ad 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -225,8 +225,8 @@ jobs: --triplet=${{ matrix.arch }}-windows ` --host-triplet=${{ matrix.arch }}-windows ` --recurse ` - fftw3 fluidsynth[sndfile] libsamplerate libsndfile libstk lilv lv2 ` - portaudio sdl2 + fftw3 fltk fluidsynth[sndfile] libsamplerate libsndfile libstk ` + lilv lv2 portaudio sdl2 - name: Set up build environment uses: ilammy/msvc-dev-cmd@d8610e2b41c6d0f0c3b4c46dad8df0fd826c68e1 with: diff --git a/CMakeLists.txt b/CMakeLists.txt index dae43e57322..bfd17660191 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -486,6 +486,13 @@ ENDIF(WANT_JACK) FIND_PACKAGE(FFTW COMPONENTS fftw3f REQUIRED) # check for FLTK +set(FLTK_SKIP_OPENGL TRUE) +set(FLTK_SKIP_FORMS TRUE) +set(FLTK_SKIP_IMAGES TRUE) +set(FLTK_SKIP_MATH TRUE) +if(MINGW_PREFIX) + set(FLTK_SKIP_FLUID TRUE) +endif() FIND_PACKAGE(FLTK) IF(FLTK_FOUND) SET(STATUS_ZYN "OK") diff --git a/cmake/modules/PluginList.cmake b/cmake/modules/PluginList.cmake index 151c5bd66a2..fe98a64b442 100644 --- a/cmake/modules/PluginList.cmake +++ b/cmake/modules/PluginList.cmake @@ -100,7 +100,6 @@ ENDIF() IF(MSVC) SET(MSVC_INCOMPATIBLE_PLUGINS LadspaEffect - ZynAddSubFx ) message(WARNING "Compiling with MSVC. The following plugins are not available: ${MSVC_INCOMPATIBLE_PLUGINS}") LIST(REMOVE_ITEM PLUGIN_LIST ${MSVC_INCOMPATIBLE_PLUGINS}) diff --git a/include/IoHelper.h b/include/IoHelper.h index c7d65c917ae..96d6aa1446e 100644 --- a/include/IoHelper.h +++ b/include/IoHelper.h @@ -47,7 +47,7 @@ namespace lmms #ifdef _WIN32 -std::wstring toWString(const std::string& s) +inline std::wstring toWString(const std::string& s) { std::wstring ret; int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), @@ -64,7 +64,7 @@ std::wstring toWString(const std::string& s) #endif -FILE* F_OPEN_UTF8(std::string const& fname, const char* mode){ +inline FILE* F_OPEN_UTF8(std::string const& fname, const char* mode){ #ifdef LMMS_BUILD_WIN32 return _wfopen(toWString(fname).data(), toWString(mode).data()); #else @@ -73,7 +73,7 @@ FILE* F_OPEN_UTF8(std::string const& fname, const char* mode){ } -int fileToDescriptor(FILE* f, bool closeFile = true) +inline int fileToDescriptor(FILE* f, bool closeFile = true) { int fh; if (f == nullptr) {return -1;} diff --git a/plugins/ZynAddSubFx/CMakeLists.txt b/plugins/ZynAddSubFx/CMakeLists.txt index b184162a387..3369a793865 100644 --- a/plugins/ZynAddSubFx/CMakeLists.txt +++ b/plugins/ZynAddSubFx/CMakeLists.txt @@ -1,5 +1,12 @@ +if(NOT FLTK_FOUND) + return() +endif() + INCLUDE(BuildPlugin) +find_package(Threads REQUIRED) +find_package(ZLIB REQUIRED) + set(CMAKE_POSITION_INDEPENDENT_CODE ON) # definitions for ZynAddSubFX @@ -11,40 +18,20 @@ ELSE() ADD_DEFINITIONS(-DOS_WINDOWS) ENDIF() -# do not conflict with LMMS' Controller class -ADD_DEFINITIONS(-DController=ZynController) - # use asm optimizations when on x86 or x86_64 -IF(LMMS_HOST_X86 OR LMMS_HOST_X86_64) +if(NOT MSVC AND (LMMS_HOST_X86 OR LMMS_HOST_X86_64)) ADD_DEFINITIONS(-DASM_F2I_YES) -ENDIF(LMMS_HOST_X86 OR LMMS_HOST_X86_64) +endif() # build ZynAddSubFX with full optimizations -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wno-write-strings -Wno-deprecated-declarations -fpermissive") +if(NOT MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -Wno-write-strings -Wno-deprecated-declarations -fpermissive") +endif() IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND NOT "${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS "6.0.0") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-misleading-indentation") ENDIF() -IF(LMMS_BUILD_WIN32) - # link system-libraries - ADD_DEFINITIONS(-DPTW32_STATIC_LIB) - # fix X11 headers errors caused by bug with mingw + c++11 (enable -std=gnu++0x) - SET(CMAKE_CXX_EXTENSIONS ON) -ENDIF(LMMS_BUILD_WIN32) - -SET(FLTK_SKIP_OPENGL TRUE) -SET(FLTK_SKIP_FORMS TRUE) -SET(FLTK_SKIP_IMAGES TRUE) -SET(FLTK_SKIP_MATH TRUE) -IF(MINGW_PREFIX) - SET(FLTK_SKIP_FLUID TRUE) -ENDIF() - -IF(NOT FLTK_FOUND) - RETURN() -ENDIF() - IF(MINGW_PREFIX) SET(FLTK_FLUID_EXECUTABLE "${MINGW_PREFIX}/bin/fluid") ENDIF() @@ -57,13 +44,15 @@ IF(NOT EXISTS ${FLTK_FLUID_EXECUTABLE}) ENDIF() ENDIF() -INCLUDE_DIRECTORIES("${FLTK_INCLUDE_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}" - ${FFTW3F_INCLUDE_DIRS} - "${CMAKE_CURRENT_BINARY_DIR}" - "${CMAKE_BINARY_DIR}") - -include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/zynaddsubfx/src/UI) +include_directories( + "${FLTK_INCLUDE_DIR}" + "${CMAKE_CURRENT_SOURCE_DIR}" + ${FFTW3F_INCLUDE_DIRS} + "${CMAKE_CURRENT_BINARY_DIR}" + "${CMAKE_BINARY_DIR}" + "${CMAKE_SOURCE_DIR}/src/3rdparty/mingw-std-threads" + "${CMAKE_CURRENT_SOURCE_DIR}/zynaddsubfx/src/UI" +) ADD_DEFINITIONS(-DPLUGINVERSION) # removes exit confirmation dialogs etc. in MasterUI.fl add_subdirectory(zynaddsubfx/src/Nio) @@ -116,24 +105,23 @@ SET(zynaddsubfx_core_SRCS zynaddsubfx/src/Synth/PADnote.cpp zynaddsubfx/src/Synth/Resonance.cpp zynaddsubfx/src/Synth/SUBnote.cpp - ) - - -IF(LMMS_BUILD_LINUX) - ADD_LIBRARY(ZynAddSubFxCore MODULE LocalZynAddSubFx.cpp ${zynaddsubfx_core_SRCS}) -ELSE() - ADD_LIBRARY(ZynAddSubFxCore SHARED LocalZynAddSubFx.cpp ${zynaddsubfx_core_SRCS}) -ENDIF() -TARGET_LINK_LIBRARIES(ZynAddSubFxCore zynaddsubfx_nio ${FFTW3F_LIBRARIES} ${QT_LIBRARIES} -lz -lpthread) - -TARGET_LINK_LIBRARIES(ZynAddSubFxCore Qt5::Widgets Qt5::Xml) - -IF(LMMS_BUILD_WIN32) - TARGET_LINK_LIBRARIES(ZynAddSubFxCore -lws2_32) - INSTALL(TARGETS ZynAddSubFxCore RUNTIME DESTINATION "${PLUGIN_DIR}") -ELSE(LMMS_BUILD_WIN32) - INSTALL(TARGETS ZynAddSubFxCore LIBRARY DESTINATION "${PLUGIN_DIR}") -ENDIF(LMMS_BUILD_WIN32) +) + +add_library(ZynAddSubFxCoreObjs OBJECT LocalZynAddSubFx.cpp ${zynaddsubfx_core_SRCS}) +add_library(ZynAddSubFxCore INTERFACE) +target_sources(ZynAddSubFxCore INTERFACE + $ + $ +) + +target_link_libraries(ZynAddSubFxCore INTERFACE + ${FFTW3F_LIBRARIES} + ${QT_LIBRARIES} + Qt5::Widgets + Qt5::Xml + Threads::Threads + ZLIB::ZLIB +) LINK_DIRECTORIES("${CMAKE_CURRENT_BINARY_DIR}/..") IF(LMMS_BUILD_LINUX) @@ -144,10 +132,11 @@ ELSE() SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${PLUGIN_DIR}") ENDIF() BUILD_PLUGIN(zynaddsubfx ZynAddSubFx.cpp ZynAddSubFx.h MOCFILES ZynAddSubFx.h EMBEDDED_RESOURCES artwork.png logo.png) -TARGET_LINK_LIBRARIES(zynaddsubfx -lZynAddSubFxCore) -ADD_DEPENDENCIES(zynaddsubfx ZynAddSubFxCore) +target_link_libraries(zynaddsubfx ZynAddSubFxCore) -IF(WIN32) +if(MSVC) + set(WINRC "${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfx.rc") +elseif(WIN32) SET(WINRC "${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfxrc.obj") ADD_CUSTOM_COMMAND(OUTPUT "${WINRC}" COMMAND "${CMAKE_RC_COMPILER}" @@ -155,14 +144,19 @@ IF(WIN32) "-o\"${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfxrc.obj\"" "-i\"${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfx.rc\"" DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/zynaddsubfx.rc") -ENDIF(WIN32) +endif() # Use libraries in non-standard directories (e.g., another version of Qt) SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) ADD_SUBDIRECTORY("${LMMS_SOURCE_DIR}/src/common" common) -ADD_EXECUTABLE(RemoteZynAddSubFx RemoteZynAddSubFx.cpp ${LMMS_COMMON_SRCS} "${WINRC}") +add_executable(RemoteZynAddSubFx + RemoteZynAddSubFx.cpp + ${LMMS_COMMON_SRCS} + "${WINRC}" + $ +) INSTALL(TARGETS RemoteZynAddSubFx RUNTIME DESTINATION "${PLUGIN_DIR}") # Needed to deploy dependencies of RemoteZynAddSubFx SET_PROPERTY(GLOBAL APPEND PROPERTY PLUGINS_BUILT "RemoteZynAddSubFx") @@ -182,8 +176,7 @@ IF(FLTK_CONFIG AND NOT (LMMS_BUILD_APPLE OR LMMS_BUILD_WIN32)) STRING(REPLACE " " ";" FLTK_FILTERED_LDFLAGS ${FLTK_FILTERED_LDFLAGS}) LIST(REMOVE_ITEM FLTK_FILTERED_LDFLAGS -lX11) ENDIF() -TARGET_LINK_LIBRARIES(RemoteZynAddSubFx zynaddsubfx_gui -lZynAddSubFxCore ${FLTK_FILTERED_LDFLAGS} -lpthread ) -ADD_DEPENDENCIES(RemoteZynAddSubFx ZynAddSubFxCore) +target_link_libraries(RemoteZynAddSubFx ZynAddSubFxCore ${FLTK_FILTERED_LDFLAGS}) if(LMMS_HAVE_LIBRT) target_link_libraries(RemoteZynAddSubFx rt) @@ -199,13 +192,6 @@ ENDIF(LMMS_BUILD_WIN32) IF(LMMS_BUILD_WIN32) - add_custom_command( - TARGET ZynAddSubFxCore - POST_BUILD - COMMAND "${STRIP_COMMAND}" "$" - VERBATIM - COMMAND_EXPAND_LISTS - ) add_custom_command( TARGET RemoteZynAddSubFx POST_BUILD diff --git a/plugins/ZynAddSubFx/LocalZynAddSubFx.cpp b/plugins/ZynAddSubFx/LocalZynAddSubFx.cpp index f09cb666224..83ef3e9a246 100644 --- a/plugins/ZynAddSubFx/LocalZynAddSubFx.cpp +++ b/plugins/ZynAddSubFx/LocalZynAddSubFx.cpp @@ -22,19 +22,25 @@ * */ -#include +#include "LocalZynAddSubFx.h" -#include "zynaddsubfx/src/Misc/Util.h" -#include #include -#include "LocalZynAddSubFx.h" +#include "lmmsconfig.h" + +#ifdef LMMS_BUILD_WIN32 +# include +# include "IoHelper.h" +#else +# include +#endif #include "MidiEvent.h" #include "zynaddsubfx/src/Nio/NulEngine.h" #include "zynaddsubfx/src/Misc/Master.h" #include "zynaddsubfx/src/Misc/Part.h" +#include "zynaddsubfx/src/Misc/Util.h" // Global variable in zynaddsubfx/src/globals.h SYNTH_T* synth = nullptr; @@ -53,14 +59,6 @@ LocalZynAddSubFx::LocalZynAddSubFx() : { if( s_instanceCount == 0 ) { -#ifdef LMMS_BUILD_WIN32 -#ifndef __WINPTHREADS_VERSION - // (non-portable) initialization of statically linked pthread library - pthread_win32_process_attach_np(); - pthread_win32_thread_attach_np(); -#endif -#endif // LMMS_BUILD_WIN32 - initConfig(); synth = new SYNTH_T; @@ -143,14 +141,20 @@ void LocalZynAddSubFx::loadXML( const std::string & _filename ) { char * f = strdup( _filename.c_str() ); - pthread_mutex_lock( &m_master->mutex ); - m_master->defaults(); - m_master->loadXML( f ); - pthread_mutex_unlock( &m_master->mutex ); + { + const auto lock = std::lock_guard{m_master->mutex}; + m_master->defaults(); + m_master->loadXML( f ); + } m_master->applyparameters(); +#ifdef LMMS_BUILD_WIN32 + _wunlink(toWString(_filename).c_str()); +#else unlink( f ); +#endif + free( f ); } @@ -161,10 +165,11 @@ void LocalZynAddSubFx::loadPreset( const std::string & _filename, int _part ) { char * f = strdup( _filename.c_str() ); - pthread_mutex_lock( &m_master->mutex ); - m_master->part[_part]->defaultsinstrument(); - m_master->part[_part]->loadXMLinstrument( f ); - pthread_mutex_unlock( &m_master->mutex ); + { + const auto lock = std::lock_guard{m_master->mutex}; + m_master->part[_part]->defaultsinstrument(); + m_master->part[_part]->loadXMLinstrument( f ); + } m_master->applyparameters(); @@ -262,8 +267,13 @@ void LocalZynAddSubFx::processMidiEvent( const MidiEvent& event ) void LocalZynAddSubFx::processAudio( sampleFrame * _out ) { +#ifdef _MSC_VER + const auto outputl = static_cast(_alloca(synth->buffersize * sizeof(float))); + const auto outputr = static_cast(_alloca(synth->buffersize * sizeof(float))); +#else float outputl[synth->buffersize]; float outputr[synth->buffersize]; +#endif m_master->GetAudioOutSamples( synth->buffersize, synth->samplerate, outputl, outputr ); diff --git a/plugins/ZynAddSubFx/RemoteZynAddSubFx.cpp b/plugins/ZynAddSubFx/RemoteZynAddSubFx.cpp index 4c69beed025..c4d6b71a16b 100644 --- a/plugins/ZynAddSubFx/RemoteZynAddSubFx.cpp +++ b/plugins/ZynAddSubFx/RemoteZynAddSubFx.cpp @@ -22,17 +22,19 @@ * */ +#include "RemoteZynAddSubFx.h" + #include #ifdef LMMS_BUILD_WIN32 #include #endif #include +#include "ThreadShims.h" #undef CursorShape // is, by mistake, not undefed in FL #include "RemotePluginClient.h" -#include "RemoteZynAddSubFx.h" #include "LocalZynAddSubFx.h" #include "zynaddsubfx/src/Nio/Nio.h" @@ -60,12 +62,12 @@ class RemoteZynAddSubFx : public RemotePluginClient, public LocalZynAddSubFx sendMessage( IdInitDone ); waitForMessage( IdInitDone ); - pthread_mutex_init( &m_guiMutex, nullptr ); - pthread_create( &m_messageThreadHandle, nullptr, messageLoop, this ); + m_messageThread = std::thread{&RemoteZynAddSubFx::messageLoop, this}; } ~RemoteZynAddSubFx() override { + m_messageThread.join(); Nio::stop(); } @@ -84,9 +86,8 @@ class RemoteZynAddSubFx : public RemotePluginClient, public LocalZynAddSubFx message m; while( ( m = receiveMessage() ).id != IdQuit ) { - pthread_mutex_lock( &m_master->mutex ); + const auto lock = std::lock_guard{m_master->mutex}; processMessage( m ); - pthread_mutex_unlock( &m_master->mutex ); } m_guiExit = true; } @@ -102,9 +103,10 @@ class RemoteZynAddSubFx : public RemotePluginClient, public LocalZynAddSubFx case IdHideUI: case IdLoadSettingsFromFile: case IdLoadPresetFile: - pthread_mutex_lock( &m_guiMutex ); - m_guiMessages.push( _m ); - pthread_mutex_unlock( &m_guiMutex ); + { + const auto lock = std::lock_guard{m_guiMutex}; + m_guiMessages.push( _m ); + } break; case IdSaveSettingsToFile: @@ -144,22 +146,13 @@ class RemoteZynAddSubFx : public RemotePluginClient, public LocalZynAddSubFx LocalZynAddSubFx::processAudio( _out ); } - static void * messageLoop( void * _arg ) - { - auto _this = static_cast(_arg); - - _this->messageLoop(); - - return nullptr; - } - void guiLoop(); private: const int m_guiSleepTime; - pthread_t m_messageThreadHandle; - pthread_mutex_t m_guiMutex; + std::thread m_messageThread; + std::mutex m_guiMutex; std::queue m_guiMessages; bool m_guiExit; @@ -189,12 +182,11 @@ void RemoteZynAddSubFx::guiLoop() } if( exitProgram == 1 ) { - pthread_mutex_lock( &m_master->mutex ); + const auto lock = std::lock_guard{m_master->mutex}; sendMessage( IdHideUI ); exitProgram = 0; - pthread_mutex_unlock( &m_master->mutex ); } - pthread_mutex_lock( &m_guiMutex ); + const auto lock = std::lock_guard{m_guiMutex}; while( m_guiMessages.size() ) { RemotePluginClient::message m = m_guiMessages.front(); @@ -219,9 +211,8 @@ void RemoteZynAddSubFx::guiLoop() { ui->refresh_master_ui(); } - pthread_mutex_lock( &m_master->mutex ); + const auto lock = std::lock_guard{m_master->mutex}; sendMessage( IdLoadSettingsFromFile ); - pthread_mutex_unlock( &m_master->mutex ); break; } @@ -235,9 +226,8 @@ void RemoteZynAddSubFx::guiLoop() ui->updatepanel(); ui->refresh_master_ui(); } - pthread_mutex_lock( &m_master->mutex ); + const auto lock = std::lock_guard{m_master->mutex}; sendMessage( IdLoadPresetFile ); - pthread_mutex_unlock( &m_master->mutex ); break; } @@ -245,7 +235,6 @@ void RemoteZynAddSubFx::guiLoop() break; } } - pthread_mutex_unlock( &m_guiMutex ); } Fl::flush(); @@ -271,15 +260,6 @@ int main( int _argc, char * * _argv ) const auto pollParentThread = PollParentThread{}; #endif -#ifdef LMMS_BUILD_WIN32 -#ifndef __WINPTHREADS_VERSION - // (non-portable) initialization of statically linked pthread library - pthread_win32_process_attach_np(); - pthread_win32_thread_attach_np(); -#endif -#endif // LMMS_BUILD_WIN32 - - #ifdef SYNC_WITH_SHM_FIFO RemoteZynAddSubFx * remoteZASF = new RemoteZynAddSubFx( _argv[1], _argv[2] ); @@ -291,14 +271,6 @@ int main( int _argc, char * * _argv ) delete remoteZASF; - -#ifdef LMMS_BUILD_WIN32 -#ifndef __WINPTHREADS_VERSION - pthread_win32_thread_detach_np(); - pthread_win32_process_detach_np(); -#endif -#endif // LMMS_BUILD_WIN32 - return 0; } diff --git a/plugins/ZynAddSubFx/ThreadShims.h b/plugins/ZynAddSubFx/ThreadShims.h new file mode 100644 index 00000000000..843b50fb58b --- /dev/null +++ b/plugins/ZynAddSubFx/ThreadShims.h @@ -0,0 +1,9 @@ +#include +#include +#include + +#if defined(__MINGW32__) && !defined(_GLIBCXX_HAS_GTHREADS) +# include +# include +# include +#endif diff --git a/plugins/ZynAddSubFx/zynaddsubfx b/plugins/ZynAddSubFx/zynaddsubfx index b9855dbe164..551e816a633 160000 --- a/plugins/ZynAddSubFx/zynaddsubfx +++ b/plugins/ZynAddSubFx/zynaddsubfx @@ -1 +1 @@ -Subproject commit b9855dbe16424edc528a6796ddbc50b1042482c7 +Subproject commit 551e816a6334fd190c74ce971378063b2757b47b diff --git a/tests/scripted/check-namespace b/tests/scripted/check-namespace index 5f71505b2c9..a816f0d7bd5 100755 --- a/tests/scripted/check-namespace +++ b/tests/scripted/check-namespace @@ -77,7 +77,9 @@ exclude_files = re.compile( 'plugins/MidiExport/MidiFile.hpp|' 'plugins/ReverbSC/[a-z]|' 'plugins/Sf2Player/fluidsynthshims.h|' - '/portsmf/' + '/portsmf/|' + # only forward to headers that are not ours: + 'plugins/ZynAddSubFx/ThreadShims.h' ) files = [Path(f) for f in result.stdout.splitlines() if not exclude_files.search(f)] @@ -131,7 +133,7 @@ for cur_file in files: if cur_file.is_file(): cur_text = cur_file.read_text(errors='replace') - if str(cur_file) not in known_no_namespace_lmms: + if cur_file.as_posix() not in known_no_namespace_lmms: namespace_pattern.search(cur_text) or error(cur_file, None, f'File has no namespace lmms') header_guard = str(cur_file).endswith('.h')