JUCE 内置 VST3 SDK 的 ModuleInfoLib 深度指南:解析与生成 moduleinfo.json
【免费下载链接】JUCEJUCE is an open-source cross-platform C++ application framework for desktop and mobile applications, including VST, VST3, AU, AUv3, LV2 and AAX audio plug-ins.项目地址: https://gitcode.com/GitHub_Trending/ju/JUCE
导读
本文聚焦于 JUCE 仓库内嵌的 Steinberg VST3 SDK 所提供的ModuleInfoLib——一个用于解析与创建moduleinfo.json(VST3 插件模块清单)文件的 C++17 库。moduleinfo.json描述了 VST3 模块的名称、版本、工厂信息(厂商/网址/邮箱/标志)、导出的组件类(CID、分类、快照)以及新旧 CID 兼容映射,是宿主程序识别、加载与迁移插件的关键元数据。读完本文,你将掌握 ModuleInfoLib 的完整 API 调用方式、JSON 结构规范、严格校验规则,以及如何在自有工程中集成解析与生成能力。
一、背景:什么是 moduleinfo.json 与 ModuleInfoLib
moduleinfo.json是 Steinberg 定义的 VST3 模块描述文件,伴随.vst3二进制模块分发,向宿主提供模块的声明式元数据。它解决了传统上需要动态加载模块、实例化工厂才能获得的信息(如厂商、类列表、快照路径)的静态化描述问题,也用于表达 CID 迁移关系,帮助宿主在插件标识符变更后仍能正确恢复会话。
ModuleInfoLib 正是 VST3 SDK 中负责"读写这份 JSON"的官方库,其说明文档位于 modules/juce_audio_processors_headless/format_types/VST3_SDK/public.sdk/source/vst/moduleinfo/ReadMe.md。该目录下同时提供了全部实现源码:
| 文件 | 职责 |
|---|---|
moduleinfo.h | 定义ModuleInfo及其嵌套结构(数据模型) |
moduleinfoparser.cpp/.h | 解析 JSON →ModuleInfo(严格校验) |
moduleinfocreator.cpp/.h | 从已加载的VST3::Hosting::Module生成ModuleInfo并输出 JSON |
json.h/jsoncxx.h | 底层 JSON 解析引擎(sheredom/json.h 单头库)及 C++ 封装 |
二、数据模型:ModuleInfo 结构总览
解析与创建两端共享同一套数据模型,定义在 moduleinfo.h 的Steinberg::ModuleInfo结构体中,包含四个部分:
struct ModuleInfo { struct FactoryInfo { std::string vendor; // 厂商名 std::string url; // 厂商网址 std::string email; // 联系邮箱 int32_t flags {0}; // 工厂标志位(见下文) }; struct Snapshot { double scaleFactor {1.}; // 快照缩放因子,默认 1.0 std::string path; // 快照图片路径 }; using SnapshotList = std::vector<Snapshot>; struct ClassInfo { std::string cid; // 组件类唯一标识(CID,UUID 字符串) std::string category; // 分类(如 kAudioEffectClass) std::string name; // 类名 std::string vendor; // 该类所属厂商 std::string version; // 版本号字符串 std::string sdkVersion; // 编译所用 SDK 版本 std::vector<std::string> subCategories; // 子分类列表 SnapshotList snapshots; // 快照列表 int32_t cardinality {0x7FFFFFFF}; // 可实例化数量,默认取极大值表示不限 uint32_t flags {0}; // 类标志位 }; struct Compatibility { std::string newCID; // 新 CID std::vector<std::string> oldCID; // 被取代的旧 CID 列表 }; std::string name; // 模块名 std::string version; // 模块版本 FactoryInfo factoryInfo; // 工厂信息 ClassList classes; // 类列表 CompatibilityList compatibility; // CID 兼容映射表 };从源码结构看,Compatibility与ClassInfo是可选的集合(解析器允许缺省),而模块名、版本、工厂信息和类列表属于必填顶层字段。
三、解析 moduleinfo.json:接入步骤与 API
3.1 需要包含的文件
按 ReadMe.md 的说明,解析端需要把以下五个文件加入工程:
moduleinfoparser.cppmoduleinfoparser.hmoduleinfo.hjson.hjsoncxx.h
同时需要把VST SDK 的根目录加入头文件搜索路径(moduleinfoparser.cpp内部依赖pluginterfaces/base/ipluginbase.h中的PFactoryInfo标志定义,该头位于 SDK 根目录下)。
3.2 解析调用方式
先把moduleinfo.json的完整内容读入内存缓冲区,然后调用parseJson或parseCompatibilityJson:
auto moduleInfo = ModuleInfoLib::parseCompatibilityJson (std::string_view (buffer, bufferSize), &std::cerr);parseCompatibilityJson的完整签名(见 moduleinfoparser.h):
std::optional<ModuleInfo::CompatibilityList> parseCompatibilityJson ( std::string_view jsonData, std::ostream* optErrorOutput);若解析成功,返回的std::optional含有值;失败则返回空 optional,并把错误信息写入可选的错误输出流。与之并行的还有解析完整模块信息的parseJson:
std::optional<ModuleInfo> parseJson (std::string_view jsonData, std::ostream* optErrorOutput);optErrorOutput可为nullptr(静默模式)。两个函数的行为一致:绝不抛异常,任何错误都以空 optional + 错误流输出的方式返回,因此调用方只需检查 optional 是否有值。
3.3 底层解析引擎:json.h + jsoncxx.h
解析器并非手写 JSON 扫描,而是建立在单头库 sheredom/json.h 之上(json.h),并经由 jsoncxx.h 封装为类型安全的 C++ 接口。
值得注意的实现细节:JSON::Document::parse在调用json_parse_ex时启用了两个解析标志——json_parse_flags_allow_json5(允许 JSON5 语法,如单引号字符串、C 风格注释、十六进制数字、尾随逗号等宽松写法)和json_parse_flags_allow_location_information(为每个值记录 offset/line/row 位置信息)。这意味着解析器能接受 JSON5 风格的 moduleinfo 文件,同时能在出错时给出精确的行列号定位。
jsoncxx.h还提供了便捷的类型访问接口:Value::asObject/asArray/asString/asNumber/asBoolean/asNull、Object/Array的范围 for 迭代、Number::getInteger/getDouble(整数优先走std::from_chars,浮点走std::stod),以及errorToString把json_parse_error_e错误码转为可读字符串。
四、严格校验:moduleinfo.json 的字段规范
moduleinfoparser.cpp内置了非常严格的 schema 校验,解析失败时抛出parse_error(携带 offset/line/row 定位信息)或std::logic_error。理解这些规则是手写或调试moduleinfo.json的关键。
4.1 顶层必填字段
解析器只接受以下五个顶层键,其余任何键都会报Unexpected JSON Token:
| 顶层键 | 类型 | 必填 |
|---|---|---|
Name | 字符串 | ✅ |
Version | 字符串 | ✅ |
Factory Info | 对象 | ✅ |
Compatibility | 数组 | 可选 |
Classes | 数组 | ✅ |
且每个键只允许出现一次,重复出现即报错。
4.2 Factory Info 规范
Factory Info对象包含四个键,全部必填且不可重复:
| 键 | 类型 | 说明 |
|---|---|---|
Vendor | 字符串 | 厂商名 |
URL | 字符串 | 厂商网址 |
E-Mail | 字符串 | 联系邮箱 |
Flags | 对象 | 三个布尔标志位 |
Flags对象只接受以下三个布尔键(对应PFactoryInfo的标志位):
| 键 | 对应标志 |
|---|---|
Classes Discardable | PFactoryInfo::kClassesDiscardable(类可被宿主丢弃,按需重建) |
Component Non Discardable | PFactoryInfo::kComponentNonDiscardable |
Unicode | PFactoryInfo::kUnicode |
标志值必须是布尔类型,出现未知键会报Unknown flag。注意Classes Discardable与后续创建 API 的includeDiscardableClasses参数语义直接相关。
4.3 Classes 数组规范
Classes是对象数组,每个类对象支持九个键(其中快照与子分类可选,其余必填):
| 键 | 类型 | 必填 |
|---|---|---|
CID | 字符串 | ✅ |
Category | 字符串 | ✅ |
Name | 字符串 | ✅ |
Vendor | 字符串 | ✅ |
Version | 字符串 | ✅ |
SDKVersion | 字符串 | ✅ |
Sub Categories | 字符串数组 | 可选 |
Class Flags | 整数 | ✅ |
Cardinality | 整数 | ✅ |
Snapshots | 对象数组 | 可选 |
Snapshots数组内每个对象恰有两个键:Path(字符串)与Scale Factor(双精度浮点数),二者缺一不可(scaleFactor == 0.或path为空均报Missing Snapshot keys)。
4.4 Compatibility 数组规范
Compatibility是对象数组,每个对象包含:
| 键 | 类型 | 说明 |
|---|---|---|
New | 字符串 | 新 CID |
Old | 字符串数组 | 一个或多个旧 CID |
New与Old均不可为空,否则分别报Expect New CID here/Expect Old CID here。
4.5 错误输出格式
无论是 JSON 语法错误还是字段语义错误,错误信息都会通过你传入的std::ostream*输出,并附带定位信息:
error : json_parse_error_expected_colon offset : 42 line no: 3 row no : 10语法错误来自json.h的json_parse_result_s(printJsonParseError输出 error/offset/line no/row no 四行),语义错误来自parse_error(what()包含消息及 offset/line/row 三行)。
五、创建 moduleinfo.json:从 VST3 模块生成清单
5.1 依赖与接入
按 ReadMe 说明,生成端需要链接 VST3 SDK 的sdk_hosting库,并包含以下文件:
moduleinfocreator.cppmoduleinfocreator.hmoduleinfo.h
此外,还需要从 hosting 目录加入模块平台实现(三选一,对应所在平台):
module_win32.cpp(Windows)module_mac.mm(macOS)module_linux.cpp(Linux)
这三个平台实现文件在当前仓库中均真实存在(module_linux.cpp、module_mac.mm、module_win32.cpp),它们负责跨平台加载 VST3 模块二进制、解析导出表与工厂信息。
5.2 两个核心方法
moduleinfocreator.h 暴露两个函数:
// 从一个已加载的模块生成 ModuleInfo ModuleInfo createModuleInfo (const VST3::Hosting::Module& module, bool includeDiscardableClasses); // 把 ModuleInfo 以 JSON 形式写入输出流 void outputJson (const ModuleInfo& info, std::ostream& output);典型用法(对应 ReadMe 示例):
auto moduleInfo = ModuleInfoLib::createModuleInfo (module, false); ModuleInfoLib::outputJson (moduleInfo, std::cout);5.3 createModuleInfo 的实现逻辑
从 moduleinfocreator.cpp 源码可以还原出完整生成流程:
- 模块名:取
module.getName(),并去掉最后一个.之后的扩展名(如MyPlugin.vst3→MyPlugin)。 - 工厂信息:从
module.getFactory().info()拷贝 vendor、url、email、flags 四项。 - 类列表的条件生成:只有当工厂的
classesDiscardable()为 false,或其为 true 且includeDiscardableClasses参数为 true 时,才枚举factory.classInfos()生成ClassInfo。也就是说:对于"类可丢弃"的模块,默认(传 false)不导出类列表——这正是includeDiscardableClasses参数的语义(头文件注释:if true adds the current available classes to the module info)。 - 快照关联:调用
VST3::Hosting::Module::getSnapshots (module.getPath())取得模块目录下的快照图片,按uid(即 CID)与类匹配;快照路径若以模块路径为前缀会被裁剪成相对路径写入 JSON。 - 类字段映射:依次填充
cid(ci.ID().toString())、category、name、vendor、version、sdkVersion、subCategories、cardinality、classFlags。
5.4 outputJson 与 JSON5 输出
outputJson内部使用一个JSON5Writer辅助类(同样位于 moduleinfocreator.cpp)进行美化输出(缩进 2 空格、键后带:),输出结构严格与解析器期望的 schema 对称:
{ "Name": "MyPlugin", "Version": "1.0.0", "Factory Info": { "Vendor": "MyCompany", "URL": "https://example.com", "E-Mail": "dev@example.com", "Flags": { "Unicode": true, "Classes Discardable": false, "Component Non Discardable": false } }, "Classes": [ { "CID": "01234567-89ab-cdef-0123-456789abcdef", "Category": "Audio Effect", "Name": "My Effect", "Vendor": "MyCompany", "Version": "1.0.0", "SDKVersion": "3.7.12", "Sub Categories": ["Fx", "Stereo"], "Class Flags": 0, "Cardinality": 2147483647, "Snapshots": [ { "Scale Factor": 1.0, "Path": "snapshot.png" } ] } ] }需要注意:outputJson生成的是键名带空格的 JSON5 风格文件(如"Factory Info"、"Class Flags"),这与解析器接受的键名严格一致,读写两端对称闭合。
六、工程集成与使用建议
6.1 完整接入清单
把解析 + 生成能力同时纳入自有工程的完整清单为:
- 解析端:
moduleinfoparser.cpp、moduleinfoparser.h、moduleinfo.h、json.h、jsoncxx.h - 生成端:
moduleinfocreator.cpp、moduleinfocreator.h、moduleinfo.h+sdk_hosting库 + 平台module_*.cpp/.mm - 编译要求:C++17(
std::optional、std::string_view、std::variant) - 头文件搜索路径:VST SDK 根目录
6.2 在 JUCE 生态中的位置
本仓库(JUCE)将 VST3 SDK 完整内嵌于 modules/juce_audio_processors_headless/format_types/VST3_SDK 目录,作为juce_audio_processors_headless模块的 VST3 宿主/加载实现基础。sdk_hosting的VST3::Hosting::Module正是 JUCE 的 VST3 插件扫描与宿主功能所依赖的模块加载层,ModuleInfoLib 则在此之上提供元数据的 JSON 序列化/反序列化能力,可用于:插件管理器导出清单、安装器生成或校验 moduleinfo、以及宿主持久化插件信息时的 CID 兼容迁移记录。
6.3 实践建议
- 解析时永远传错误流:即使不关心错误详情,也建议传入
&std::cerr或自定义日志流,便于定位畸形文件的行列位置。 - 写入与读取保持键名一致:手写 JSON 时必须使用带空格的规范键名(
Factory Info、Class Flags、Sub Categories、Scale Factor、E-Mail等),否则会被严格校验拒绝。 - 区分
parseJson与parseCompatibilityJson:只需 CID 迁移信息时用后者,需要完整模块清单时用前者,两者共享同一严格校验内核。 - 注意
includeDiscardableClasses:对声明Classes Discardable的模块,若希望清单包含当前可用的类列表,请传true。
七、小结
ModuleInfoLib 是 VST3 SDK 中处理moduleinfo.json的官方轻量级库:解析端提供"绝不抛异常、失败返回空 optional"的容错 API 与严格的字段校验;创建端基于sdk_hosting的模块加载能力,一条调用即可从.vst3模块生成结构化清单并输出为 JSON5 格式。掌握其数据模型(ModuleInfo/FactoryInfo/ClassInfo/Compatibility)、JSON 键名规范与两个核心 API,即可在宿主、安装器或插件管理工具中可靠地读写 VST3 模块元数据。
提示:ReadMe 中提到 VST3 SDK 还包含
moduleinfotool命令行工具,可以从命令行完成"模块 → moduleinfo.json"的转换;就当前仓库快照而言,该工具的可执行源码未包含在内,但完全可以通过上文介绍的createModuleInfo+outputJson两个 API 在自有代码中实现等价能力。
【免费下载链接】JUCEJUCE is an open-source cross-platform C++ application framework for desktop and mobile applications, including VST, VST3, AU, AUv3, LV2 and AAX audio plug-ins.项目地址: https://gitcode.com/GitHub_Trending/ju/JUCE
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考