AudioXL

AudioXL

通过游戏自身的音频引擎实现自定义声音和音频元数据。包含脚本扩展。(っˆڡˆς)

- 介绍 -

这个项目的初衷,是我试图找到一种比使用 FootstepsFX 更好的方法来识别特定鞋子。所以我添加了一个功能,然后就有了下一个,再下一个……于是我们走到了今天:AudioXL 是漫长而繁琐工作的成果,期间我常常因为遇到瓶颈而放弃,但每当我学到新东西时又会重新拾起。

AudioXL 不依赖 REDmod 或第二个音频引擎,它通过合并元数据记录而非整体替换文件的方式工作,将新音频送入游戏引擎自身的自定义声音注册表中,这也意味着一个普通的 WAV 文件就能成为游戏自己混音器上的一等公民 Wwise 事件。

无需 REDmod、无需声音库创作或第二引擎,即可在游戏中加入新声音。

简而言之 - 放一个声音文件夹和旁边的一个小 JSON 文件,游戏就会像播放自己的声音一样播放它们。


- 对于玩家 -

无需任何配置。安装它,然后安装基于它构建的模组即可。AudioXL 与 REDmod 共存:如果你启用 REDmod 启动,它的声音和 AudioXL 的声音会共享同一个注册表,两者都能播放。

前置要求

可选: Redscript Configuration Framework - 在游戏中显示此页面。

安装

将压缩包拖入你的模组管理器,或将其解压到游戏文件夹中,使最终路径结构如下:

Cyberpunk 2077\red4ext\plugins\AudioXL\AudioXL.dll
Cyberpunk 2077\red4ext\plugins\AudioXL\audioxl_routing.bnk
Cyberpunk 2077\r6\scripts\AudioXL\AudioXL.reds

基于 AudioXL 的模组会将它们的声音放在:

Cyberpunk 2077\red4ext\plugins\AudioXL\sounds\<ModName>\

卸载

删除

red4ext\plugins\AudioXL

r6\scripts\AudioXL

AudioXL 不会在你的存档中留下任何东西,所以它可以随时添加或移除。


- 对于模组作者:新声音 -

在以下路径下创建一个文件夹:

red4ext\plugins\AudioXL\sounds\<YourMod>\

然后将你的音频放入其中,并添加一个 sounds.json 文件:

{
  "sounds": [
    { "name": "mymod_alarm",  "type": "mod_sfx_2d",        "file": "alarm.wav" },
    { "name": "mymod_step",   "type": "mod_sfx_occlusion", "file": "step.ogg", "gain": 0.8 },
    { "name": "mymod_pad",    "type": "axl_music_2d",      "file": "pad.mp3", "loop": true, "fadeIn": 2.0, "fadeOut": 3.0 },
    { "name": "w_gun_pistol_power_liberty_fire_single",  "type": "mod_sfx_2d", "file": "liberty.wav" },
    { "name": "w_gun_pistol_power_lexington_fire_single", "type": "mod_skip" }
  ]
}

这就是全部集成工作。该文件夹会在音频初始化时被读取一次。然后,在任何脚本中:

GameInstance.GetAudioSystem(gi).Play(n"mymod_alarm");
GameInstance.GetAudioSystem(gi).Play(n"mymod_step", npc.GetEntityID(), n"feet");   // 在 NPC 上定位播放

注册表规则

  • 新名称 代表一个新事件。 原版事件名称 会替换该事件在所有播放位置的音频:枪声、脚步声、界面、任何东西。 mod_skip 会使原版事件静音。
  • 格式:WAV(16 或 24 位 PCM)、MP3、OGG、FLAC。WAV 文件会被内存映射,因此大量文件在播放前不占用资源;对于长音轨,请添加:
    "stream": true
    
  • 名称是全局的,最先注册的生效。请用你的模组名称作为前缀。
  • 注册表容量为 4096 行,与 REDmod 共享。

字段说明

name      要发布的事件名称(必需)
type      路由类型,见下文(默认为 mod_sfx_2d)
file      音频文件,相对于清单文件(除非类型是 mod_skip,否则必需)
gain      1.0 = 原始音量          pitch      0 = 原始音调    distance  0 = 默认
loop      true/false               rate       播放速率,0.5 = 半速,低八度
fadeIn    秒数                     fadeOut    秒数,由 AudioXLAPI.Stop 应用
start     文件起始秒数              end        结束秒数,0 = 到结尾
stream    true = 映射文件,仅在播放时读取
subtitle  文本,或 { "en-us": "...", "de-de": "..." }      speaker   与字幕一起显示的名称

路由类型 决定了声音遵循哪个混音器和音量滑块:

mod_sfx_2d            普通 2D 音效                  (音效滑块)
mod_sfx_occlusion     定位播放,可被墙壁遮挡         (音效滑块)
mod_sfx_low_occlusion, mod_sfx_room, mod_sfx_street, mod_sfx_city, mod_sfx_radio, mod_sfx_ui
axl_voice_2d          对话混音器                    (对话滑块)
axl_music_2d          音乐混音器                    (音乐滑块)
axl_radio_2d          载具收音机                    (载具收音机滑块)
axl_sfx_2d, axl_master_2d
mod_skip              使指定的原版事件静音

mod_sfx_* 类型是游戏自带的;axl_* 类型由 AudioXL 提供。

实时控制,针对你注册的声音:

AudioXLAPI.Stop(n"mymod_pad", 3.0);      // 3 秒淡出;原版 Stop 对这些无效
AudioXLAPI.SetGain(n"mymod_pad", 0.5);   // 播放时调整音量
AudioXLAPI.IsPlaying(n"mymod_pad");

带字幕的语音台词

{ "name": "mymod_greeting", "type": "axl_voice_2d", "speaker": "V",
  "file": { "fem": "greeting_f.wav", "male": "greeting_m.wav" },
  "subtitle": { "en-us": "啊,该死,又来了" } }
AudioXLAPI.PlayLine(n"mymod_greeting", player.GetEntityID(), n"V");

PlayLine 会根据 V 的体型选择对应的音频,在对话混音器上播放,并在游戏自身的 HUD 字幕栏中显示字幕,时长与音频长度精确匹配。这需要游戏会话:Session/Ready 在主菜单也会触发,所以请用以下条件进行判断:

!event.IsPreGame()

如果你更喜欢脚本注册:

AudioXLAPI.RegisterSound(mod, name, type, path, gain, pitch, distance)

这等同于清单文件中的一行,在你的 OnLoad 中调用即可。


- 对于模组作者:元数据记录 -

鞋类设置、武器声音分配、载具引擎、环境音效:所有这些都存在于已编译的音频元数据中,AudioXL 会合并你的元数据而不是替换整个文件。

添加记录: 打开起始文件

.audio_metadata

在 WolvenKit 中,添加你的记录,将其保存在你的存档中你自己的路径下,并注册它:

AudioXLAPI.Register("My Mod", r"mymod\sound\metadata\records.audio_metadata",
                    ["lcm_footsteps_concrete=lcm_concrete_mymod"]);

列表中的配对将一个鞋类记录分配给一种材质;鞋类记录只有在被列出后才会生效。

编辑原版记录: 继承

AudioXLPatcher

在 Apply 中编辑类型化字段,然后注册它。为常见情况提供了一个生成器:将其指向一个修改过的元数据导出文件,它会为你生成修补器。


- 转换 REDmod 声音模组 -

一个带有自定义声音的 REDmod 已经拥有了 AudioXL 所需的一切。

  1. 将 REDmod 的
    info.json
    
    及其
    customSounds\
    
    文件夹,原封不动地复制到:
    red4ext\plugins\AudioXL\sounds\<YourMod>\
    
    AudioXL 会直接读取 REDmod 的格式:name、type、file、gain、pitch。
  2. 如果该模组还替换了:
    cooked_metadata.audio_metadata
    
    对该文件运行附带的生成器。它会与原版文件进行差异对比,并生成一个包含所有记录编辑的 RedScript 修补器,你可以将其作为脚本发布。
  3. 从你的包中删除 REDmod 文件夹。你的用户将不再需要 REDmod。

我已经在自己的环境中对模组 The Loudening 测试了这种方法。30 条记录编辑和 490 个自定义声音,运行效果非常好!我也尝试联系过该模组的作者,但尚未收到回复,所以我不能在这里上传这项成果。


- 已知限制 -

  • 场景对话(任务配音)不走注册表。它由配音映射表和 WEM 文件驱动;ArchiveXL 可以合并映射表,但 WEM 文件需要 Wwise 2023.1。
  • radioport 路由是实验性的:它在主菜单会跟随其滑块,但目前游戏中是静音的。
  • 行数据在音频初始化时读取一次。添加清单需要重启游戏;脚本注册则随时有效。
  • 某些声音在主菜单不会播放,特别是那些通过音效总线的。

- GitHub -

完整的源代码、插件和脚本都在 GitHub 上: DigitalVixenSWE/cp2077-audio-xl。构建说明在 README 中。


- 致谢 -

感谢 psiberx 提供了 Codeware 并指出了 Resource/Load 回调。还要感谢 The Loudening 的作者 notjasonleeMisterChedda 的“啊,该死,又来了”,它们是我测试这两个模组的对象。

感谢所有优秀的模组作者,他们持续为我们创作免费内容供大家享受!


DigitalVixen 模组套件的一部分。 你现在可以在 Discord 上找到我,[点击这里](https://discord.gg/TRuuDSrGWJ)!