mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
VST3: Allow manifest helper to run independently
This commit is contained in:
parent
80116d60da
commit
f3d7c74ea1
46 changed files with 1299 additions and 1519 deletions
|
|
@ -1,441 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Project : VST SDK
|
||||
// Flags : clang-format SMTGSequencer
|
||||
//
|
||||
// Category : moduleinfotool
|
||||
// Filename : public.sdk/samples/vst-utilities/moduleinfotool/main.cpp
|
||||
// Created by : Steinberg, 12/2021
|
||||
// Description : main entry point
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// LICENSE
|
||||
// (c) 2024, Steinberg Media Technologies GmbH, All Rights Reserved
|
||||
//-----------------------------------------------------------------------------
|
||||
// Redistribution and use in source and binary forms, with or without modification,
|
||||
// are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
||||
// this list of conditions and the following disclaimer in the documentation
|
||||
// and/or other materials provided with the distribution.
|
||||
// * Neither the name of the Steinberg Media Technologies nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from this
|
||||
// software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
// OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "pluginterfaces/base/iplugincompatibility.h"
|
||||
#include "public.sdk/source/common/memorystream.h"
|
||||
|
||||
#include "public.sdk/source/common/readfile.h"
|
||||
#include "public.sdk/source/vst/hosting/module.h"
|
||||
#include "public.sdk/source/vst/moduleinfo/moduleinfocreator.h"
|
||||
#include "public.sdk/source/vst/moduleinfo/moduleinfoparser.h"
|
||||
#include "public.sdk/source/vst/utility/stringconvert.h"
|
||||
#include "base/source/fcommandline.h"
|
||||
#include "pluginterfaces/base/fplatform.h"
|
||||
#include "pluginterfaces/vst/vsttypes.h"
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace Steinberg {
|
||||
namespace ModuleInfoTool {
|
||||
namespace {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
constexpr auto BUILD_INFO = "moduleinfotool 1.0.0 [Built " __DATE__ "]";
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
//-- Options
|
||||
constexpr auto optHelp = "help";
|
||||
constexpr auto optCreate = "create";
|
||||
constexpr auto optValidate = "validate";
|
||||
constexpr auto optModuleVersion = "version";
|
||||
constexpr auto optModulePath = "path";
|
||||
constexpr auto optInfoPath = "infopath";
|
||||
constexpr auto optModuleCompatPath = "compat";
|
||||
constexpr auto optOutputPath = "output";
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void printUsage (std::ostream& s)
|
||||
{
|
||||
s << "Usage:\n";
|
||||
s << " moduleinfotool -create -version VERSION -path MODULE_PATH [-compat PATH -output PATH]\n";
|
||||
s << " moduleinfotool -validate -path MODULE_PATH [-infopath PATH]\n";
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
std::optional<ModuleInfo::CompatibilityList> openAndParseCompatJSON (const std::string& path)
|
||||
{
|
||||
auto data = readFile (path);
|
||||
if (data.empty ())
|
||||
{
|
||||
std::cout << "Can not read '" << path << "'\n";
|
||||
printUsage (std::cout);
|
||||
return {};
|
||||
}
|
||||
std::stringstream error;
|
||||
auto result = ModuleInfoLib::parseCompatibilityJson (data, &error);
|
||||
if (!result)
|
||||
{
|
||||
std::cout << "Can not parse '" << path << "'\n";
|
||||
std::cout << error.str ();
|
||||
printUsage (std::cout);
|
||||
return {};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
std::optional<ModuleInfo::CompatibilityList> loadCompatibilityFromModule (const VST3::Hosting::Module& module)
|
||||
{
|
||||
const auto& factory = module.getFactory();
|
||||
const auto& infos = factory.classInfos();
|
||||
|
||||
const auto iter = std::find_if (infos.begin(), infos.end(), [&] (const auto& info)
|
||||
{
|
||||
return info.category() == kPluginCompatibilityClass;
|
||||
});
|
||||
|
||||
if (iter == infos.end())
|
||||
return {};
|
||||
|
||||
const auto compatibility = factory.createInstance<Steinberg::IPluginCompatibility> (iter->ID());
|
||||
|
||||
if (compatibility == nullptr)
|
||||
return {};
|
||||
|
||||
Steinberg::MemoryStream stream;
|
||||
|
||||
if (compatibility->getCompatibilityJSON (&stream) != kResultOk)
|
||||
return {};
|
||||
|
||||
const std::string_view streamView (stream.getData(), stream.getSize());
|
||||
|
||||
return ModuleInfoLib::parseCompatibilityJson (streamView, nullptr);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int createJSON (const std::optional<ModuleInfo::CompatibilityList>& compat,
|
||||
const std::string& modulePath, const std::string& moduleVersion,
|
||||
std::ostream& outStream)
|
||||
{
|
||||
std::string errorStr;
|
||||
auto module = VST3::Hosting::Module::create (modulePath, errorStr);
|
||||
if (!module)
|
||||
{
|
||||
std::cout << errorStr;
|
||||
return 1;
|
||||
}
|
||||
auto moduleInfo = ModuleInfoLib::createModuleInfo (*module, false);
|
||||
if (compat)
|
||||
moduleInfo.compatibility = *compat;
|
||||
else if (auto loaded = loadCompatibilityFromModule (*module))
|
||||
moduleInfo.compatibility = *loaded;
|
||||
|
||||
moduleInfo.version = moduleVersion;
|
||||
|
||||
std::stringstream output;
|
||||
ModuleInfoLib::outputJson (moduleInfo, output);
|
||||
auto str = output.str ();
|
||||
outStream << str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct validate_error : std::exception
|
||||
{
|
||||
validate_error (const std::string& str) : str (str) {}
|
||||
const char* what () const noexcept override { return str.data (); }
|
||||
|
||||
private:
|
||||
std::string str;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void validate (const ModuleInfo& moduleInfo, const VST3::Hosting::Module& module)
|
||||
{
|
||||
auto factory = module.getFactory ();
|
||||
auto factoryInfo = factory.info ();
|
||||
auto classInfoList = factory.classInfos ();
|
||||
auto snapshotList = module.getSnapshots (module.getPath ());
|
||||
|
||||
if (factoryInfo.vendor () != moduleInfo.factoryInfo.vendor)
|
||||
throw validate_error ("factoryInfo.vendor different: " + moduleInfo.factoryInfo.vendor);
|
||||
if (factoryInfo.url () != moduleInfo.factoryInfo.url)
|
||||
throw validate_error ("factoryInfo.url different: " + moduleInfo.factoryInfo.url);
|
||||
if (factoryInfo.email () != moduleInfo.factoryInfo.email)
|
||||
throw validate_error ("factoryInfo.email different: " + moduleInfo.factoryInfo.email);
|
||||
if (factoryInfo.flags () != moduleInfo.factoryInfo.flags)
|
||||
throw validate_error ("factoryInfo.flags different: " +
|
||||
std::to_string (moduleInfo.factoryInfo.flags));
|
||||
|
||||
for (const auto& ci : moduleInfo.classes)
|
||||
{
|
||||
auto cid = VST3::UID::fromString (ci.cid);
|
||||
if (!cid)
|
||||
throw validate_error ("could not parse class UID: " + ci.cid);
|
||||
auto it = std::find_if (classInfoList.begin (), classInfoList.end (),
|
||||
[&] (const auto& el) { return el.ID () == *cid; });
|
||||
if (it == classInfoList.end ())
|
||||
throw validate_error ("cannot find CID in class list: " + ci.cid);
|
||||
if (it->name () != ci.name)
|
||||
throw validate_error ("class name different: " + ci.name);
|
||||
if (it->category () != ci.category)
|
||||
throw validate_error ("class category different: " + ci.category);
|
||||
if (it->vendor () != ci.vendor)
|
||||
throw validate_error ("class vendor different: " + ci.vendor);
|
||||
if (it->version () != ci.version)
|
||||
throw validate_error ("class version different: " + ci.version);
|
||||
if (it->sdkVersion () != ci.sdkVersion)
|
||||
throw validate_error ("class sdkVersion different: " + ci.sdkVersion);
|
||||
if (it->subCategories () != ci.subCategories)
|
||||
throw validate_error ("class subCategories different: " /* + ci.subCategories*/);
|
||||
if (it->cardinality () != ci.cardinality)
|
||||
throw validate_error ("class cardinality different: " +
|
||||
std::to_string (ci.cardinality));
|
||||
if (it->classFlags () != ci.flags)
|
||||
throw validate_error ("class flags different: " + std::to_string (ci.flags));
|
||||
classInfoList.erase (it);
|
||||
|
||||
auto snapshotListIt = std::find_if (snapshotList.begin (), snapshotList.end (),
|
||||
[&] (const auto& el) { return el.uid == *cid; });
|
||||
if (snapshotListIt == snapshotList.end () && !ci.snapshots.empty ())
|
||||
throw validate_error ("cannot find snapshots for: " + ci.cid);
|
||||
for (const auto& snapshot : ci.snapshots)
|
||||
{
|
||||
auto snapshotIt = std::find_if (
|
||||
snapshotListIt->images.begin (), snapshotListIt->images.end (),
|
||||
[&] (const auto& el) { return el.scaleFactor == snapshot.scaleFactor; });
|
||||
if (snapshotIt == snapshotListIt->images.end ())
|
||||
throw validate_error ("cannot find snapshots for scale factor: " +
|
||||
std::to_string (snapshot.scaleFactor));
|
||||
std::string_view path (snapshotIt->path);
|
||||
if (path.find (module.getPath ()) == 0)
|
||||
path.remove_prefix (module.getPath ().size () + 1);
|
||||
if (path != snapshot.path)
|
||||
throw validate_error ("cannot find snapshots with path: " + snapshot.path);
|
||||
snapshotListIt->images.erase (snapshotIt);
|
||||
}
|
||||
if (snapshotListIt != snapshotList.end () && !snapshotListIt->images.empty ())
|
||||
{
|
||||
std::string errorStr = "Missing Snapshots in moduleinfo:\n";
|
||||
for (const auto& s : snapshotListIt->images)
|
||||
{
|
||||
errorStr += s.path + '\n';
|
||||
}
|
||||
throw validate_error (errorStr);
|
||||
}
|
||||
if (snapshotListIt != snapshotList.end ())
|
||||
snapshotList.erase (snapshotListIt);
|
||||
}
|
||||
if (!classInfoList.empty ())
|
||||
throw validate_error ("Missing classes in moduleinfo");
|
||||
if (!snapshotList.empty ())
|
||||
throw validate_error ("Missing snapshots in moduleinfo");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int validate (const std::string& modulePath, std::string infoJsonPath)
|
||||
{
|
||||
if (infoJsonPath.empty ())
|
||||
{
|
||||
auto path = VST3::Hosting::Module::getModuleInfoPath (modulePath);
|
||||
if (!path)
|
||||
{
|
||||
std::cerr << "Module does not contain a moduleinfo.json: '" << modulePath << "'"
|
||||
<< '\n';
|
||||
return 1;
|
||||
}
|
||||
infoJsonPath = *path;
|
||||
}
|
||||
|
||||
auto data = readFile (infoJsonPath);
|
||||
if (data.empty ())
|
||||
{
|
||||
std::cerr << "Empty or non existing file: '" << infoJsonPath << "'" << '\n';
|
||||
printUsage (std::cout);
|
||||
return 1;
|
||||
}
|
||||
auto moduleInfo = ModuleInfoLib::parseJson (data, &std::cerr);
|
||||
if (moduleInfo)
|
||||
{
|
||||
std::string errorStr;
|
||||
auto module = VST3::Hosting::Module::create (modulePath, errorStr);
|
||||
if (!module)
|
||||
{
|
||||
std::cerr << errorStr;
|
||||
printUsage (std::cout);
|
||||
return 1;
|
||||
}
|
||||
try
|
||||
{
|
||||
validate (*moduleInfo, *module);
|
||||
}
|
||||
catch (const std::exception& exc)
|
||||
{
|
||||
std::cerr << "Error:\n" << exc.what () << '\n';
|
||||
printUsage (std::cout);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
printUsage (std::cout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // anonymous
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int run (int argc, char* argv[])
|
||||
{
|
||||
// parse command line
|
||||
CommandLine::Descriptions desc;
|
||||
CommandLine::VariablesMap valueMap;
|
||||
CommandLine::FilesVector files;
|
||||
|
||||
using Description = CommandLine::Description;
|
||||
desc.addOptions (
|
||||
BUILD_INFO,
|
||||
{
|
||||
{optCreate, "Create moduleinfo", Description::kBool},
|
||||
{optValidate, "Validate moduleinfo", Description::kBool},
|
||||
{optModuleVersion, "Module version", Description::kString},
|
||||
{optModulePath, "Path to module", Description::kString},
|
||||
{optInfoPath, "Path to moduleinfo.json", Description::kString},
|
||||
{optModuleCompatPath, "Path to compatibility.json", Description::kString},
|
||||
{optOutputPath, "Write json to file instead of stdout", Description::kString},
|
||||
{optHelp, "Print help", Description::kBool},
|
||||
});
|
||||
CommandLine::parse (argc, argv, desc, valueMap, &files);
|
||||
|
||||
bool isCreate = valueMap.count (optCreate) != 0 && valueMap.count (optModuleVersion) != 0 &&
|
||||
valueMap.count (optModulePath) != 0;
|
||||
bool isValidate = valueMap.count (optValidate) && valueMap.count (optModulePath) != 0;
|
||||
|
||||
if (valueMap.hasError () || valueMap.count (optHelp) || !(isCreate || isValidate))
|
||||
{
|
||||
std::cout << '\n' << desc << '\n';
|
||||
printUsage (std::cout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int result = 1;
|
||||
|
||||
const auto& modulePath = valueMap[optModulePath];
|
||||
if (isCreate)
|
||||
{
|
||||
auto* outputStream = &std::cout;
|
||||
std::optional<ModuleInfo::CompatibilityList> compat;
|
||||
if (valueMap.count (optModuleCompatPath) != 0)
|
||||
{
|
||||
const auto& compatPath = valueMap[optModuleCompatPath];
|
||||
compat = openAndParseCompatJSON (compatPath);
|
||||
if (!compat)
|
||||
return 1;
|
||||
}
|
||||
bool writeToFile = false;
|
||||
if (valueMap.count (optOutputPath) != 0)
|
||||
{
|
||||
writeToFile = true;
|
||||
#if SMTG_OS_WINDOWS
|
||||
auto tmp = Vst::StringConvert::convert (valueMap[optOutputPath]);
|
||||
auto outputFile = reinterpret_cast<const wchar_t*> (tmp.data ());
|
||||
#else
|
||||
auto outputFile = valueMap[optOutputPath];
|
||||
#endif
|
||||
auto ostream = new std::ofstream (outputFile);
|
||||
|
||||
if (ostream->is_open ())
|
||||
outputStream = ostream;
|
||||
else
|
||||
{
|
||||
std::cout << "Cannot create output file: " << valueMap[optOutputPath] << '\n';
|
||||
return result;
|
||||
}
|
||||
}
|
||||
const auto& moduleVersion = valueMap[optModuleVersion];
|
||||
result = createJSON (compat, modulePath, moduleVersion, *outputStream);
|
||||
if (writeToFile)
|
||||
delete outputStream;
|
||||
}
|
||||
else if (isValidate)
|
||||
{
|
||||
std::string moduleInfoJsonPath;
|
||||
if (valueMap.count (optInfoPath) != 0)
|
||||
moduleInfoJsonPath = valueMap[optInfoPath];
|
||||
result = validate (modulePath, moduleInfoJsonPath);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // ModuleInfoTool
|
||||
} // Steinberg
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
#if SMTG_OS_WINDOWS
|
||||
//------------------------------------------------------------------------
|
||||
using Utf8String = std::string;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
using Utf8Args = std::vector<Utf8String>;
|
||||
Utf8Args toUtf8Args (int argc, wchar_t* wargv[])
|
||||
{
|
||||
Utf8Args utf8Args;
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
auto str = reinterpret_cast<const Steinberg::Vst::TChar*> (wargv[i]);
|
||||
utf8Args.push_back (Steinberg::Vst::StringConvert::convert (str));
|
||||
}
|
||||
|
||||
return utf8Args;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
using Utf8ArgPtrs = std::vector<char*>;
|
||||
Utf8ArgPtrs toUtf8ArgPtrs (Utf8Args& utf8Args)
|
||||
{
|
||||
Utf8ArgPtrs utf8ArgPtrs;
|
||||
for (auto& el : utf8Args)
|
||||
{
|
||||
utf8ArgPtrs.push_back (el.data ());
|
||||
}
|
||||
|
||||
return utf8ArgPtrs;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int wmain (int argc, wchar_t* wargv[])
|
||||
{
|
||||
Utf8Args utf8Args = toUtf8Args (argc, wargv);
|
||||
Utf8ArgPtrs utf8ArgPtrs = toUtf8ArgPtrs (utf8Args);
|
||||
|
||||
char** argv = &(utf8ArgPtrs.at (0));
|
||||
return Steinberg::ModuleInfoTool::run (argc, argv);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int main (int argc, char* argv[])
|
||||
{
|
||||
return Steinberg::ModuleInfoTool::run (argc, argv);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
#endif // SMTG_OS_WINDOWS
|
||||
|
|
@ -41,129 +41,6 @@ namespace juce
|
|||
|
||||
JUCE_BEGIN_NO_SANITIZE ("vptr")
|
||||
|
||||
//==============================================================================
|
||||
#define JUCE_DECLARE_VST3_COM_REF_METHODS \
|
||||
Steinberg::uint32 PLUGIN_API addRef() override { return (Steinberg::uint32) ++refCount; } \
|
||||
Steinberg::uint32 PLUGIN_API release() override { const int r = --refCount; if (r == 0) delete this; return (Steinberg::uint32) r; }
|
||||
|
||||
#define JUCE_DECLARE_VST3_COM_QUERY_METHODS \
|
||||
Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID, void** obj) override \
|
||||
{ \
|
||||
jassertfalse; \
|
||||
*obj = nullptr; \
|
||||
return Steinberg::kNotImplemented; \
|
||||
}
|
||||
|
||||
inline bool doUIDsMatch (const Steinberg::TUID a, const Steinberg::TUID b) noexcept
|
||||
{
|
||||
return std::memcmp (a, b, sizeof (Steinberg::TUID)) == 0;
|
||||
}
|
||||
|
||||
/* Holds a tresult and a pointer to an object.
|
||||
|
||||
Useful for holding intermediate results of calls to queryInterface.
|
||||
*/
|
||||
class QueryInterfaceResult
|
||||
{
|
||||
public:
|
||||
QueryInterfaceResult() = default;
|
||||
|
||||
QueryInterfaceResult (Steinberg::tresult resultIn, void* ptrIn)
|
||||
: result (resultIn), ptr (ptrIn) {}
|
||||
|
||||
bool isOk() const noexcept { return result == Steinberg::kResultOk; }
|
||||
|
||||
Steinberg::tresult extract (void** obj) const
|
||||
{
|
||||
*obj = result == Steinberg::kResultOk ? ptr : nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
Steinberg::tresult result = Steinberg::kResultFalse;
|
||||
void* ptr = nullptr;
|
||||
};
|
||||
|
||||
/* Holds a tresult and a pointer to an object.
|
||||
|
||||
Calling InterfaceResultWithDeferredAddRef::extract() will also call addRef
|
||||
on the pointed-to object. It is expected that users will use
|
||||
InterfaceResultWithDeferredAddRef to hold intermediate results of a queryInterface
|
||||
call. When a suitable interface is found, the function can be exited with
|
||||
`return suitableInterface.extract (obj)`, which will set the obj pointer,
|
||||
add a reference to the interface, and return the appropriate result code.
|
||||
*/
|
||||
class InterfaceResultWithDeferredAddRef
|
||||
{
|
||||
public:
|
||||
InterfaceResultWithDeferredAddRef() = default;
|
||||
|
||||
template <typename Ptr>
|
||||
InterfaceResultWithDeferredAddRef (Steinberg::tresult resultIn, Ptr* ptrIn)
|
||||
: result (resultIn, ptrIn),
|
||||
addRefFn (doAddRef<Ptr>) {}
|
||||
|
||||
bool isOk() const noexcept { return result.isOk(); }
|
||||
|
||||
Steinberg::tresult extract (void** obj) const
|
||||
{
|
||||
const auto toReturn = result.extract (obj);
|
||||
|
||||
if (result.isOk() && *obj != nullptr)
|
||||
NullCheckedInvocation::invoke (addRefFn, *obj);
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Ptr>
|
||||
static void doAddRef (void* obj) { static_cast<Ptr*> (obj)->addRef(); }
|
||||
|
||||
QueryInterfaceResult result;
|
||||
void (*addRefFn) (void*) = nullptr;
|
||||
};
|
||||
|
||||
template <typename ClassType> struct UniqueBase {};
|
||||
template <typename CommonClassType, typename SourceClassType> struct SharedBase {};
|
||||
|
||||
template <typename ToTest, typename CommonClassType, typename SourceClassType>
|
||||
InterfaceResultWithDeferredAddRef testFor (ToTest& toTest,
|
||||
const Steinberg::TUID targetIID,
|
||||
SharedBase<CommonClassType, SourceClassType>)
|
||||
{
|
||||
if (! doUIDsMatch (targetIID, CommonClassType::iid))
|
||||
return {};
|
||||
|
||||
return { Steinberg::kResultOk, static_cast<CommonClassType*> (static_cast<SourceClassType*> (std::addressof (toTest))) };
|
||||
}
|
||||
|
||||
template <typename ToTest, typename ClassType>
|
||||
InterfaceResultWithDeferredAddRef testFor (ToTest& toTest,
|
||||
const Steinberg::TUID targetIID,
|
||||
UniqueBase<ClassType>)
|
||||
{
|
||||
return testFor (toTest, targetIID, SharedBase<ClassType, ClassType>{});
|
||||
}
|
||||
|
||||
template <typename ToTest>
|
||||
InterfaceResultWithDeferredAddRef testForMultiple (ToTest&, const Steinberg::TUID) { return {}; }
|
||||
|
||||
template <typename ToTest, typename Head, typename... Tail>
|
||||
InterfaceResultWithDeferredAddRef testForMultiple (ToTest& toTest, const Steinberg::TUID targetIID, Head head, Tail... tail)
|
||||
{
|
||||
const auto result = testFor (toTest, targetIID, head);
|
||||
|
||||
if (result.isOk())
|
||||
return result;
|
||||
|
||||
return testForMultiple (toTest, targetIID, tail...);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if VST_VERSION < 0x030608
|
||||
#define kAmbi1stOrderACN kBFormat
|
||||
#endif
|
||||
|
||||
//==============================================================================
|
||||
inline juce::String toString (const Steinberg::char8* string) noexcept { return juce::String (juce::CharPointer_UTF8 ((juce::CharPointer_UTF8::CharType*) string)); }
|
||||
inline juce::String toString (const Steinberg::char16* string) noexcept { return juce::String (juce::CharPointer_UTF16 ((juce::CharPointer_UTF16::CharType*) string)); }
|
||||
|
|
@ -184,6 +61,11 @@ inline void toString128 (Steinberg::Vst::String128 result, const juce::String& s
|
|||
Steinberg::UString (result, 128).assign (toString (source));
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
#if VST_VERSION < 0x030608
|
||||
#define kAmbi1stOrderACN kBFormat
|
||||
#endif
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
static const Steinberg::FIDString defaultVST3WindowType = Steinberg::kPlatformTypeHWND;
|
||||
#elif JUCE_MAC
|
||||
|
|
@ -192,7 +74,6 @@ inline void toString128 (Steinberg::Vst::String128 result, const juce::String& s
|
|||
static const Steinberg::FIDString defaultVST3WindowType = Steinberg::kPlatformTypeX11EmbedWindowID;
|
||||
#endif
|
||||
|
||||
|
||||
//==============================================================================
|
||||
static inline Steinberg::Vst::SpeakerArrangement getArrangementForBus (Steinberg::Vst::IAudioProcessor* processor,
|
||||
bool isInput, int busIndex)
|
||||
|
|
@ -1192,83 +1073,6 @@ private:
|
|||
std::vector<ChannelMapping> mappings;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
// We have to trust that Steinberg won't double-delete
|
||||
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDelete)
|
||||
template <class ObjectType>
|
||||
class VSTComSmartPtr
|
||||
{
|
||||
public:
|
||||
VSTComSmartPtr() = default;
|
||||
VSTComSmartPtr (const VSTComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); }
|
||||
~VSTComSmartPtr() { if (source != nullptr) source->release(); }
|
||||
|
||||
explicit operator bool() const noexcept { return operator!= (nullptr); }
|
||||
ObjectType* get() const noexcept { return source; }
|
||||
ObjectType& operator*() const noexcept { return *source; }
|
||||
ObjectType* operator->() const noexcept { return source; }
|
||||
|
||||
VSTComSmartPtr& operator= (const VSTComSmartPtr& other)
|
||||
{
|
||||
auto p = other;
|
||||
std::swap (p.source, source);
|
||||
return *this;
|
||||
}
|
||||
|
||||
VSTComSmartPtr& operator= (std::nullptr_t)
|
||||
{
|
||||
return operator= (VSTComSmartPtr{});
|
||||
}
|
||||
|
||||
bool operator== (std::nullptr_t) const noexcept { return source == nullptr; }
|
||||
bool operator!= (std::nullptr_t) const noexcept { return source != nullptr; }
|
||||
|
||||
bool loadFrom (Steinberg::FUnknown* o)
|
||||
{
|
||||
*this = nullptr;
|
||||
return o != nullptr && o->queryInterface (ObjectType::iid, (void**) &source) == Steinberg::kResultOk;
|
||||
}
|
||||
|
||||
bool loadFrom (Steinberg::IPluginFactory* factory, const Steinberg::TUID& uuid)
|
||||
{
|
||||
jassert (factory != nullptr);
|
||||
*this = nullptr;
|
||||
return factory->createInstance (uuid, ObjectType::iid, (void**) &source) == Steinberg::kResultOk;
|
||||
}
|
||||
|
||||
/** Increments refcount. */
|
||||
static auto addOwner (ObjectType* t)
|
||||
{
|
||||
return VSTComSmartPtr (t, true);
|
||||
}
|
||||
|
||||
/** Does not initially increment refcount; assumes t has a positive refcount. */
|
||||
static auto becomeOwner (ObjectType* t)
|
||||
{
|
||||
return VSTComSmartPtr (t, false);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit VSTComSmartPtr (ObjectType* object, bool autoAddRef) noexcept : source (object) { if (source != nullptr && autoAddRef) source->addRef(); }
|
||||
ObjectType* source = nullptr;
|
||||
};
|
||||
|
||||
/** Increments refcount. */
|
||||
template <class ObjectType>
|
||||
auto addVSTComSmartPtrOwner (ObjectType* t)
|
||||
{
|
||||
return VSTComSmartPtr<ObjectType>::addOwner (t);
|
||||
}
|
||||
|
||||
/** Does not initially increment refcount; assumes t has a positive refcount. */
|
||||
template <class ObjectType>
|
||||
auto becomeVSTComSmartPtrOwner (ObjectType* t)
|
||||
{
|
||||
return VSTComSmartPtr<ObjectType>::becomeOwner (t);
|
||||
}
|
||||
|
||||
// NOLINTEND(clang-analyzer-cplusplus.NewDelete)
|
||||
|
||||
//==============================================================================
|
||||
/* This class stores a plugin's preferred MIDI mappings.
|
||||
|
||||
|
|
|
|||
|
|
@ -245,6 +245,22 @@ namespace Presonus
|
|||
JUCE_END_IGNORE_WARNINGS_MSVC
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
//==============================================================================
|
||||
#if JucePlugin_Enable_ARA
|
||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wpragma-pack")
|
||||
#include <ARA_API/ARAVST3.h>
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
#if ARA_SUPPORT_VERSION_1
|
||||
#error "Unsupported ARA version - only ARA version 2 and onward are supported by the current implementation"
|
||||
#endif
|
||||
|
||||
DEF_CLASS_IID (ARA::IPlugInEntryPoint)
|
||||
DEF_CLASS_IID (ARA::IPlugInEntryPoint2)
|
||||
DEF_CLASS_IID (ARA::IMainFactory)
|
||||
#endif // JucePlugin_Enable_ARA
|
||||
|
||||
//==============================================================================
|
||||
#if JUCE_WINDOWS
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -35,20 +35,10 @@
|
|||
#if JUCE_PLUGINHOST_VST3 && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD)
|
||||
|
||||
#include "juce_VST3Headers.h"
|
||||
#include "juce_VST3Utilities.h"
|
||||
#include "juce_VST3Common.h"
|
||||
#include "juce_ARACommon.h"
|
||||
|
||||
#if JUCE_PLUGINHOST_ARA && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX)
|
||||
#include <ARA_API/ARAVST3.h>
|
||||
|
||||
namespace ARA
|
||||
{
|
||||
DEF_CLASS_IID (IMainFactory)
|
||||
DEF_CLASS_IID (IPlugInEntryPoint)
|
||||
DEF_CLASS_IID (IPlugInEntryPoint2)
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
*/
|
||||
|
||||
#include "juce_VST3Headers.h"
|
||||
#include "juce_VST3Utilities.h"
|
||||
#include "juce_VST3Common.h"
|
||||
|
||||
namespace juce
|
||||
|
|
|
|||
243
modules/juce_audio_processors/format_types/juce_VST3Utilities.h
Normal file
243
modules/juce_audio_processors/format_types/juce_VST3Utilities.h
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef DOXYGEN
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
JUCE_BEGIN_NO_SANITIZE ("vptr")
|
||||
|
||||
//==============================================================================
|
||||
#define JUCE_DECLARE_VST3_COM_REF_METHODS \
|
||||
Steinberg::uint32 PLUGIN_API addRef() override { return (Steinberg::uint32) ++refCount; } \
|
||||
Steinberg::uint32 PLUGIN_API release() override { const int r = --refCount; if (r == 0) delete this; return (Steinberg::uint32) r; }
|
||||
|
||||
#define JUCE_DECLARE_VST3_COM_QUERY_METHODS \
|
||||
Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID, void** obj) override \
|
||||
{ \
|
||||
jassertfalse; \
|
||||
*obj = nullptr; \
|
||||
return Steinberg::kNotImplemented; \
|
||||
}
|
||||
|
||||
inline bool doUIDsMatch (const Steinberg::TUID a, const Steinberg::TUID b) noexcept
|
||||
{
|
||||
return std::memcmp (a, b, sizeof (Steinberg::TUID)) == 0;
|
||||
}
|
||||
|
||||
/* Holds a tresult and a pointer to an object.
|
||||
|
||||
Useful for holding intermediate results of calls to queryInterface.
|
||||
*/
|
||||
class QueryInterfaceResult
|
||||
{
|
||||
public:
|
||||
QueryInterfaceResult() = default;
|
||||
|
||||
QueryInterfaceResult (Steinberg::tresult resultIn, void* ptrIn)
|
||||
: result (resultIn), ptr (ptrIn) {}
|
||||
|
||||
bool isOk() const noexcept { return result == Steinberg::kResultOk; }
|
||||
|
||||
Steinberg::tresult extract (void** obj) const
|
||||
{
|
||||
*obj = result == Steinberg::kResultOk ? ptr : nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
Steinberg::tresult result = Steinberg::kResultFalse;
|
||||
void* ptr = nullptr;
|
||||
};
|
||||
|
||||
/* Holds a tresult and a pointer to an object.
|
||||
|
||||
Calling InterfaceResultWithDeferredAddRef::extract() will also call addRef
|
||||
on the pointed-to object. It is expected that users will use
|
||||
InterfaceResultWithDeferredAddRef to hold intermediate results of a queryInterface
|
||||
call. When a suitable interface is found, the function can be exited with
|
||||
`return suitableInterface.extract (obj)`, which will set the obj pointer,
|
||||
add a reference to the interface, and return the appropriate result code.
|
||||
*/
|
||||
class InterfaceResultWithDeferredAddRef
|
||||
{
|
||||
public:
|
||||
InterfaceResultWithDeferredAddRef() = default;
|
||||
|
||||
template <typename Ptr>
|
||||
InterfaceResultWithDeferredAddRef (Steinberg::tresult resultIn, Ptr* ptrIn)
|
||||
: result (resultIn, ptrIn),
|
||||
addRefFn (doAddRef<Ptr>) {}
|
||||
|
||||
bool isOk() const noexcept { return result.isOk(); }
|
||||
|
||||
Steinberg::tresult extract (void** obj) const
|
||||
{
|
||||
const auto toReturn = result.extract (obj);
|
||||
|
||||
if (result.isOk() && *obj != nullptr && addRefFn != nullptr)
|
||||
addRefFn (*obj);
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Ptr>
|
||||
static void doAddRef (void* obj) { static_cast<Ptr*> (obj)->addRef(); }
|
||||
|
||||
QueryInterfaceResult result;
|
||||
void (*addRefFn) (void*) = nullptr;
|
||||
};
|
||||
|
||||
template <typename ClassType> struct UniqueBase {};
|
||||
template <typename CommonClassType, typename SourceClassType> struct SharedBase {};
|
||||
|
||||
template <typename ToTest, typename CommonClassType, typename SourceClassType>
|
||||
InterfaceResultWithDeferredAddRef testFor (ToTest& toTest,
|
||||
const Steinberg::TUID targetIID,
|
||||
SharedBase<CommonClassType, SourceClassType>)
|
||||
{
|
||||
if (! doUIDsMatch (targetIID, CommonClassType::iid))
|
||||
return {};
|
||||
|
||||
return { Steinberg::kResultOk, static_cast<CommonClassType*> (static_cast<SourceClassType*> (std::addressof (toTest))) };
|
||||
}
|
||||
|
||||
template <typename ToTest, typename ClassType>
|
||||
InterfaceResultWithDeferredAddRef testFor (ToTest& toTest,
|
||||
const Steinberg::TUID targetIID,
|
||||
UniqueBase<ClassType>)
|
||||
{
|
||||
return testFor (toTest, targetIID, SharedBase<ClassType, ClassType>{});
|
||||
}
|
||||
|
||||
template <typename ToTest>
|
||||
InterfaceResultWithDeferredAddRef testForMultiple (ToTest&, const Steinberg::TUID) { return {}; }
|
||||
|
||||
template <typename ToTest, typename Head, typename... Tail>
|
||||
InterfaceResultWithDeferredAddRef testForMultiple (ToTest& toTest, const Steinberg::TUID targetIID, Head head, Tail... tail)
|
||||
{
|
||||
const auto result = testFor (toTest, targetIID, head);
|
||||
|
||||
if (result.isOk())
|
||||
return result;
|
||||
|
||||
return testForMultiple (toTest, targetIID, tail...);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
// We have to trust that Steinberg won't double-delete
|
||||
// NOLINTBEGIN(clang-analyzer-cplusplus.NewDelete)
|
||||
template <class ObjectType>
|
||||
class VSTComSmartPtr
|
||||
{
|
||||
public:
|
||||
VSTComSmartPtr() = default;
|
||||
VSTComSmartPtr (const VSTComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); }
|
||||
~VSTComSmartPtr() { if (source != nullptr) source->release(); }
|
||||
|
||||
explicit operator bool() const noexcept { return operator!= (nullptr); }
|
||||
ObjectType* get() const noexcept { return source; }
|
||||
ObjectType& operator*() const noexcept { return *source; }
|
||||
ObjectType* operator->() const noexcept { return source; }
|
||||
|
||||
VSTComSmartPtr& operator= (const VSTComSmartPtr& other)
|
||||
{
|
||||
auto p = other;
|
||||
std::swap (p.source, source);
|
||||
return *this;
|
||||
}
|
||||
|
||||
VSTComSmartPtr& operator= (std::nullptr_t)
|
||||
{
|
||||
return operator= (VSTComSmartPtr{});
|
||||
}
|
||||
|
||||
bool operator== (std::nullptr_t) const noexcept { return source == nullptr; }
|
||||
bool operator!= (std::nullptr_t) const noexcept { return source != nullptr; }
|
||||
|
||||
bool loadFrom (Steinberg::FUnknown* o)
|
||||
{
|
||||
*this = nullptr;
|
||||
return o != nullptr && o->queryInterface (ObjectType::iid, (void**) &source) == Steinberg::kResultOk;
|
||||
}
|
||||
|
||||
bool loadFrom (Steinberg::IPluginFactory* factory, const Steinberg::TUID& uuid)
|
||||
{
|
||||
jassert (factory != nullptr);
|
||||
*this = nullptr;
|
||||
return factory->createInstance (uuid, ObjectType::iid, (void**) &source) == Steinberg::kResultOk;
|
||||
}
|
||||
|
||||
/** Increments refcount. */
|
||||
static auto addOwner (ObjectType* t)
|
||||
{
|
||||
return VSTComSmartPtr (t, true);
|
||||
}
|
||||
|
||||
/** Does not initially increment refcount; assumes t has a positive refcount. */
|
||||
static auto becomeOwner (ObjectType* t)
|
||||
{
|
||||
return VSTComSmartPtr (t, false);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit VSTComSmartPtr (ObjectType* object, bool autoAddRef) noexcept : source (object) { if (source != nullptr && autoAddRef) source->addRef(); }
|
||||
ObjectType* source = nullptr;
|
||||
};
|
||||
|
||||
/** Increments refcount. */
|
||||
template <class ObjectType>
|
||||
auto addVSTComSmartPtrOwner (ObjectType* t)
|
||||
{
|
||||
return VSTComSmartPtr<ObjectType>::addOwner (t);
|
||||
}
|
||||
|
||||
/** Does not initially increment refcount; assumes t has a positive refcount. */
|
||||
template <class ObjectType>
|
||||
auto becomeVSTComSmartPtrOwner (ObjectType* t)
|
||||
{
|
||||
return VSTComSmartPtr<ObjectType>::becomeOwner (t);
|
||||
}
|
||||
|
||||
// NOLINTEND(clang-analyzer-cplusplus.NewDelete)
|
||||
|
||||
JUCE_END_NO_SANITIZE
|
||||
|
||||
} // namespace juce
|
||||
|
||||
#endif // DOXYGEN
|
||||
|
|
@ -142,6 +142,7 @@
|
|||
//==============================================================================
|
||||
#include "utilities/juce_AAXClientExtensions.h"
|
||||
#include "utilities/juce_VST2ClientExtensions.h"
|
||||
#include "utilities/juce_VST3Interface.h"
|
||||
#include "utilities/juce_VST3ClientExtensions.h"
|
||||
#include "format_types/juce_ARACommon.h"
|
||||
#include "utilities/juce_ExtensionsVisitor.h"
|
||||
|
|
|
|||
|
|
@ -1155,8 +1155,8 @@ public:
|
|||
See also the helper function getXmlFromBinary() for loading settings as XML.
|
||||
|
||||
In the case that this AudioProcessor is implementing a VST3 that has declared compatible
|
||||
plugins via VST3ClientExtensions::getCompatibleClasses(), the state passed to this
|
||||
function may have been created by one of these compatible plugins.
|
||||
plugins via JUCE_VST3_COMPATIBLE_CLASSES, the state passed to this function may have
|
||||
been created by one of these compatible plugins.
|
||||
|
||||
If the parameter IDs of the current plugin differ from the IDs of the plugin whose state
|
||||
was passed to this function, you can use information from the plugin state
|
||||
|
|
|
|||
|
|
@ -36,8 +36,8 @@
|
|||
|
||||
#include <juce_core/system/juce_PlatformDefs.h>
|
||||
|
||||
#ifndef JUCE_API
|
||||
#define JUCE_API
|
||||
#if ! (defined (JUCE_API) || defined (DOXYGEN))
|
||||
#define JUCE_API
|
||||
#endif
|
||||
|
||||
#if (JucePlugin_Enable_ARA || (JUCE_PLUGINHOST_ARA && (JUCE_PLUGINHOST_VST3 || JUCE_PLUGINHOST_AU))) && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX)
|
||||
|
|
|
|||
|
|
@ -35,128 +35,11 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
std::map<uint32_t, String> VST3ClientExtensions::getCompatibleParameterIds (const InterfaceId&) const
|
||||
std::map<uint32_t, String> VST3ClientExtensions::getCompatibleParameterIds (const VST3Interface::Id&) const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
VST3ClientExtensions::InterfaceId VST3ClientExtensions::convertJucePluginId (uint32_t manufacturerCode,
|
||||
uint32_t pluginCode,
|
||||
InterfaceType interfaceType)
|
||||
{
|
||||
const auto word0 = std::invoke ([&]() -> uint32_t
|
||||
{
|
||||
switch (interfaceType)
|
||||
{
|
||||
case InterfaceType::ara: [[fallthrough]];
|
||||
case InterfaceType::controller: [[fallthrough]];
|
||||
case InterfaceType::compatibility: [[fallthrough]];
|
||||
case InterfaceType::component: return 0xABCDEF01;
|
||||
case InterfaceType::processor: return 0x0101ABAB;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return 0;
|
||||
});
|
||||
|
||||
const auto word1 = std::invoke ([&]() -> uint32_t
|
||||
{
|
||||
switch (interfaceType)
|
||||
{
|
||||
case InterfaceType::ara: return 0xA1B2C3D4;
|
||||
case InterfaceType::controller: return 0x1234ABCD;
|
||||
case InterfaceType::compatibility: return 0xC0DEF00D;
|
||||
case InterfaceType::component: return 0x9182FAEB;
|
||||
case InterfaceType::processor: return 0xABCDEF01;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return 0;
|
||||
});
|
||||
|
||||
constexpr auto getByteFromLSB = [] (uint32_t word, int byteIndex)
|
||||
{
|
||||
jassert (isPositiveAndNotGreaterThan (byteIndex, 3));
|
||||
return (std::byte) ((word >> (byteIndex * 8)) & 0xff);
|
||||
};
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
constexpr auto isWindows = true;
|
||||
#else
|
||||
constexpr auto isWindows = false;
|
||||
#endif
|
||||
|
||||
return {
|
||||
getByteFromLSB (word0, isWindows ? 0 : 3),
|
||||
getByteFromLSB (word0, isWindows ? 1 : 2),
|
||||
getByteFromLSB (word0, isWindows ? 2 : 1),
|
||||
getByteFromLSB (word0, isWindows ? 3 : 0),
|
||||
|
||||
getByteFromLSB (word1, isWindows ? 2 : 3),
|
||||
getByteFromLSB (word1, isWindows ? 3 : 2),
|
||||
getByteFromLSB (word1, isWindows ? 0 : 1),
|
||||
getByteFromLSB (word1, isWindows ? 1 : 0),
|
||||
|
||||
getByteFromLSB (manufacturerCode, 3),
|
||||
getByteFromLSB (manufacturerCode, 2),
|
||||
getByteFromLSB (manufacturerCode, 1),
|
||||
getByteFromLSB (manufacturerCode, 0),
|
||||
|
||||
getByteFromLSB (pluginCode, 3),
|
||||
getByteFromLSB (pluginCode, 2),
|
||||
getByteFromLSB (pluginCode, 1),
|
||||
getByteFromLSB (pluginCode, 0)
|
||||
};
|
||||
}
|
||||
|
||||
VST3ClientExtensions::InterfaceId VST3ClientExtensions::convertVST2PluginId (uint32_t pluginCode,
|
||||
const String& pluginName,
|
||||
InterfaceType interfaceType)
|
||||
{
|
||||
VST3ClientExtensions::InterfaceId iid{};
|
||||
|
||||
iid[0] = (std::byte) 'V';
|
||||
iid[1] = (std::byte) 'S';
|
||||
iid[2] = (std::byte) std::invoke ([&]
|
||||
{
|
||||
switch (interfaceType)
|
||||
{
|
||||
case InterfaceType::controller: return 'E';
|
||||
case InterfaceType::component: return 'T';
|
||||
case InterfaceType::ara: [[fallthrough]];
|
||||
case InterfaceType::compatibility: [[fallthrough]];
|
||||
case InterfaceType::processor: break;
|
||||
}
|
||||
|
||||
// A VST2 plugin only has two interfaces
|
||||
// - component (the audio effect)
|
||||
// - controller (the editor/UI)
|
||||
jassertfalse;
|
||||
return '\0';
|
||||
});
|
||||
iid[3] = (std::byte) (pluginCode >> 24);
|
||||
iid[4] = (std::byte) (pluginCode >> 16);
|
||||
iid[5] = (std::byte) (pluginCode >> 8);
|
||||
iid[6] = (std::byte) pluginCode;
|
||||
|
||||
for (const auto [index, character] : enumerate (pluginName, (size_t) 7))
|
||||
{
|
||||
if (index >= iid.size())
|
||||
break;
|
||||
|
||||
iid[index] = (std::byte) CharacterFunctions::toLowerCase (character);
|
||||
}
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
std::swap (iid[0], iid[3]);
|
||||
std::swap (iid[1], iid[2]);
|
||||
std::swap (iid[4], iid[5]);
|
||||
std::swap (iid[6], iid[7]);
|
||||
#endif
|
||||
|
||||
return iid;
|
||||
}
|
||||
|
||||
uint32_t VST3ClientExtensions::convertJuceParameterId (const String& parameterId, bool studioOneCompatible)
|
||||
{
|
||||
auto hash = (uint32_t) (parameterId.hashCode());
|
||||
|
|
@ -167,27 +50,4 @@ uint32_t VST3ClientExtensions::convertJuceParameterId (const String& parameterId
|
|||
return hash;
|
||||
}
|
||||
|
||||
VST3ClientExtensions::InterfaceId VST3ClientExtensions::toInterfaceId (const String& interfaceIdString)
|
||||
{
|
||||
jassert (interfaceIdString.length() == 32);
|
||||
jassert (interfaceIdString.containsOnly ("0123456789abcdefABCDEF"));
|
||||
|
||||
return { (std::byte) interfaceIdString.substring ( 0, 2).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring ( 2, 4).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring ( 4, 6).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring ( 6, 8).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring ( 8, 10).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring (10, 12).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring (12, 14).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring (14, 16).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring (16, 18).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring (18, 20).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring (20, 22).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring (22, 24).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring (24, 26).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring (26, 28).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring (28, 30).getHexValue32(),
|
||||
(std::byte) interfaceIdString.substring (30, 32).getHexValue32() };
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace Steinberg
|
|||
using TUID = char[16];
|
||||
} // namespace Steinberg
|
||||
|
||||
#endif
|
||||
#endif // DOXYGEN
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
|
@ -104,36 +104,6 @@ struct VST3ClientExtensions
|
|||
*/
|
||||
virtual bool getPluginHasMainInput() const { return true; }
|
||||
|
||||
using InterfaceId = std::array<std::byte, 16>;
|
||||
|
||||
/** This function should return the UIDs of any compatible VST2 or VST3
|
||||
plug-ins.
|
||||
|
||||
This information will be used to implement the IPluginCompatibility
|
||||
interface. Hosts can use this interface to determine whether this VST3
|
||||
is capable of replacing a given VST2.
|
||||
|
||||
Each compatible class is a 16-byte array that corresponds to the VST3
|
||||
interface ID for the class implementing the IComponent interface.
|
||||
For VST2 or JUCE plugins these IDs can be determined in the following
|
||||
ways:
|
||||
- Use convertVST2PluginId() for VST2 plugins or JUCE VST3 plugins with
|
||||
JUCE_VST3_CAN_REPLACE_VST3 enabled
|
||||
- Use convertJucePluginId() for any other JUCE VST3 plugins
|
||||
|
||||
If JUCE_VST3_CAN_REPLACE_VST2 is enabled the VST3 plugin will have the
|
||||
same identifier as the VST2 plugin and therefore there will be no need
|
||||
to implement this function.
|
||||
|
||||
If the parameter IDs between compatible versions differ
|
||||
getCompatibleParameterIds() should also be overridden. However, unlike
|
||||
getCompatibleParameterIds() this function should remain constant and
|
||||
always return the same IDs.
|
||||
|
||||
@see getCompatibleParameterIds()
|
||||
*/
|
||||
virtual std::vector<InterfaceId> getCompatibleClasses() const { return {}; }
|
||||
|
||||
/** This function should return a map of VST3 parameter IDs and the JUCE
|
||||
parameters they map to.
|
||||
|
||||
|
|
@ -195,74 +165,35 @@ struct VST3ClientExtensions
|
|||
@endcode
|
||||
|
||||
@param compatibleClass A plugin identifier, either for the current
|
||||
plugin or one listed in getCompatibleClasses().
|
||||
plugin or one listed in JUCE_VST3_COMPATIBLE_CLASSES.
|
||||
This parameter allows the implementation to
|
||||
return a different parameter map for each
|
||||
compatible class. Use convertJucePluginId() and
|
||||
convertVST2PluginId() to determine the class IDs
|
||||
used by JUCE plugins.
|
||||
When JUCE_VST3_CAN_REPLACE_VST2 is set, the
|
||||
InterfaceId denoting the VST2 version of the
|
||||
plugin will match the InterfaceId of the
|
||||
VST3 that replaces it. In this case, you should
|
||||
only include the VST2 mappings in the returned
|
||||
map, assuming there are no collisions between
|
||||
the VST2 parameter indices and the VST3 ParamIDs.
|
||||
In the unlikely event of a collision between
|
||||
the VST2 and VST3 parameter IDs, you should
|
||||
inspect the state that was most recently
|
||||
passed to setStateInformation() to determine
|
||||
whether the host is loading a VST2 state that
|
||||
requires parameter remapping. If you determine
|
||||
that no remapping is necessary, you can indicate
|
||||
this by returning an empty map.
|
||||
compatible class. Use VST3Interface::jucePluginId()
|
||||
and VST3Interface::vst2PluginId() to determine
|
||||
the class IDs used by JUCE plugins. When
|
||||
JUCE_VST3_CAN_REPLACE_VST2 is set, the ID
|
||||
denoting the VST2 version of the plugin will
|
||||
match the ID of the VST3 that replaces it. In
|
||||
this case, assuming there are no collisions
|
||||
between the VST2 parameter indices and the VST3
|
||||
ParamIDs you should only include the VST2
|
||||
mappings in the returned map. In the unlikely
|
||||
event of a collision you should inspect the
|
||||
state that was most recently passed to
|
||||
setStateInformation() to determine whether the
|
||||
host is loading a VST2 state that requires
|
||||
parameter remapping. If you determine that no
|
||||
remapping is necessary, you can indicate this by
|
||||
returning an empty map.
|
||||
|
||||
@returns A map where each key is a VST3 parameter ID in the compatible
|
||||
plugin, and the value is the unique JUCE parameter ID in the
|
||||
current plugin that it should be mapped to.
|
||||
|
||||
@see getCompatibleClasses, convertJucePluginId, convertVST2PluginId, convertJuceParameterId
|
||||
@see JUCE_VST3_COMPATIBLE_CLASSES, VST3Interface::jucePluginId, VST3Interface::vst2PluginId, VST3Interface::hexStringToId
|
||||
*/
|
||||
virtual std::map<uint32_t, String> getCompatibleParameterIds (const InterfaceId& compatibleClass) const;
|
||||
virtual std::map<uint32_t, String> getCompatibleParameterIds (const VST3Interface::Id& compatibleClass) const;
|
||||
|
||||
/** An enum indicating the various VST3 interface types.
|
||||
|
||||
In most cases users shouldn't need to concern themselves with any
|
||||
interfaces other than the component, which is used to report the actual
|
||||
audio effect.
|
||||
*/
|
||||
enum class InterfaceType
|
||||
{
|
||||
ara,
|
||||
controller,
|
||||
compatibility,
|
||||
component,
|
||||
processor
|
||||
};
|
||||
|
||||
/** Returns a 16-byte array indicating the VST3 interface ID used for a
|
||||
given JUCE VST3 plugin.
|
||||
|
||||
Internally this is what JUCE will use to assign an ID to each VST3
|
||||
interface, unless JUCE_VST3_CAN_REPLACE_VST2 is enabled.
|
||||
|
||||
@see convertVST2PluginId, getCompatibleClasses, getCompatibleParameterIds
|
||||
*/
|
||||
static InterfaceId convertJucePluginId (uint32_t manufacturerCode,
|
||||
uint32_t pluginCode,
|
||||
InterfaceType interfaceType = InterfaceType::component);
|
||||
|
||||
/** Returns a 16-byte array indicating the VST3 interface ID used for a
|
||||
given VST2 plugin.
|
||||
|
||||
Internally JUCE will use this method to assign an ID for the component
|
||||
and controller interfaces when JUCE_VST3_CAN_REPLACE_VST2 is enabled.
|
||||
|
||||
@see convertJucePluginId, getCompatibleClasses, getCompatibleParameterIds
|
||||
*/
|
||||
static InterfaceId convertVST2PluginId (uint32_t pluginCode,
|
||||
const String& pluginName,
|
||||
InterfaceType interfaceType = InterfaceType::component);
|
||||
|
||||
/** Returns the VST3 compatible parameter ID reported for a given JUCE
|
||||
parameter.
|
||||
|
|
@ -276,8 +207,67 @@ struct VST3ClientExtensions
|
|||
static uint32_t convertJuceParameterId (const String& parameterId,
|
||||
bool studioOneCompatible = true);
|
||||
|
||||
/** Converts a 32-character hex notation string to a VST3 interface ID. */
|
||||
static InterfaceId toInterfaceId (const String& interfaceIdString);
|
||||
private:
|
||||
/** Instead of overriding this function you should define the preprocessor
|
||||
definition JUCE_VST3_COMPATIBLE_CLASSES as described in the docs.
|
||||
|
||||
@see JUCE_VST3_COMPATIBLE_CLASSES
|
||||
*/
|
||||
virtual std::vector<VST3Interface::Id> getCompatibleClasses() const final
|
||||
{
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
#if DOXYGEN
|
||||
/** An optional user defined preprocessor definition for declaring a comma
|
||||
separated list of VST2 and VST3 plugin identifiers that this VST3 plugin
|
||||
can replace in a DAW session.
|
||||
|
||||
The definition of this preprocessor must be defined at the project
|
||||
level, normally in your CMake or Projucer project files.
|
||||
|
||||
This information will be used to implement the IPluginCompatibility
|
||||
interface.
|
||||
|
||||
If JUCE_VST3_CAN_REPLACE_VST2 is enabled, the VST3 plugin will have the
|
||||
same identifier as the VST2 plugin and therefore you don't need to
|
||||
implement this preprocessor definition.
|
||||
|
||||
This preprocessor definition can contain code that depends on any class
|
||||
or function defined as part of the VST3Interface struct but should avoid
|
||||
any other dependencies!
|
||||
|
||||
Each compatible class is a 16-byte array that corresponds to the VST3
|
||||
interface identifier as reported by a plugins IComponent interface.
|
||||
For VST2 or JUCE plugins these identifiers can be determined in the
|
||||
following ways:
|
||||
- Use VST3Interface::vst2PluginId() for any VST2 plugins or JUCE VST3
|
||||
plugin with JUCE_VST3_CAN_REPLACE_VST3 enabled
|
||||
- Use VST3Interface::jucePluginId() for any other JUCE VST3 plugins
|
||||
|
||||
Examples
|
||||
|
||||
@code
|
||||
// Defines a VST2 plugin this VST3 can replace
|
||||
JUCE_VST3_COMPATIBLE_CLASSES=VST3Interface::vst2PluginId ('Plug', "Plugin Name")
|
||||
|
||||
// Defines a VST3 plugin this VST3 can replace
|
||||
JUCE_VST3_COMPATIBLE_CLASSES=VST3Interface::jucePluginId ('Manu', 'Plug')
|
||||
|
||||
// Defines both a VST2 and a VST3 plugin this VST3 can replace
|
||||
JUCE_VST3_COMPATIBLE_CLASSES=VST3Interface::vst2PluginId ('Plug', "Plugin Name"), VST3Interface::jucePluginId ('Manu', 'Plug')
|
||||
|
||||
// Defines a non-JUCE VST3 plugin this VST3 can replace
|
||||
JUCE_VST3_COMPATIBLE_CLASSES=VST3Interface::hexStringToId ("0F1E2D3C4B5A69788796A5B4C3D2E1F0")
|
||||
@endcode
|
||||
|
||||
If the parameter IDs between compatible versions differ
|
||||
VST3ClientExtensions::getCompatibleParameterIds() should also be overridden.
|
||||
|
||||
@see VST3Interface VST3ClientExtensions::getCompatibleParameterIds()
|
||||
*/
|
||||
#define JUCE_VST3_COMPATIBLE_CLASSES
|
||||
#endif // DOXYGEN
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
248
modules/juce_audio_processors/utilities/juce_VST3Interface.h
Normal file
248
modules/juce_audio_processors/utilities/juce_VST3Interface.h
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE framework.
|
||||
Copyright (c) Raw Material Software Limited
|
||||
|
||||
JUCE is an open source framework subject to commercial or open source
|
||||
licensing.
|
||||
|
||||
By downloading, installing, or using the JUCE framework, or combining the
|
||||
JUCE framework with any other source code, object code, content or any other
|
||||
copyrightable work, you agree to the terms of the JUCE End User Licence
|
||||
Agreement, and all incorporated terms including the JUCE Privacy Policy and
|
||||
the JUCE Website Terms of Service, as applicable, which will bind you. If you
|
||||
do not agree to the terms of these agreements, we will not license the JUCE
|
||||
framework to you, and you must discontinue the installation or download
|
||||
process and cease use of the JUCE framework.
|
||||
|
||||
JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/
|
||||
JUCE Privacy Policy: https://juce.com/juce-privacy-policy
|
||||
JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/
|
||||
|
||||
Or:
|
||||
|
||||
You may also use this code under the terms of the AGPLv3:
|
||||
https://www.gnu.org/licenses/agpl-3.0.en.html
|
||||
|
||||
THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL
|
||||
WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF
|
||||
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
/** Useful functions and classes for defining VST3 Interface Ids.
|
||||
|
||||
The classes and functions in this struct are intentionally lightweight,
|
||||
requiring almost no JUCE or Steinberg VST3 SDK dependencies.
|
||||
|
||||
@tags{Audio}
|
||||
*/
|
||||
struct VST3Interface
|
||||
{
|
||||
/** An enum indicating the various VST3 interface types.
|
||||
|
||||
In most cases users shouldn't need to concern themselves with any interfaces
|
||||
other than the component, which is used to report the actual audio effect.
|
||||
*/
|
||||
enum class Type
|
||||
{
|
||||
ara,
|
||||
controller,
|
||||
compatibility,
|
||||
component,
|
||||
processor
|
||||
};
|
||||
|
||||
/** A type storing the byte values for a unique VST3 interface identifier. */
|
||||
using Id = std::array<std::byte, 16>;
|
||||
|
||||
/** Returns a 16-byte array indicating the VST3 interface ID used for a given
|
||||
VST2 plugin.
|
||||
|
||||
Internally JUCE will use this method to assign an ID for the component and
|
||||
controller interfaces when JUCE_VST3_CAN_REPLACE_VST2 is enabled.
|
||||
|
||||
@see jucePluginId, hexStringToId
|
||||
*/
|
||||
static Id vst2PluginId (uint32_t pluginCode,
|
||||
const char* pluginName,
|
||||
Type interfaceType = Type::component)
|
||||
{
|
||||
Id iid{};
|
||||
|
||||
iid[0] = (std::byte) 'V';
|
||||
iid[1] = (std::byte) 'S';
|
||||
iid[2] = (std::byte) std::invoke ([&]
|
||||
{
|
||||
switch (interfaceType)
|
||||
{
|
||||
case Type::controller: return 'E';
|
||||
case Type::component: return 'T';
|
||||
case Type::ara: [[fallthrough]];
|
||||
case Type::compatibility: [[fallthrough]];
|
||||
case Type::processor: break;
|
||||
}
|
||||
|
||||
// A VST2 plugin only has two possible interfaces
|
||||
// - component (the audio effect)
|
||||
// - controller (the editor/UI)
|
||||
jassertfalse;
|
||||
return '\0';
|
||||
});
|
||||
iid[3] = (std::byte) (pluginCode >> 24);
|
||||
iid[4] = (std::byte) (pluginCode >> 16);
|
||||
iid[5] = (std::byte) (pluginCode >> 8);
|
||||
iid[6] = (std::byte) pluginCode;
|
||||
|
||||
for (size_t index = 7; index < iid.size() && *pluginName != 0; ++index)
|
||||
{
|
||||
iid[index] = (std::byte) std::tolower (*pluginName);
|
||||
++pluginName;
|
||||
}
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
std::swap (iid[0], iid[3]);
|
||||
std::swap (iid[1], iid[2]);
|
||||
std::swap (iid[4], iid[5]);
|
||||
std::swap (iid[6], iid[7]);
|
||||
#endif
|
||||
|
||||
return iid;
|
||||
}
|
||||
|
||||
/** Returns a 16-byte array indicating the VST3 interface ID used for a given
|
||||
JUCE VST3 plugin.
|
||||
|
||||
Internally this is what JUCE will use to assign an ID to each VST3 interface,
|
||||
unless JUCE_VST3_CAN_REPLACE_VST2 is enabled.
|
||||
|
||||
@see vst2PluginId, hexStringToId
|
||||
*/
|
||||
static inline Id jucePluginId (uint32_t manufacturerCode,
|
||||
uint32_t pluginCode,
|
||||
Type interfaceType = Type::component)
|
||||
{
|
||||
const auto word0 = std::invoke ([&]() -> uint32_t
|
||||
{
|
||||
switch (interfaceType)
|
||||
{
|
||||
case Type::ara: [[fallthrough]];
|
||||
case Type::controller: [[fallthrough]];
|
||||
case Type::compatibility: [[fallthrough]];
|
||||
case Type::component: return 0xABCDEF01;
|
||||
case Type::processor: return 0x0101ABAB;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return 0;
|
||||
});
|
||||
|
||||
const auto word1 = std::invoke ([&]() -> uint32_t
|
||||
{
|
||||
switch (interfaceType)
|
||||
{
|
||||
case Type::ara: return 0xA1B2C3D4;
|
||||
case Type::controller: return 0x1234ABCD;
|
||||
case Type::compatibility: return 0xC0DEF00D;
|
||||
case Type::component: return 0x9182FAEB;
|
||||
case Type::processor: return 0xABCDEF01;
|
||||
}
|
||||
|
||||
jassertfalse;
|
||||
return 0;
|
||||
});
|
||||
|
||||
constexpr auto getByteFromLSB = [] (uint32_t word, int byteIndex)
|
||||
{
|
||||
jassert (0 <= byteIndex && byteIndex <= 3);
|
||||
return (std::byte) ((word >> (byteIndex * 8)) & 0xff);
|
||||
};
|
||||
|
||||
#if JUCE_WINDOWS
|
||||
constexpr auto isWindows = true;
|
||||
#else
|
||||
constexpr auto isWindows = false;
|
||||
#endif
|
||||
|
||||
return {
|
||||
getByteFromLSB (word0, isWindows ? 0 : 3),
|
||||
getByteFromLSB (word0, isWindows ? 1 : 2),
|
||||
getByteFromLSB (word0, isWindows ? 2 : 1),
|
||||
getByteFromLSB (word0, isWindows ? 3 : 0),
|
||||
|
||||
getByteFromLSB (word1, isWindows ? 2 : 3),
|
||||
getByteFromLSB (word1, isWindows ? 3 : 2),
|
||||
getByteFromLSB (word1, isWindows ? 0 : 1),
|
||||
getByteFromLSB (word1, isWindows ? 1 : 0),
|
||||
|
||||
getByteFromLSB (manufacturerCode, 3),
|
||||
getByteFromLSB (manufacturerCode, 2),
|
||||
getByteFromLSB (manufacturerCode, 1),
|
||||
getByteFromLSB (manufacturerCode, 0),
|
||||
|
||||
getByteFromLSB (pluginCode, 3),
|
||||
getByteFromLSB (pluginCode, 2),
|
||||
getByteFromLSB (pluginCode, 1),
|
||||
getByteFromLSB (pluginCode, 0)
|
||||
};
|
||||
}
|
||||
|
||||
/** Converts a 32-character hex notation string to a VST3 interface ID.
|
||||
|
||||
@see jucePluginId, vst2PluginId
|
||||
*/
|
||||
static inline Id hexStringToId (const char* hex)
|
||||
{
|
||||
jassert (std::strlen (hex) == 32);
|
||||
|
||||
const auto getByteValue = [](const char* str)
|
||||
{
|
||||
const auto getCharacterValue = [](const char c)
|
||||
{
|
||||
if (c >= '0' && c <= '9')
|
||||
return (std::byte) (c - '0');
|
||||
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return (std::byte) (c - 'A' + 10);
|
||||
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return (std::byte) (c - 'a' + 10);
|
||||
|
||||
// Invalid hex character!
|
||||
jassertfalse;
|
||||
return std::byte{};
|
||||
};
|
||||
|
||||
return getCharacterValue (str[0]) << 4
|
||||
| getCharacterValue (str[1]);
|
||||
};
|
||||
|
||||
return { getByteValue (hex),
|
||||
getByteValue (hex + 2),
|
||||
getByteValue (hex + 4),
|
||||
getByteValue (hex + 6),
|
||||
getByteValue (hex + 8),
|
||||
getByteValue (hex + 10),
|
||||
getByteValue (hex + 12),
|
||||
getByteValue (hex + 14),
|
||||
getByteValue (hex + 16),
|
||||
getByteValue (hex + 18),
|
||||
getByteValue (hex + 20),
|
||||
getByteValue (hex + 22),
|
||||
getByteValue (hex + 24),
|
||||
getByteValue (hex + 26),
|
||||
getByteValue (hex + 28),
|
||||
getByteValue (hex + 30) };
|
||||
}
|
||||
|
||||
VST3Interface() = delete;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
Loading…
Add table
Add a link
Reference in a new issue