From 1641f5f95f710943e2a7c0dbf9eb3456d128ea76 Mon Sep 17 00:00:00 2001 From: Dalton Messmer Date: Thu, 10 Jul 2025 02:08:42 -0400 Subject: [PATCH] Use C++20 in `RemoteVstPlugin` (#7916) - Build RemoteVstPlugin in C++20 mode - Avoids using std::wstring due to strange issues with it when built with wineg++. See https://bugs.winehq.org/show_bug.cgi?id=58465 - Fix some memory leaks + minor cleanup of RemoteVstPlugin code - Rename `F_OPEN_UTF8` to `fopenUtf8` - Use C++20 in our `determine_version_from_source` CMake function - Update ZynAddSubFX submodule --- cmake/modules/ImportedTargetHelpers.cmake | 2 +- include/IoHelper.h | 89 ++++-- include/LocaleHelper.h | 11 +- include/RemotePluginClient.h | 4 +- include/VstSyncData.h | 10 +- include/aeffectx.h | 3 + plugins/VstBase/RemoteVstPlugin.cpp | 288 ++++++++++-------- .../VstBase/RemoteVstPlugin/CMakeLists.txt | 7 +- plugins/ZynAddSubFx/LocalZynAddSubFx.cpp | 2 +- plugins/ZynAddSubFx/zynaddsubfx | 2 +- src/core/VstSyncController.cpp | 20 +- 11 files changed, 255 insertions(+), 183 deletions(-) diff --git a/cmake/modules/ImportedTargetHelpers.cmake b/cmake/modules/ImportedTargetHelpers.cmake index d3d979901..3327fbf8e 100644 --- a/cmake/modules/ImportedTargetHelpers.cmake +++ b/cmake/modules/ImportedTargetHelpers.cmake @@ -44,7 +44,7 @@ function(determine_version_from_source _version_out _target _source) _dvfs_run_result _dvfs_compile_result "${CMAKE_CURRENT_BINARY_DIR}" SOURCES "${_source_file}" LINK_LIBRARIES "${_target}" - CXX_STANDARD 17 + CXX_STANDARD 20 RUN_OUTPUT_VARIABLE _run_output COMPILE_OUTPUT_VARIABLE _compile_output ) diff --git a/include/IoHelper.h b/include/IoHelper.h index 3c453fa58..eca4f9ed5 100644 --- a/include/IoHelper.h +++ b/include/IoHelper.h @@ -22,24 +22,31 @@ * */ +// NOTE: The LMMS/zynaddsubfx repo contains a copy of this header. +// If you modify this file, consider modifying it there as well. + #ifndef LMMS_IO_HELPER_H #define LMMS_IO_HELPER_H -#include "lmmsconfig.h" - #include +#include +#include +#include +#include +#include #ifdef _WIN32 -#include +# ifndef NOMINMAX +# define NOMINMAX +# endif +# include #endif -#ifdef LMMS_BUILD_WIN32 -#include -#else -#ifdef LMMS_HAVE_UNISTD_H -#include +#if defined(_WIN32) && !defined(__WINE__) +# include +#elif __has_include() +# include #endif -#endif // LMMS_BUILD_WIN32 namespace lmms { @@ -47,43 +54,67 @@ namespace lmms #ifdef _WIN32 -inline std::wstring toWString(const std::string& s) +/** + * UTF-8 to wide string conversion + * NOTE: Avoids using std::wstring because it does not work correctly with wineg++ + */ +inline std::unique_ptr toWString(std::string_view utf8) { - std::wstring ret; - int len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), - s.length(), nullptr, 0); - if (len == 0) + std::unique_ptr ret; + if (utf8.empty()) { + ret = std::make_unique(1); return ret; } - ret.resize(len); - MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s.length(), &ret[0], len); + + if (utf8.length() > static_cast(std::numeric_limits::max())) + { + throw std::overflow_error{"toWString: input string is too long"}; + } + const auto utf8Len = static_cast(utf8.length()); + + int result = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.data(), utf8Len, nullptr, 0); + if (result <= 0) + { + const DWORD error = ::GetLastError(); + throw std::invalid_argument{"toWString: failed to get size of result string. error code: " + std::to_string(error)}; + } + + ret = std::make_unique(result + 1); // includes null terminator + result = ::MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8.data(), utf8Len, ret.get(), result); + if (result <= 0) + { + const DWORD error = ::GetLastError(); + throw std::invalid_argument{"toWString: failed to convert. error code: " + std::to_string(error)}; + } + return ret; } -#endif +#endif // _WIN32 - -inline FILE* F_OPEN_UTF8(std::string const& fname, const char* mode){ -#ifdef LMMS_BUILD_WIN32 - return _wfopen(toWString(fname).data(), toWString(mode).data()); +//! std::fopen wrapper that expects UTF-8 encoded `filename` and `mode` +inline std::FILE* fopenUtf8(const std::string& filename, const char* mode) +{ +#if defined(_WIN32) && !defined(__WINE__) + return _wfopen(toWString(filename).get(), toWString(mode).get()); #else - return fopen(fname.data(), mode); + return std::fopen(filename.c_str(), mode); #endif } - -inline int fileToDescriptor(FILE* f, bool closeFile = true) +//! Returns the POSIX file descriptor of the given FILE +inline int fileToDescriptor(std::FILE* file, bool closeFile = true) { - if (f == nullptr) {return -1;} + if (file == nullptr) { return -1; } -#ifdef LMMS_BUILD_WIN32 - int fh = _dup(_fileno(f)); +#if defined(_WIN32) && !defined(__WINE__) + int fh = _dup(_fileno(file)); #else - int fh = dup(fileno(f)); + int fh = dup(fileno(file)); #endif - if (closeFile) {fclose(f);} + if (closeFile) { std::fclose(file); } return fh; } diff --git a/include/LocaleHelper.h b/include/LocaleHelper.h index c1e1b4735..14d7d73d5 100644 --- a/include/LocaleHelper.h +++ b/include/LocaleHelper.h @@ -25,6 +25,9 @@ * */ +// NOTE: The LMMS/zynaddsubfx repo contains a copy of this header. +// If you modify this file, consider modifying it there as well. + #ifndef LMMS_LOCALEHELPER_H #define LMMS_LOCALEHELPER_H @@ -36,7 +39,7 @@ namespace lmms::LocaleHelper { -inline double toDouble(QString str, bool* ok = nullptr) +inline double toDouble(const QString& str, bool* ok = nullptr) { bool isOkay; QLocale c(QLocale::C); @@ -48,16 +51,16 @@ inline double toDouble(QString str, bool* ok = nullptr) german.setNumberOptions(QLocale::RejectGroupSeparator); value = german.toDouble(str, &isOkay); } - if (ok != nullptr) {*ok = isOkay;} + if (ok != nullptr) { *ok = isOkay; } return value; } -inline float toFloat(QString str, bool* ok = nullptr) +inline float toFloat(const QString& str, bool* ok = nullptr) { double d = toDouble(str, ok); if (!std::isinf(d) && std::fabs(d) > std::numeric_limits::max()) { - if (ok != nullptr) {*ok = false;} + if (ok != nullptr) { *ok = false; } return 0.0f; } return static_cast(d); diff --git a/include/RemotePluginClient.h b/include/RemotePluginClient.h index 241896506..081c88eb7 100644 --- a/include/RemotePluginClient.h +++ b/include/RemotePluginClient.h @@ -259,8 +259,8 @@ bool RemotePluginClient::processMessage( const message & _m ) debugMessage(std::string{"Failed to attach sync data: "} + error.what() + '\n'); std::exit(EXIT_FAILURE); } - m_bufferSize = m_vstSyncData->m_bufferSize; - m_sampleRate = m_vstSyncData->m_sampleRate; + m_bufferSize = m_vstSyncData->bufferSize; + m_sampleRate = m_vstSyncData->sampleRate; reply_message.id = IdHostInfoGotten; reply = true; break; diff --git a/include/VstSyncData.h b/include/VstSyncData.h index 480bc7fb4..94d3199e4 100644 --- a/include/VstSyncData.h +++ b/include/VstSyncData.h @@ -48,13 +48,13 @@ struct VstSyncData bool isCycle; float cycleStart; float cycleEnd; - bool m_playbackJumped; - int m_bufferSize; - int m_sampleRate; - int m_bpm; + bool playbackJumped; + int bufferSize; + int sampleRate; + int bpm; #ifdef VST_SNC_LATENCY - float m_latency; + float latency; #endif } ; diff --git a/include/aeffectx.h b/include/aeffectx.h index 2c69464cc..1a771fabf 100644 --- a/include/aeffectx.h +++ b/include/aeffectx.h @@ -107,6 +107,7 @@ constexpr int effOpen = 0; constexpr int effClose = 1; // currently unused constexpr int effSetProgram = 2; // currently unused constexpr int effGetProgram = 3; // currently unused +constexpr int effSetProgramName = 4; constexpr int effGetProgramName = 5; // currently unused constexpr int effGetParamLabel = 6; constexpr int effGetParamDisplay = 7; @@ -119,8 +120,10 @@ constexpr int effEditOpen = 14; constexpr int effEditClose = 15; constexpr int effEditIdle = 19; constexpr int effEditTop = 20; +constexpr int effGetChunk = 23; constexpr int effSetChunk = 24; constexpr int effProcessEvents = 25; +constexpr int effGetProgramNameIndexed = 29; constexpr int effGetEffectName = 45; constexpr int effGetVendorString = 47; constexpr int effGetProductString = 48; diff --git a/plugins/VstBase/RemoteVstPlugin.cpp b/plugins/VstBase/RemoteVstPlugin.cpp index 077216b30..9fa64f2ba 100644 --- a/plugins/VstBase/RemoteVstPlugin.cpp +++ b/plugins/VstBase/RemoteVstPlugin.cpp @@ -86,12 +86,12 @@ #include #include -#include +#include +#include +#include #include #include -#include -#include -#include +#include #include @@ -101,11 +101,11 @@ struct ERect { - short top; - short left; - short bottom; - short right; -} ; + std::int16_t top; + std::int16_t left; + std::int16_t bottom; + std::int16_t right; +}; #endif @@ -474,15 +474,15 @@ private: double m_currentSamplePos; int m_currentProgram; - // host to plugin synchronisation data structure - struct in + //! Host to plugin synchronisation data structure + struct Sync { - double lastppqPos; - double m_Timestamp; - int32_t m_lastFlags; - } ; + double lastppqPos = 0; + double timestamp = -1; + std::int32_t lastFlags = 0; + }; - in * m_in; + Sync m_sync; }; @@ -511,16 +511,10 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) : m_midiEvents(), m_bpm( 0 ), m_currentSamplePos( 0 ), - m_currentProgram( -1 ), - m_in( nullptr ) + m_currentProgram(-1) { __plugin = this; - m_in = ( in* ) new char[ sizeof( in ) ]; - m_in->lastppqPos = 0; - m_in->m_Timestamp = -1; - m_in->m_lastFlags = 0; - // process until we have loaded the plugin while( 1 ) { @@ -817,7 +811,7 @@ void RemoteVstPlugin::initEditor() pluginDispatch( effEditOpen, 0, 0, m_window ); - ERect * er; + ERect* er = nullptr; pluginDispatch( effEditGetRect, 0, 0, &er ); m_windowWidth = er->right - er->left; @@ -857,7 +851,7 @@ void RemoteVstPlugin::initEditor() // change name XStoreName(m_display, m_window, pluginName()); - ERect * er; + ERect* er = nullptr; pluginDispatch(effEditGetRect, 0, 0, &er); m_windowWidth = er->right - er->left; @@ -946,7 +940,7 @@ 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 ) + if ((m_libInst = LoadLibraryW(toWString(_plugin_file).get())) == nullptr) { DWORD error = GetLastError(); debugMessage( "LoadLibrary failed: " + GetErrorAsString(error) ); @@ -1033,6 +1027,7 @@ void RemoteVstPlugin::process( const SampleFrame* _in, SampleFrame* _out ) // first sort events chronologically, since some plugins // (e.g. Sinnah) can hang if they're out of order + // TODO: Sort on the server side instead std::stable_sort( m_midiEvents.begin(), m_midiEvents.end(), []( const VstMidiEvent &a, const VstMidiEvent &b ) { @@ -1131,6 +1126,7 @@ void RemoteVstPlugin::processMidiEvent( const MidiEvent& event, const f_cnt_t of } vme.midiData[3] = 0; + // TODO: Would this cause a data race with the process method? The two methods must not be called concurrently m_midiEvents.push_back( vme ); } @@ -1288,10 +1284,10 @@ void RemoteVstPlugin::saveChunkToFile( const std::string & _file ) if( m_plugin->flags & 32 ) { void * chunk = nullptr; - const int len = pluginDispatch( 23, 0, 0, &chunk ); + const int len = pluginDispatch(effGetChunk, 0, 0, &chunk); if( len > 0 ) { - FILE* fp = F_OPEN_UTF8( _file, "wb" ); + FILE* fp = fopenUtf8(_file, "wb"); if (!fp) { fprintf( stderr, @@ -1364,13 +1360,13 @@ void RemoteVstPlugin::getProgramNames() char presName[1024+256*30]; char curProgName[30]; if (isInitialized() == false) return; - bool progNameIndexed = ( pluginDispatch( 29, 0, -1, curProgName ) == 1 ); + bool progNameIndexed = pluginDispatch(effGetProgramNameIndexed, 0, -1, curProgName) == 1; if (m_plugin->numPrograms > 1) { if (progNameIndexed) { for (int i = 0; i< (m_plugin->numPrograms >= 256?256:m_plugin->numPrograms); i++) { - pluginDispatch( 29, i, -1, curProgName ); + pluginDispatch(effGetProgramNameIndexed, i, -1, curProgName); if (i == 0) sprintf( presName, "%s", curProgName ); else sprintf( presName + strlen(presName), "|%s", curProgName ); } @@ -1401,7 +1397,7 @@ inline unsigned int endian_swap(unsigned int& x) return (x>>24) | ((x<<8) & 0x00FF0000) | ((x>>8) & 0x0000FF00) | (x<<24); } -struct sBank +struct Bank { unsigned int chunkMagic; unsigned int byteSize; @@ -1416,9 +1412,9 @@ struct sBank void RemoteVstPlugin::savePreset( const std::string & _file ) { unsigned int chunk_size = 0; - auto pBank = (sBank*)new char[sizeof(sBank)]; + auto bank = Bank{}; char progName[ 128 ] = { 0 }; - char* data = nullptr; + char* data = nullptr; // TODO: Fix convoluted and potentially leaky memory management const bool chunky = ( m_plugin->flags & ( 1 << 5 ) ) != 0; bool isPreset = _file.substr( _file.find_last_of( "." ) + 1 ) == "fxp"; int presNameLen = _file.find_last_of( "/" ) + _file.find_last_of( "\\" ) + 2; @@ -1426,73 +1422,90 @@ void RemoteVstPlugin::savePreset( const std::string & _file ) if (isPreset) { for (size_t i = 0; i < _file.length() - 4 - presNameLen; i++) + { progName[i] = i < 23 ? _file[presNameLen + i] : 0; - pluginDispatch( 4, 0, 0, progName ); + } + pluginDispatch(effSetProgramName, 0, 0, progName); } - if ( chunky ) - chunk_size = pluginDispatch( 23, isPreset, 0, &data ); - else { - if (isPreset) { + + if (chunky) + { + chunk_size = pluginDispatch(effGetChunk, isPreset, 0, &data); + } + else + { + if (isPreset) + { chunk_size = m_plugin->numParams * sizeof( float ); data = new char[ chunk_size ]; auto toUIntArray = reinterpret_cast(data); for ( int i = 0; i < m_plugin->numParams; i++ ) { float value = m_plugin->getParameter( m_plugin, i ); - auto pValue = (unsigned int*)&value; + auto pValue = reinterpret_cast(&value); toUIntArray[ i ] = endian_swap( *pValue ); } - } else chunk_size = (((m_plugin->numParams * sizeof( float )) + 56)*m_plugin->numPrograms); + } + else + { + chunk_size = (((m_plugin->numParams * sizeof(float)) + 56) * m_plugin->numPrograms); + } } - pBank->chunkMagic = 0x4B6E6343; - pBank->byteSize = chunk_size + ( chunky ? sizeof( int ) : 0 ) + 48; - if (!isPreset) pBank->byteSize += 100; - pBank->byteSize = endian_swap( pBank->byteSize ); - pBank->fxMagic = chunky ? 0x68435046 : 0x6B437846; - if (!isPreset && chunky) pBank->fxMagic = 0x68434246; - if (!isPreset &&!chunky) pBank->fxMagic = 0x6B427846; + bank.chunkMagic = 0x4B6E6343; + bank.byteSize = chunk_size + (chunky ? sizeof(int) : 0) + 48; + if (!isPreset) { bank.byteSize += 100; } + bank.byteSize = endian_swap(bank.byteSize); + bank.fxMagic = chunky ? 0x68435046 : 0x6B437846; + if (!isPreset && chunky) { bank.fxMagic = 0x68434246; } + if (!isPreset && !chunky) { bank.fxMagic = 0x6B427846; } - pBank->version = 0x01000000; + bank.version = 0x01000000; auto uIntToFile = (unsigned int)m_plugin->uniqueID; - pBank->fxID = endian_swap( uIntToFile ); + bank.fxID = endian_swap(uIntToFile); uIntToFile = (unsigned int) pluginVersion(); - pBank->fxVersion = endian_swap( uIntToFile ); + bank.fxVersion = endian_swap(uIntToFile); uIntToFile = (unsigned int) chunky ? m_plugin->numPrograms : m_plugin->numParams; if (!isPreset &&!chunky) uIntToFile = (unsigned int) m_plugin->numPrograms; - pBank->numPrograms = endian_swap( uIntToFile ); + bank.numPrograms = endian_swap(uIntToFile); - FILE * stream = F_OPEN_UTF8( _file, "wb" ); + FILE* stream = fopenUtf8(_file, "wb"); if (!stream) { fprintf( stderr, "Error opening file for saving preset.\n" ); return; } - fwrite ( pBank, 1, 28, stream ); + fwrite(&bank, 1, 28, stream); fwrite ( progName, 1, isPreset ? 28 : 128, stream ); if ( chunky ) { uIntToFile = endian_swap( chunk_size ); fwrite ( &uIntToFile, 1, 4, stream ); } - if (pBank->fxMagic != 0x6B427846 ) + + if (bank.fxMagic != 0x6B427846) + { fwrite ( data, 1, chunk_size, stream ); - else { + } + else + { int numPrograms = m_plugin->numPrograms; int currProgram = pluginDispatch( effGetProgram ); chunk_size = (m_plugin->numParams * sizeof( float )); - pBank->byteSize = chunk_size + 48; - pBank->byteSize = endian_swap( pBank->byteSize ); - pBank->fxMagic = 0x6B437846; + bank.byteSize = chunk_size + 48; + bank.byteSize = endian_swap(bank.byteSize); + bank.fxMagic = 0x6B437846; uIntToFile = (unsigned int) m_plugin->numParams; - pBank->numPrograms = endian_swap( uIntToFile ); + bank.numPrograms = endian_swap(uIntToFile); data = new char[ chunk_size ]; - unsigned int* pValue,* toUIntArray = reinterpret_cast( data ); + unsigned int* pValue; + unsigned int* toUIntArray = reinterpret_cast(data); float value; - for (int j = 0; j < numPrograms; j++) { + for (int j = 0; j < numPrograms; j++) + { pluginDispatch( effSetProgram, 0, j ); - pluginDispatch( effGetProgramName, 0, 0, pBank->prgName ); - fwrite ( pBank, 1, 56, stream ); + pluginDispatch(effGetProgramName, 0, 0, bank.prgName); + fwrite(&bank, 1, 56, stream); for ( int i = 0; i < m_plugin->numParams; i++ ) { value = m_plugin->getParameter( m_plugin, i ); @@ -1505,10 +1518,10 @@ void RemoteVstPlugin::savePreset( const std::string & _file ) } fclose( stream ); - if ( !chunky ) + if (!chunky) + { delete[] data; - delete[] (sBank*)pBank; - + } } @@ -1516,93 +1529,120 @@ void RemoteVstPlugin::savePreset( const std::string & _file ) void RemoteVstPlugin::loadPresetFile( const std::string & _file ) { - void * chunk = nullptr; - unsigned int pLen; + std::unique_ptr chunk; + unsigned int pLen = 0; unsigned int len = 0; - sBank pBank; - FILE * stream = F_OPEN_UTF8( _file, "rb" ); + auto bank = Bank{}; + FILE* stream = fopenUtf8(_file, "rb"); if (!stream) { fprintf( stderr, "Error opening file for loading preset.\n" ); return; } - if ( fread ( &pBank, 1, 56, stream ) != 56 ) + + if (fread(&bank, 1, 56, stream) != 56) { fprintf( stderr, "Error loading preset file.\n" ); } - pBank.fxID = endian_swap( pBank.fxID ); - pBank.numPrograms = endian_swap( pBank.numPrograms ); + bank.fxID = endian_swap(bank.fxID); + bank.numPrograms = endian_swap(bank.numPrograms); unsigned int toUInt; float * pFloat; - if (static_cast(m_plugin->uniqueID) != pBank.fxID) { + if (static_cast(m_plugin->uniqueID) != bank.fxID) + { sendMessage( message( IdVstCurrentProgramName ). addString( "Error: Plugin UniqID not match" ) ); fclose( stream ); return; } - if( _file.substr( _file.find_last_of( "." ) + 1 ) != "fxp" ) - fseek ( stream , 156 , SEEK_SET ); + if (_file.substr(_file.find_last_of('.') + 1) != "fxp") + { + fseek(stream, 156, SEEK_SET); + } - if(pBank.fxMagic != 0x6B427846) { - if(pBank.fxMagic != 0x6B437846) { + if (bank.fxMagic != 0x6B427846) + { + if (bank.fxMagic != 0x6B437846) + { if ( fread (&pLen, 1, 4, stream) != 4 ) { fprintf( stderr, "Error loading preset file.\n" ); } - chunk = new char[len = endian_swap(pLen)]; - } else chunk = new char[len = sizeof(float)*pBank.numPrograms]; - if ( fread (chunk, len, 1, stream) != 1 ) + len = endian_swap(pLen); + } + else + { + len = static_cast(sizeof(float) * bank.numPrograms); + } + + chunk = std::make_unique_for_overwrite(len); + if (fread(chunk.get(), len, 1, stream) != 1) { fprintf( stderr, "Error loading preset file.\n" ); } fclose( stream ); } - if(_file.substr(_file.find_last_of(".") + 1) == "fxp") { - pBank.prgName[23] = 0; - pluginDispatch( 4, 0, 0, pBank.prgName ); - if(pBank.fxMagic != 0x6B437846) - pluginDispatch( 24, 1, len, chunk ); + if (_file.substr(_file.find_last_of(".") + 1) == "fxp") + { + // TODO: Could this crash if chunk is null? + bank.prgName[23] = '\0'; + pluginDispatch(effSetProgramName, 0, 0, bank.prgName); + if (bank.fxMagic != 0x6B437846) + { + pluginDispatch(effSetChunk, 1, len, chunk.get()); + } else { - auto toUIntArray = reinterpret_cast(chunk); - for (auto i = 0u; i < pBank.numPrograms; i++) + auto toUIntArray = reinterpret_cast(chunk.get()); + for (auto i = 0u; i < bank.numPrograms; i++) { toUInt = endian_swap( toUIntArray[ i ] ); - pFloat = ( float* ) &toUInt; + pFloat = reinterpret_cast(&toUInt); m_plugin->setParameter( m_plugin, i, *pFloat ); } } - } else { - if(pBank.fxMagic != 0x6B427846) { - pluginDispatch( 24, 0, len, chunk ); - } else { - int numPrograms = pBank.numPrograms; + } + else + { + if (bank.fxMagic != 0x6B427846) + { + // TODO: Could this crash if chunk is null? + pluginDispatch(effSetChunk, 0, len, chunk.get()); + } + else + { + int numPrograms = static_cast(bank.numPrograms); unsigned int * toUIntArray; int currProgram = pluginDispatch( effGetProgram ); - chunk = new char[ len = sizeof(float)*m_plugin->numParams ]; - toUIntArray = reinterpret_cast( chunk ); - for (int i =0; i < numPrograms; i++) { - if ( fread (&pBank, 1, 56, stream) != 56 ) + + len = static_cast(sizeof(float) * m_plugin->numParams); + chunk = std::make_unique_for_overwrite(len); + toUIntArray = reinterpret_cast(chunk.get()); + + for (int i = 0; i < numPrograms; i++) + { + if (fread(&bank, 1, 56, stream) != 56) { fprintf( stderr, "Error loading preset file.\n" ); } - if ( fread (chunk, len, 1, stream) != 1 ) + if (fread(chunk.get(), len, 1, stream) != 1) { fprintf( stderr, "Error loading preset file.\n" ); } pluginDispatch( effSetProgram, 0, i ); - pBank.prgName[23] = 0; - pluginDispatch( 4, 0, 0, pBank.prgName ); - for (int j = 0; j < m_plugin->numParams; j++ ) { + bank.prgName[23] = '\0'; + pluginDispatch(effSetProgramName, 0, 0, bank.prgName); + for (int j = 0; j < m_plugin->numParams; j++) + { toUInt = endian_swap( toUIntArray[ j ] ); - pFloat = ( float* ) &toUInt; + pFloat = reinterpret_cast(&toUInt); m_plugin->setParameter( m_plugin, j, *pFloat ); } } @@ -1612,30 +1652,26 @@ void RemoteVstPlugin::loadPresetFile( const std::string & _file ) } sendCurrentProgramName(); - - delete[] (char*)chunk; } void RemoteVstPlugin::loadChunkFromFile(const std::string& _file, std::size_t _len) { - auto chunk = new char[_len]; - - FILE* fp = F_OPEN_UTF8( _file, "rb" ); + FILE* fp = fopenUtf8(_file, "rb"); if (!fp) { fprintf( stderr, "Error opening file for loading chunk.\n" ); return; } - if ( fread( chunk, 1, _len, fp ) != _len ) + + auto chunk = std::make_unique_for_overwrite(_len); + if (fread(chunk.get(), 1, _len, fp) != _len) { fprintf( stderr, "Error loading chunk from file.\n" ); } close_check( fp ); - pluginDispatch( effSetChunk, 0, _len, chunk ); - - delete[] chunk; + pluginDispatch(effSetChunk, 0, _len, chunk.get()); } @@ -1775,9 +1811,9 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode, memset( &_timeInfo, 0, sizeof( _timeInfo ) ); _timeInfo.samplePos = __plugin->m_currentSamplePos; - _timeInfo.sampleRate = syncData->m_sampleRate; + _timeInfo.sampleRate = syncData->sampleRate; _timeInfo.flags = 0; - _timeInfo.tempo = syncData->m_bpm; + _timeInfo.tempo = syncData->bpm; _timeInfo.timeSigNumerator = syncData->timeSigNumer; _timeInfo.timeSigDenominator = syncData->timeSigDenom; _timeInfo.flags |= kVstTempoValid; @@ -1791,19 +1827,19 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode, _timeInfo.flags |= kVstTransportCycleActive; } - if (syncData->ppqPos != __plugin->m_in->m_Timestamp) + if (syncData->ppqPos != __plugin->m_sync.timestamp) { _timeInfo.ppqPos = syncData->ppqPos; - __plugin->m_in->lastppqPos = syncData->ppqPos; - __plugin->m_in->m_Timestamp = syncData->ppqPos; + __plugin->m_sync.lastppqPos = syncData->ppqPos; + __plugin->m_sync.timestamp = syncData->ppqPos; } else if (syncData->isPlaying) { - __plugin->m_in->lastppqPos += - syncData->m_bpm / 60.0 - * syncData->m_bufferSize - / syncData->m_sampleRate; - _timeInfo.ppqPos = __plugin->m_in->lastppqPos; + __plugin->m_sync.lastppqPos += + syncData->bpm / 60.0 + * syncData->bufferSize + / syncData->sampleRate; + _timeInfo.ppqPos = __plugin->m_sync.lastppqPos; } // _timeInfo.ppqPos = syncData->ppqPos; _timeInfo.flags |= kVstPpqPosValid; @@ -1819,12 +1855,12 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode, _timeInfo.flags |= kVstBarsValid; if ((_timeInfo.flags & (kVstTransportPlaying | kVstTransportCycleActive)) - != (__plugin->m_in->m_lastFlags & (kVstTransportPlaying | kVstTransportCycleActive)) - || syncData->m_playbackJumped) + != (__plugin->m_sync.lastFlags & (kVstTransportPlaying | kVstTransportCycleActive)) + || syncData->playbackJumped) { _timeInfo.flags |= kVstTransportChanged; } - __plugin->m_in->m_lastFlags = _timeInfo.flags; + __plugin->m_sync.lastFlags = _timeInfo.flags; return (intptr_t) &_timeInfo; } @@ -2219,7 +2255,7 @@ void * RemoteVstPlugin::processingThread(void * _param) PostMessage( __MessageHwnd, WM_USER, static_cast(GuiThreadMessage::ProcessPluginMessage), - (LPARAM) new message( m ) ); + reinterpret_cast(new message(m))); #else _this->queueMessage( m ); #endif diff --git a/plugins/VstBase/RemoteVstPlugin/CMakeLists.txt b/plugins/VstBase/RemoteVstPlugin/CMakeLists.txt index 3f861e2d5..b360f1c9c 100644 --- a/plugins/VstBase/RemoteVstPlugin/CMakeLists.txt +++ b/plugins/VstBase/RemoteVstPlugin/CMakeLists.txt @@ -6,7 +6,7 @@ endif() project(RemoteVstPlugin LANGUAGES CXX) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) include(CheckCXXPreprocessor) include(CheckCXXSourceCompiles) @@ -59,8 +59,7 @@ if(LMMS_HAVE_LIBRT) endif() target_include_directories(${EXE_NAME} - PRIVATE - "${LMMS_SOURCE_DIR}/plugins/vst_base/common" + PRIVATE "${LMMS_SOURCE_DIR}/include" "${LMMS_BINARY_DIR}" ) @@ -73,7 +72,7 @@ if(MSVC) endif() if(IS_MINGW) - SET(CMAKE_REQUIRED_FLAGS "-std=c++17") + SET(CMAKE_REQUIRED_FLAGS "-std=c++20") endif() if(LMMS_BUILD_WIN32) diff --git a/plugins/ZynAddSubFx/LocalZynAddSubFx.cpp b/plugins/ZynAddSubFx/LocalZynAddSubFx.cpp index 5dc8fb205..63496dec7 100644 --- a/plugins/ZynAddSubFx/LocalZynAddSubFx.cpp +++ b/plugins/ZynAddSubFx/LocalZynAddSubFx.cpp @@ -151,7 +151,7 @@ void LocalZynAddSubFx::loadXML( const std::string & _filename ) m_master->applyparameters(); #ifdef LMMS_BUILD_WIN32 - _wunlink(toWString(_filename).c_str()); + _wunlink(toWString(_filename).get()); #else unlink( f ); #endif diff --git a/plugins/ZynAddSubFx/zynaddsubfx b/plugins/ZynAddSubFx/zynaddsubfx index db8ffedb7..66a42efcc 160000 --- a/plugins/ZynAddSubFx/zynaddsubfx +++ b/plugins/ZynAddSubFx/zynaddsubfx @@ -1 +1 @@ -Subproject commit db8ffedb7212a7ed9777ffacb9118afbbf779d7c +Subproject commit 66a42efcc72d4d75a70412795f1510c4297ab826 diff --git a/src/core/VstSyncController.cpp b/src/core/VstSyncController.cpp index 984b1b32c..c5b33a05f 100644 --- a/src/core/VstSyncController.cpp +++ b/src/core/VstSyncController.cpp @@ -52,7 +52,7 @@ VstSyncController::VstSyncController() } m_syncData->isPlaying = false; - m_syncData->m_bufferSize = Engine::audioEngine()->framesPerPeriod(); + m_syncData->bufferSize = Engine::audioEngine()->framesPerPeriod(); m_syncData->timeSigNumer = 4; m_syncData->timeSigDenom = 4; @@ -67,9 +67,9 @@ void VstSyncController::setAbsolutePosition(double ticks) if (!m_syncData) { return; } #ifdef VST_SNC_LATENCY - m_syncData->ppqPos = ( ( ticks + 0 ) / 48.0 ) - m_syncData->m_latency; + m_syncData->ppqPos = ((ticks + 0) / 48.0) - m_syncData->latency; #else - m_syncData->ppqPos = ( ( ticks + 0 ) / 48.0 ); + m_syncData->ppqPos = ((ticks + 0) / 48.0); #endif } @@ -88,10 +88,10 @@ void VstSyncController::setTempo(int newTempo) { if (!m_syncData) { return; } - m_syncData->m_bpm = newTempo; + m_syncData->bpm = newTempo; #ifdef VST_SNC_LATENCY - m_syncData->m_latency = m_syncData->m_bufferSize * newTempo / ( (float) m_syncData->m_sampleRate * 60 ); + m_syncData->latency = m_syncData->bufferSize * newTempo / (static_cast(m_syncData->sampleRate) * 60); #endif } @@ -132,7 +132,7 @@ void VstSyncController::setPlaybackJumped(bool jumped) { if (!m_syncData) { return; } - m_syncData->m_playbackJumped = jumped; + m_syncData->playbackJumped = jumped; } @@ -141,10 +141,10 @@ void VstSyncController::update() { if (!m_syncData) { return; } - m_syncData->m_bufferSize = Engine::audioEngine()->framesPerPeriod(); + m_syncData->bufferSize = Engine::audioEngine()->framesPerPeriod(); #ifdef VST_SNC_LATENCY - m_syncData->m_latency = m_syncData->m_bufferSize * m_syncData->m_bpm / ( (float) m_syncData->m_sampleRate * 60 ); + m_syncData->latency = m_syncData->bufferSize * m_syncData->bpm / (static_cast(m_syncData->sampleRate) * 60); #endif } @@ -154,10 +154,10 @@ void VstSyncController::updateSampleRate() { if (!m_syncData) { return; } - m_syncData->m_sampleRate = Engine::audioEngine()->outputSampleRate(); + m_syncData->sampleRate = Engine::audioEngine()->outputSampleRate(); #ifdef VST_SNC_LATENCY - m_syncData->m_latency = m_syncData->m_bufferSize * m_syncData->m_bpm / ( (float) m_syncData->m_sampleRate * 60 ); + m_syncData->latency = m_syncData->bufferSize * m_syncData->bpm / (static_cast(m_syncData->sampleRate) * 60); #endif }