博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

用c++设计音效插件 :3 VST3编程指南

Posted on 2022-06-17 21:34  pencilCool  阅读(1467)  评论(0编辑  收藏  举报

翻译自: https://learning.oreilly.com/library/view/designing-audio-effect/9780429954313/xhtml/Ch03.xhtml#sec3_1_1

VST3是Steinberg成熟的VST插件规范的当前版本。可敬的VST2 API可以说比音频插件历史上任何其他API产生了更多的商业和免费插件,在2018年10月正式被淘汰,它被从VST SDK中删除,新的插件作者不能合法地为其编写,尽管对于已经与斯坦伯格签署许可协议的老的插件开发者有一个祖父条款。VST3从头开始重新设计,除了一些命名规则和其他非常小的细节,与VST2几乎没有共同之处。VST3专门解决了VST2 API的一些缺点,包括有点模糊的侧链规范和消息系统。VST3的设计也考虑到了升级和产品扩展,开发者在每个版本中都会增加新的功能。最后,由于VST2的规范已经优雅地偃旗息鼓,我将在本文中交替使用 "VST3 "和 "VST "两个术语。你可以从Steinberg(www.steinberg.net/en/company/developers.html)免费下载VST3 SDK,我们鼓励你加入开发者的论坛,在那里你可以发表问题。

3.1 设置VST3 SDK

VST SDK只是一个特定层次的子文件夹的集合。你可以从Steinberg下载SDK并将其解压到你的硬盘上。VST SDK已经被设置为与CMake一起工作(后面会有更多介绍),所以你会注意到文件夹的名字没有空格。根文件夹被命名为VST_SDK。从SDK 3.6.10开始,根文件夹包含两个子文件夹,一个用于VST2,另一个用于VST3。Steinberg已经使VST2的插件API过时,不再开发或支持它。VST2文件夹包含旧的VST2 API文件;这些文件用于目前SDK中包含的VST3-to-VST2包装对象,并且相当简单地添加到项目中。除非你以前有销售VST2插件的许可证,否则你不允许销售新的VST2插件。我不确定未来的SDK是否会包含VST2部分,或者VST2包装器是否会存在很长时间。

3.1.1 VST3样本项目

当SDK安装在您的硬盘上时,您需要运行CMake来提取示例项目。在SDK文档和视频教程中都有说明,网址是www.willpirkle.com。VST3 SDK包含了丰富的示例插件项目,可以生成十多个各种形状和大小的插件。在你的系统上安装SDK,然后使用CMake软件生成一个Xcode或Visual Studio编译器项目,其中包含每一个样本插件。你可以通过一次构建操作来构建所有的插件。如果你的编译器和SDK设置正确,你将得到一个无错误的构建,并有一堆VST3插件可以玩。在尝试编写你自己的插件之前,你应该验证你的编译器是否能正确地构建SDK样本项目。

3.1.2 VST3文档

VST3的API文档包含在SDK中,是用Doxygen®生成的,它可以创建基于HTML的文档,你可以用网络浏览器查看。你可以通过简单地双击index.html文件来打开文档,它是Doxygen的主页。该文件位于SDK根目录附近的VST_SDK/VST3_SDK/index.html;你一定要把它收藏起来并经常参考。VST3 SDK的文档随着每一个新的SDK版本的发布而大大改善。它包含了大量的信息,以及所有结构、类、函数和VST3编程范例的文档。

3.2 VST3的结构和剖析

VST插件可以为Windows、MacOS、iOS和Linux编写。这意味着你必须使用适当的编译器和操作系统来针对这些产品--例如,你不能使用Xcode来编写Windows VST。本书特别针对Windows和MacOS,尽管VST API的编写是独立于平台的。如果你有兴趣为iOS或Linux写作,我建议你先把Windows和MacOS的版本写好:这些版本有更多的信息和帮助。最新版本的VST3 SDK将Windows和MacOS的插件打包成一个包,你可以把它看成是一个由子文件夹和文件组成的简单目录。捆绑包被设置成对一般用户来说是一个文件,但实际上它是一个文件夹--在MacOS中,你可以右击插件 "文件 "并选择 "显示包内容 "来进入捆绑包。VST3 SDK还包括用于生成自定义GUI的VSTGUI4,尽管你可以使用任何你喜欢的GUI开发库;VSTGUI4被设计为直接与VST3接口,ASPiK使用VSTGUI4来操作GUI库。

VST3的模块结构(VST-MA)的核心是基于(但不等同于)微软的通用对象模型(COM)编程范式。这使得VST3的API可以很容易地被更新和修改,而不会破坏旧版本。COM实际上只是一种编写软件的 "方式 "或方法,在技术上独立于任何编程语言,尽管VST-MA在写作时只支持C++。

COM编程围绕着接口的概念,我们也在本书所附的FX对象(IAudioSignalProcessor和IAudioSignalGenerator)中使用。对于VST-MA来说,接口是一个只定义虚拟功能的C++对象,因此它代表一个抽象的基类。没有成员变量,继承接口的类必须覆盖它定义的任何纯抽象函数。一些(但不是全部)VST-MA接口是纯抽象的,因此所有继承的函数都在派生类上实现。这与Objective C编程中的协议有一些相似之处,一个类通过实现它所需要的方法来 "符合协议"。接口概念很强大,因为它允许对象以安全的方式持有指向对方的指针:如果对象A持有对象B的接口指针(即指向B的接口基类的指针),对象A只能调用接口定义的那些函数。由于是抽象的,接口没有构造函数或析构函数,所以对象A不能调用接口指针上的删除操作符,而且在编译时试图这样做会产生错误。通过多重继承,一个对象可以实现许多接口(或符合它们的协议),这样它就可以通过这些基类指针之一安全地被访问。

此外,COM范式还提供了一种装置,在与用早期SDK编译的旧对象进行交互时,可以向后兼容。它包括一个查询机制,这样一个对象可以安全地查询另一个对象,询问它是否支持某种接口。如果该对象回答说它支持,那么第一个对象就可以询问一个接口指针并使用其方法。这意味着,当新的功能被添加到VST3的API中时,它们可以被实现为新的接口类定义。主机可以查询插件,看它是否有这些新接口之一。如果没有,那么主机就不会尝试使用这些新功能。或者,主机可以 "向后 "查询该对象,看它是否有一个旧的接口,至少支持它所需要的部分功能。如果有,并且主机获得了它的接口指针,那么主机可以只调用那些保证存在的旧功能,防止崩溃,并为安全更新API提供一个强大的机制。

3.2.1 单组件与双组件架构

编写VST3插件有两种模式,这涉及到两个主要的插件职责如何分配:音频信号处理和GUI实现。在双组件模式中,你用两个C++对象实现插件:一个用于音频处理(称为处理器对象),另一个用于GUI接口(称为控制器对象)。VST3的架构师花了很大的力气将这两个对象相互隔离,使得两者之间几乎不可能有强大的通信。这并不意味着是一种批评,因为它紧跟C++面向对象的设计范式,它允许音频处理和GUI连接/实现在不同的CPU上运行。对于多CPU平台,即使用充满CPU的农场卡,这是有意义的。但是,如果你想用单片机的编程对象来实现插件,那么你的VST3版本可能与你的AU和AAX版本有很大不同。此外,有一些插件架构的设计模式禁止它们分布在两个独立的CPU上运行的两个对象中,或者用这种模式实现变得过于复杂。

图3.1:(a)双组件的VST3插件使用了两个C++对象;中间的粗黑条表示两个组件之间的硬性通信障碍。(b) 相比之下,单组件版本使用一个C++对象;细的虚线表示不太牢固的障碍(这确实取决于设计者)。

为了解决这个问题,VST3的API也允许单组件版本,其中一个单一的C++对象处理处理和GUI接口的工作。这就是所谓的单组件范式。架构师们简单地创建了一个单一的C++对象,并对处理器和控制器对象进行多重继承。图3.1显示了这两种不同的设计模式。请注意,与AAX和AU一样,控制器部分处理与GUI的通信,但不处理实现细节--实际渲染旋钮、按钮、开关和视图的部分,它被写在一个单独的GUI对象中。

3.2.2 VST3基类

在双组件版本中,你创建了两个C++对象,它们分别来自两个基类。AudioEffect(用于处理器)和EditController(用于控制器)。在单组件版本中,也就是我们在本书和ASPiK中专门使用的版本,你的插件是从SingleComponentEffect派生出来的,它基本上是继承了双组件。注意,与AU不同的是,不管是哪种类型的插件,FX还是合成器,都使用相同的基类(这里列出)。

AudioEffect:双组件处理器基类
EditController:双组件控制器基类
SingleComponentEffect:组合的单一对象基类

3.2.3 MacOS的捆绑ID

MacOS中的每个捆绑包都有一个独特的字符串,称为捆绑包ID。苹果公司有关于命名这个字符串的建议,以及在你准备商业销售你的产品时向苹果公司注册它。通常情况下,你将你的公司和产品名称嵌入到捆绑ID中。唯一的主要限制是,你不应该使用连字符("-")来连接字符串组件,而是应该使用句号。例如,mycompany.vst.golden-flanger是不合法的,而mycompany.vst.golden.flanger是可以的。这是在Xcode项目的信息面板中设置的,它实际上只是显示底层info.plist文件中的信息(见图3.2)。如果你有任何问题,请查阅苹果的文档。如果你使用ASPiK来生成你的VST项目,那么bundle ID值是为你创建的,并在编译器项目中的Info.plist预处理器定义中设置;你可以在项目的构建设置面板中查看或改变这个值。

3.2.4 VST3编程注意事项

就C++实现而言,VST3的API是相当直接的。然而,VST3的设计者倾向于紧跟编程技术的前沿,当前版本的SDK需要一个符合C++11的编译器。VSTGUI4也需要C++11,对于MacOS/Xcode,它也需要C++14。所以一定要检查你的SDK的发行说明以确保你的编译器能正常工作。如果你编译了样本项目并立即得到了无数的错误,请检查以确保你是符合要求的。请注意,MacOS版本要求几个编译器框架与AU项目链接,包括CoreFoundation、QuartzCore、Accellerate、OpenGL和Cocoa®;后两个框架用于VSTGUI4。然而,编译器项目实际上非常复杂--比AU和AAX更复杂--部分原因是插件必须链接到几个静态库,这些静态库与插件一起被编译,是编译器解决方案的一部分。在早期版本的VST3 API中,你预先编译了你的基础库(与当前版本的AAX相同),但后来的版本将这些库合并到编译器项目中。图3.2显示了一个库存VST3插件项目在Xcode中的样子。这个插件使用VSTGUI来渲染GUI,并有额外的库来支持,但基础库和sdk库是必须的。Visual Studio的解决方案视图也类似,显示了代表库和验证器的独立子项目。

图3.2: Xcode中一个标准的VST3项目包括多个库,一个验证器可执行文件和插件目标。

与AAX和AU一样,有大量的C++类型定义重命名标准数据类型,所以你应该总是右键单击并要求编译器带你到你不认识的定义。大多数的定义都很简单,应该是为了使代码更容易阅读,尽管有时它们会产生相反的效果。特别是,你会看到PLUGIN_API的类型定义装饰了许多VST3函数,它简单地重命名了__stdcall函数指定符。这个指定符与函数调用后堆栈的清理方式有关。如果你不知道它是什么意思,你可以安全地忽略它(它只是在不同平台上保持一致性)。

大多数VST3插件函数返回一个成功/失败的代码,是一个32位无符号整数,被类型化为tresult。成功值是kResultTrue或kResultOK(它们是相同的),而失败代码包括kResultFalse、kInvalidArgument、kNotImplemented和一些在funknown.h中定义的其他代码。

3.2.5 VST3和GUID

VST3使用GUID作为唯一识别插件的方法(对于DAW),以及在使用双组件模式时唯一识别处理器和编辑器的每一半(也许是作为一种在CPU上分配组件的方法)。单组件版本只使用一个GUID。如果你使用ASPiK,那么CMake会在创建项目时为你生成GUID;如果你不使用ASPiK,那么请查阅你的框架文档。如果你正在从头开始制作你自己的插件,那么你需要自己生成这个值。在Windows上,你可以使用Visual Studio安装的内置GUID生成器,名为guidgen.exe;在MacOS上,你可以免费下载众多GUID生成器的应用程序之一。你可以在第3.3节中提供的类定义代码中看到GUID。

3.2.6 VST3插件类工厂

VST3使用类工厂的方法,在一个典型的DAW会话中生成多个插件的实例。这种方法有几个方面的影响。首先,你需要小心使用单子或其他反模式,因为它们可能无法与类工厂正常工作。我们的ASPiK插件外壳不使用它们,你也不应该使用(请不要发恶毒的电子邮件)。第二,你的VST3插件动态分配的资源的构建和销毁并不像其他API那样发生在C++对象的构造器和析构器中。相反,有两个额外的函数用于这些目的--initialize( )和terminate( )--它们的作用在名称上应该是很明显的。所以,你只需要留下SingleComponentEffect的构造函数和析构函数。对于双组件范式,这些函数是处理器对象的一部分。

3.3 描述。插件描述字符串

你的插件描述字符串,连同GUID,是这个类工厂定义的一部分。有两个宏用于定义类工厂;你的描述信息被嵌入其中。下面是名为DEF_CLASS2的类工厂宏(用于SDK样本项目之一,AGainSimple)。它包含了以下描述字符串,除了FUID(VST3独有的)外,第2.2节中都有概述:供应商名称、供应商URL、供应商电子邮件、GUID、插件名称和插件类型代码。这些都是按顺序用黑体显示的。

请注意,创建函数是最后一个参数--这个函数使用new操作符在一行代码中提供了新的插件实例。还注意到单组件的效果代号(没有预定义常量声明的0);对于双组件版本,它被重新定义为Vst::kDistributable。在宏的参数序列中,FX插件类型代码紧随其后,为Vst::PlugType::kFx;为了完整起见,合成器版本为Vst::PlugType::kInstrumentSynth。VST3也支持一个子类别层:例如,如果你的插件是用于混响的,你可以选择将其类别分配为Vst::PlugType::kFxReverb。在这种情况下,DAW可以将你的插件与用户安装的其他混响插件分组。

。。。。。。。 先不翻译了。先搞macos 上的