声音设计师如何利用PD+Heavy进行DSP插件的开发
本文转自侯晨钟,声音设计师/作曲家/音乐科技研究员,曾任职于育碧上海工作室,参与过《舞力全开》及《孤岛惊魂》系列的声音设计工作。2015年起在游族网络担任声音设计师,2016年加入莉莉丝游戏担任声音设计师,并于同年转投育碧上海工作室担任声音设计师,2019年起进入上海音能科技有限公司任职产品专家至今。现任Audiokinetic大中华区产品专家,爱好是探寻纸盆起伏与光栅明暗变化间的神秘联系。
第一课、PureData与Heavy
背景
提到音频插件的开发,许多声音设计师会认为这是“程序员专属的黑魔法”,因为通常这项工作需要参与者能够编写代码,同时要具备扎实的数学、物理及数字信号处理方面的知识。而对于使用别人提供的音频工具的声音设计师来说,这都不是工作的必备技能,因此他们常常倾向于与此类“过于技术的话题”保持距离。
当声音设计师在别人的项目中听到了某种Wwise没有提供过的DSP效果时,他们非常有可能能够迅速理解其工作原理,并有能力利用熟悉的工具做出技术原型,甚至实现一模一样的交互表现。然而,要么由于性能方面的限制,要么由于此类工具的产出物无法以插件形式部署到创作工具及引擎中去,导致声音设计师的很多想法都止步于原型阶段而未能对实际游戏产生贡献。
幸运的是,通过使用PureData与Heavy,声音设计师现在已经有机会独立创造出具备良好性能、可以在创作工具中使用且能够在实际游戏中运行的效果器及音频源插件。
一点点科普,什么是PureData?
PureData(PD)是由美国软件工程师Miller Puckette于上世纪90年代开发的视觉化编程语言,主要用于计算机音乐及多媒体艺术的创作。由于PD是开源项目,自发布以来已经积累了庞大的开发者基础,并持续有新的扩展功能被添加(现在你甚至可以在PD里加载VST插件……)。
包含PD代码的文件被称为Patch,PD支持创建SubPatch所以使用者可以通过抽象来创建功能复杂的PD项目。
由于本文不是PD入门教程,需要了解更多的读者请前往https://puredata.info/。
从上面的视频中可以看到PD的使用方式与模块化合成器十分相似——通过连接不同的Object(模块)来实现信号系统的设计;通过调节参数与系统进行实时交互。
我们可以将PD看作是声音设计师的“画图环境”,让他们可以使用自己熟悉的设计语言来设计工具的原型,并有机会在之后“投产”。
就像用你小时候的玩具造点“能用的”东西一样
什么是Heavy?
Heavy是由Enzien Audio开发的针对PD Patch的编译器,可将声音设计师制作的PD Patch转换成C/C++代码。这使得声音设计师只需在PD环境下工作就能得到可运行于目标平台的代码,而无需自己编写。
我们可以将Heavy看作是依据声音设计师提供的工具设计图纸进行生产的自动化车间。
那么我们画图和建造工厂后生产的产品能做什么呢?
PD+Heavy生产的插件可以做什么
1. 根据声音设计师在PD Patch中的设计,进行实时的DSP运算;
2. 支持音频信号的输入输出,若源Patch中包含音频输入物件——adc~则生成效果器插件,若源patch中不包含adc~则生成源插件(如Wwise SoundSeed Wind,Wwise SynthOne);
3. 支持控制参数的输入输出,既可以接受来自Wwise SoundEngine的Game Parameter控制,也可以向Game Parameter发送数据(如作为LFO使用);
4. 支持UI事件的输入输出(仅限Unity)。
在了解了我们作为声音设计师的“新技术权力”之后,是时候设计并生产一款产品了!
设定目标—Sample Divider
就像音频版本的像素化效果
Sample Divider效果通常包含在Bitcrusher这样的失真插件当中,我将本文的目标设定为生产Sample Divider并投入实际使用。
设定这样的目标的原因很简单——1,Wwise没提供Sample Divider;2,Sample Divider实际上很实用,尤其在Cyberpunk回潮的当下(想象一下如果要实现类似《Nier: Automata》中病毒入侵时以及《Titan Fall2》中Titan受创时大量出现的声音故障表现,怎么可以没有Sample Divider!)。
无痛DSP
在开始“绘制”作为“蓝图”的PD Patch之前,我们要先了解Sample Divider的工作原理。
Sample Divider是通过以低于输入信号采样率的频率对输入信号进行重采样,以“较低的品质进行输出”来实现对原始信号的扭曲处理的。
下图是对我们之后用到的核心元件——Sample and hold(简写为S/H)模块功能的解释,来自《电子音乐理论与技术》,作者就是PD的作者本人。
S/H模块运作原理
如上图所示,类似正弦波的信号被送入S/H模块的左输入点,作为“Sample & Hold(采样及保持)”动作触发“时钟”的锯齿波信号被送入右边的输入点,当锯齿波的值从最高处快速下落至0点时便会触发S/H物件对信号进行采样的动作,而其余时间则保持已采集的数值。这样,当锯齿波频率越接近输入信号的采样率,则输出信号越接近输入信号,也就是“越高清”,反之则包含更多失真,也就是越“像素化”。
下面是一段Sample and hold模块在VCVRack(我以此类比真实的物理合成器)中工作的演示。
用示波器画台阶
开始画图
在了解了原理之后我们便可开始为生产插件准备图纸(Patch)了。
与单独使用PD情况不同的是,为了Patch能够被Heavy正常编译,我们只能使用PD当中的部分物件,否则编译时会报错。我将在本文末尾提供不可使用的PD物件列表。
为了让插件开放参数给目标平台(本文中是Wwise),我们需要按下图的格式声明参数:在PD中按Ctrl+1创建物件,填入"r”——代表该物件从外部接受信息;"SampleRateDivisionL"——在插件界面上显示的参数名称;@hv_param——代表该物件将被Heavy编译成参数接口;4、24000、24000分别为参数的最小值、最大值和默认值。
1. 为了对输入信号的左右声道进行不同的处理,增加不对称性,我在此为左右声道各创建一个参数。phasor~物件为用作S/H模块时钟的锯齿波振荡器,samphold~物件就是S/H模块,dac~物件为音频信号输出的地方。
Note:此Patch中adc~代表信号输入,当Patch当中存在adc~时,Heavy将会生成用于构建效果器插件的代码;若没有adc~物件,则Heavy会生成用于构建音频源插件的代码。
2. 接下来测试patch的运作。
Note:我添加了控制采样频率的hslider物件,由于该物件在编译成插件后将不起作用,因此测试完之后可以删除。
3. 最后将Patch保存到J:\HeavyAudioPlayground\bitcrusher.pd
Note:这个地址大家可随意选择,注意之后还会用到。
现在“图纸”已经画好了,下一篇将介绍我们的“自动化车间(Heavy)”的建造,产品(插件)的生产以及部署!
第二课、建造“自动化车间(Heavy)
上面介绍了如何绘制图纸(Patch),下面我将带领大家建造“自动化车间(Heavy)”,生产产品并将产品部署到我们的火箭(游戏)当中去!
为什么要建造车间
原本Heavy的编译环境是有网页端的,也就是你可以在线上提交Patch,然后Heavy会返回编译报告并提供代码及插件的下载地址。
但由于去年Enzien Audio把Heavy开源了,导致现在必须要将编译器的代码克隆到本地使用。因此我才将接下来要做的事情形容为建造车间(否则就是取快递了!)。
在接着往下读之前请确保你已安装了某一版本的Wwise SDK,我安装的SDK版本为2019.1.1.6977。
一、下载安装python2
首先为了能够运行Heavy,我们需要下载python2.7版本。
地址:https://www.python.org/downloads/release/python-2716/
1、找到下图中的选项并点击鼠标左键。
2、由于我是在PC上工作因此选择了Windows64位版本的安装包。
3、我将Python2.7安装到了C盘根目录下(由于我的电脑上本来已经安装了python3.7,为了加以区分我需要将python2.7的可执行文件重命名为python2)。
接下来要进行环境变量的设置。
二、环境变量的设置
1、首先在This PC(我的电脑)处点击右键,选择Properties(属性)然后点击Advance System Settings(高级系统设置)。
2、点击Environment Variables(环境变量)。
3、然后双击下图中的Path,在弹出的窗口右侧点击New(新建),填入Python2.7的安装路径(也包含子文件夹Scripts)。
这样,我们在命令行工具中输入python2时便会运行python2.7版本了。
三、设置Visual Studio
为了使用Heavy生成的Wwise相关数据进行插件的构建,我们需要对Visual Studio进行配置。
1、打开visual studio然后在Tools栏(工具栏)中选择Get Tools and Features(获得工具及特性)。
2、选择安装Desktop development with C++(使用c++进行桌面开发)。
3、如果您使用的是VS2017版本,请确保在Installation Details中勾选VC++ 2015.3 v14.00(默认是没勾上的)。
完成VS的设置,接下来该主角登场了。
四、克隆Heavy并设置
首先我们要从Github上把Heavy克隆到我们的电脑上。
地址:https://github.com/enzienaudio/hvcc
1、你可以复制Git地址到SourceTree(版本管理工具,https://www.sourcetreeapp.com/)里拽下来,也可以直接下载压缩包解压后使用。
2、然后进入Heavy所在的目录(如果您下载了压缩包,请先解压)。
3、点击上图中绿色圆圈中的空白区域,输入CMD然后回车,这样便可以直接在Heavy所在目录处开启windows命令行工具。
就不用自己把地址敲一遍了。
4、由于我们刚刚安装python2,还缺少运行heavy所需要的库,因此需要在命令行工具中输入python2 -m pip install -r requirements.txt来安装库文件。
5、接下来要让heavy代码中的Wwise SDK版本与你所安装的版本一致,否则会发生编译错误。
比如我机器上安装的是2019.1.1.6977版本的Wwise SDK,需要在c2wwise.py第58行进行替换(路径见下图上方绿色方框内)。
Note:在heavy的文档中有提到这部分,地址
https://github.com/enzienaudio/hvcc/blob/master/generators/c2wwise/c2wwise.py#L58
6、由于我的Wwise SDK被安装在了D盘,而在Heavy提供的VS Solution的模板中,默认SDK安装地址的盘符是C,所以需要都修改一下(瞧我把坑给你们填平了!路径如下图上方绿色方块内所示)。
7、首先进入下图中地址,
8、打开每个vcxproj文件,将所有第36行的盘符C改为D。
如果你有耐心并且进行完上面的所有设置,祝贺你,你已经拥有自己的插件生产车间了!
五、运行Heavy流水线
接下来就是激动人心的时刻了,开机生产!
1、以前面所述的方式,在Heavy所在目录的地址栏输入CMD打开命令行工具,然后输入“python2 hvcc.py J:\HeavyAudioPlayground\bitcrusher.pd -n HvSampleDivider -o C:\Heavy_Build\HvSampleDivider\ -g wwise”。
其中“J:\HeavyAudioPlayground\bitcrusher.pd”这段是我们之前创建的Patch所在的路径;
-n HvSampleDivider将把输出的插件命名为HvSampleDivider,否则插件会使用默认名称“Heavy”;
-o C:\Heavy_Build\HvSampleDivider\ 是编译后的资源输出的路径(大家可以随意设置);
-g wwise将指示Heavy生成构建Wwise插件需要的数据,Heavy还支持其他平台。
Note:有关Heavy的具体使用方式请参考https://github.com/enzienaudio/hvcc中Usage一节。
2、按下回车之后如没有出现报错,则Heavy已完成编译。
3、进入C:\Heavy_Build\HvSampleDivider\后,就可以看到以下内容了。
4、然后我们进入wwise->vs2015文件夹,双击Hv_HvSampleDivider_WwiseFXPlugin.sln文件运行Visual Studio。
5、如下图所示,在下拉菜单中选择Release。
6、在Build栏中点击Build Solution开始建造。
7、如果上面所有的设置都做对了,这里就能看到成功的报告。
8、然后进入C:\Heavy_Build\HvSampleDivider\wwise\build\win\x64\release,就可以看到我们的劳动成果(插件)了。
部署
一、产品的安装
接下来,该将插件部署到创作工具及游戏工程当中去了。
1、如果我们只在创作工具中使用插件,则要将上图中的dll及xml文件放到wwise的插件目录下,如下图所示。
NOTE:文件名中包含的“Auth”字段代表文件应被部署到创作工具中。
2、为了让插件在引擎中运行并被打包到游戏中去,我们需要将上图中的文件放在游戏项目工程目录下的Assets->Wwise->Deployment->Plugin->Windows->x86_64->DSP文件夹当中。
NOTE:我使用了Mix and Jam(https://www.youtube.com/channel/UCLyVUwlB_Hahir_VsKkGPIA)制作的项目作为展示工程,他的频道超级棒一定要去看!
另外,如果大家想了解插件在UE4中的部署方式,可以前往声音设计师Derrick Reyes的频道https://www.youtube.com/channel/UCkjoqOJDeT-jfCOJQPZ_F4w
3。接下来打开Wwise。
由于我们之前在Patch中包含了adc~物件,所以生成的是效果器插件而不是源插件,因此我们应该可以在Audio Object或者Bus的Effect栏中找到它,而不是在Sound SFX->Contents Editor的Add Source菜单当中。
如图,已经可以在Wwise中看到了!
4、然后添加到Wwise某个Audio Object或Bus的效果器链当中。
5、双击打开就可以看到前面我们开放的参数都以默认值显示在插件界面上了。
二、与游戏参数链接
我想要利用这个插件实现的效果是:当游戏中角色冲刺时,利用冲刺声音量的提升来降低音乐及环境声的采样率。
为此,我们需要创建游戏参数来传递冲刺音量的变化。
1、我将冲刺声分成了包含左右两个声道信息的Sound SFX,并分别添加了Wwise Meter插件来捕捉音量包络,然后发给不同的两个游戏参数:
2、然后我们要为Music及AmbientBus上的HvSampleDivider的两个参数创建RTPC,并找到理想的曲线
3、接下来,就是打包、跑游戏、享受战果啦!
成果展示
下面是HvSampleDivider在游戏中的实际表现。
Note:Music是我写的……
仔细听主角冲刺时音乐与环境声的变化,这都是Wwise原本无法做到的事情,现在是不是超级有成就感!
展望
感谢大家读到这里!
我有个疑问,既然有Max4Live,为什么不能有PD4Wwise呢?
如果可以将Heavy编译管线整合到wwise当中,使用PD的声音设计师就可以在Wwise中更方便地制作插件形式的音频资源了(就像Technical Artist制作Shader那样)!从此声音设计师也拥有了属于自己的HLSL!
让我们一起相信未来吧!
彩蛋
另外,在这个Demo中所有声音都是使用SynthOne作为声源实现的(音乐除外……)。
然而有一个疑问一直以来都困扰着我,那就是……既然有SynthOne,什么时候会有SynthTwo,SynthThree呢?!
等了这么久终于不用等了,我可以自己造了!
先来个FMOne! XD
附录——Heavy不支持的PD物件列表
也就是你“画图”的时候用了就会让生产线“卡壳”(error)的物件
第三课、如何在Wwise2021.1.x版本下继续使用Heavy Compiler?
自今年Wwise新的Major Version(2021.1.x)发布以来,越来越多的客户反馈Heavy Compiler。无法伴随Wwise 2021.1.x版本的SDK使用了,我想这对于想要在Wwise中做比较“Procedural"的声音设计的朋友来可以说是一个非常坏的消息……
这让我也开始担心hvcc会不会因为无人维护最终走向其生命尽头并带走他带给Wwise的原本旺盛的Procedural Audio的火光……直到有一天社区中的一位朋友询问与之相关的问题又紧跟着告诉我他找到了让hvcc继续伴随Wwise2021.1.x版本工作的方法……让我也随着他重新找到了希望!
不过这之后我并没有直接询问他具体如何解决了这个兼容性问题,而是选择自己尝试解决,借这篇博客将过程分享给大家。
准备工作
如果您已经很久没有使用hvcc,为接下来构建插件做一些准备工作或许会是不错的回顾方式。
Requirements
为了复现错误并进行修复,我们需要:
安装Python2,之所以这样是因为hvcc终止维护前都是基于python2开发的,不过最近社区中有朋友在尝试将hvcc迁移到python3;
安装1.5.7749,也就是我写作本文时Wwise的最新版本(记得要下载期望部署插件平台的SDK);
下载并解压hvcc (https://github.com/enzienaudio/hvcc),在本文中我将其放在了C:\hvcc_fix\hvcc-master;
做一个简单的测试用patch,比如我做了如下图所示的简单的双声道音量控制程序,命名为pd;
准备好编译时要敲的指令,保存在文本文件中或streamdeck的快捷键中,方便快速输入,例如:python2 hvcc.py c:\hvcc_fix\hvcc_Workspace\stereoGain.pd -n testTemplateChange -o c:\hvcc_fix\hvcc_Workspace\Builds\ -g wwise,关于指令不同部分的意义见下图。更详细可参考hvcc文档。
注:如果您是第一次接触使用PureData+hvcc为Wwise编写插件,欢迎回顾上面两课。
复现错误
更改SDK路径
要为Wwise2021.1.x版本生成插件,我们需要为hvcc指定Wwise2021.1.x的SDK路径方便其读取。
得益于前面的准备,我们可以在hvcc路径下开启命令行工具,迅速地对patch进行编译。
编译完成后前往C:\hvcc_fix\hvcc_Workspace\Builds\wwise\vs2015。
使用Visual Studio打开Hv_testTemplateChange_WwiseFXPlugin.sln后会发现其包含地三个.vcxproj无法被加载。
如果你没有更改过template中的sdk信息,就会出现这种情况,稍后我会讲解如何更改hvcc的vs模板。下图中可见.vcxproj中的sdk还停留在2017。
我们需要将WwiseSDKPath更改为期望使用的版本,比如我的Wwise2021.1.5.7749安装在M盘,所以我做了如下图中的更改。
接下来重新加载.vcxproj就可以开始尝试构建插件(复现报错)了。但在那之前,我们来了解一下如何修改hvcc的vs工程模板以便更快速的进行开发。
修改工程模板
其实我们不用每次生成sln之后都进行修改然后reload,而是可以直接通过修改hvcc的c2wwise框架内的vs solution模板,从而在编译时直接生成版本信息正确的sln及工程。
如上图所示,hvcc针对Wwise插件生成要使用的模板存放在C:\hvcc_fix\hvcc-master\generators\c2wwise\templates\vs2015,我们可以用随便什么文本编辑工具打开三个.vcxproj文件,修改它们35-37行的SDK路径信息,然后保存、退出。这样之后再编译Patch就可以得到工程被加载好的插件的vs sln。
Build(复现报错)
接下来就可以开始build(复现报错)了!
我在这里选择Profile 64位构建设置。
点选solution然后单击右键,选择build solution。
不出意外,和社区中朋友们报告的情况一样,出错了,构建失败。
不过先不用慌张。
尝试修复
线索在日志里
接下来让我们看Error List,可以注意到一条信息写着:”GetGameObjectID不是AK::IAkVoicePluginInfo的成员“。
由此可以推断,如果hvcc结合之前版本的Wwise SDK是可以构建成功的,那么现在AK::IAkVoicePluginInfo中已找不到GetGameObjectID便是构建失败的诱因,只需要在正确的盒子中重新找到它就可以了。
那么GetGameObjectID到底是谁的成员呢?
Hacking...
双击报错条目C2039,vs便会跳转至存在问题的代码位置。
下图是我们进行修改前的代码:
我尝试将GetGameObjectID替换为GetPlayingID,构建成功了!
但是……你懂的,我们可能构建成功的同时也弄坏了什么东西。
所以我们还是应该去寻找更可靠的答案。
答案揭晓
为了得到确切的、安全的修复,我询问了我们的CTO - Martin Dufour,从他那里了解到:GetGameObjectID的确已经从AK::IAkVoicePluginInfo移动到了别处(衷心感谢!)。
修复方法非常简单,我们要做的仅仅是把226行中的GetVoiceInfo更改为GetGameObjectInfo,that's it!
保存后再进行构建,一切顺利!
尾声
尽管Enzien Audio已经停止对hvcc的更新,但这并没有阻止人们继续使用这套方案。依然存在许多项目使用PD+hvcc做插件原型,甚至用在正式的项目中。
另外值得高兴的是,社区中已经有朋友正在尝试将hvcc升级到python3从而延续生命。