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
This commit is contained in:
Dalton Messmer
2025-07-10 02:08:42 -04:00
committed by GitHub
parent 4c3f8191af
commit 1641f5f95f
11 changed files with 255 additions and 183 deletions

View File

@@ -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 <cstdio>
#include <limits>
#include <memory>
#include <stdexcept>
#include <string>
#include <string_view>
#ifdef _WIN32
#include <windows.h>
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
#endif
#ifdef LMMS_BUILD_WIN32
#include <io.h>
#else
#ifdef LMMS_HAVE_UNISTD_H
#include <unistd.h>
#if defined(_WIN32) && !defined(__WINE__)
# include <io.h>
#elif __has_include(<unistd.h>)
# include <unistd.h>
#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<wchar_t[]> 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<wchar_t[]> ret;
if (utf8.empty())
{
ret = std::make_unique<wchar_t[]>(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::size_t>(std::numeric_limits<int>::max()))
{
throw std::overflow_error{"toWString: input string is too long"};
}
const auto utf8Len = static_cast<int>(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<wchar_t[]>(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;
}

View File

@@ -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<float>::max())
{
if (ok != nullptr) {*ok = false;}
if (ok != nullptr) { *ok = false; }
return 0.0f;
}
return static_cast<float>(d);

View File

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

View File

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

View File

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