如何在 Web 前端做 3D 音效处理
一、背景
在社交元宇宙、大逃杀等类型的游戏场景下,用户在通过简单语音交流外,结合场景也需要一些立体声效果来让用户感知游戏角色周围其他用户的存在及其对应的距离和方位,提高语音互动的趣味性。
为了满足上述需求 ZEGO Express Web SDK 从 v2.10.0(Native 为 v2.11.0)开始加入范围语音功能模块,为游戏提供语音服务。
当前范围语音功能模块主要包括如下功能:
- 范围语音:房间内的收听者对音频的接收距离有范围限制,若发声者与自己的距离超过该范围,则无法听到声音。
- 3D 音效:听者接收的声音根据发声者相对于听者的距离和方位模拟现实中声音的立体声效果。
- 小队语音:玩家可以选择加入小队,并支持在房间内自由切换“全世界”模式和“仅小队”模式。
其中对于 Web 3D 音效这部分功能的实现,我们是基于浏览器提供的 Web Audio API 对音频进行处理。这里小编也通过使用 Web Audio API 做了一个简单的环绕音的 demo 页面。
demo 在线体验地址:https://keen_wang.gitee.io/demo/music3d,页面如下图,点击“开始播放”按钮开始播放音乐,再点击“开闭空间化”进行开启或关闭 3D 音效,打开 3D 音效后就可以听到空间环绕声效果。(在体验 3D 音效时需要使用左右声道分开的耳机或音响设备)
下文将介绍如何使用 Web Audio API 来做这个环绕音 demo。
二、Web Audio API 简介
Web Audio API 用于操作声音,很多时候用于替代 <audio> 标签来播放一段音频,除此之外,还有音频处理的功能,比如音量调节、音频混合、音频空间化等。
Web Audio API 使用户可以在音频上下文( AudioContext )中进行音频操作,具有模块化路由的特点。
下面是最简单的一个路由图,表示音频源通过效果处理后输出到音频目的地,图中的 inputs、Effects、Destination 三个模块分别对应为音频节点( AudioNode )的输入源节点、处理节点、输出节点。
编辑下面我们将介绍 Web Audio API 的简单使用步骤:
1、创建 AudioContext 音频上下文实例
// 创建音频上下文
const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioCtx = new AudioContext();
AudioContext 为音频处理提供一个上下文环境,相当于一个中央控制器,用于控制着音频路由图中的各个音频节点。
2、在音频上下文里创建输入源节点和处理节点。
// 创建输入结点,解码 audio 标签的音频源
const audioEl = document.querySelector('audio');
const sourceNode = audioCtx.createMediaElementSource(audioEl);
// 创建用于控制音频振幅的处理结点 GainNode
const gainNode = audioCtx.createGain();
3、将输入源节点连到处理节点。
输入源节点通过 connect
方法将音频数据传输给处理节点。
sourceNode.connect(gainNode);
4、将处理节点连接到选定的输出节点进行效果输出。
处理节点通过 connect
方法将处理完的音频数据传输给输出节点进行效果输出。
这里的输出节点 audioCtx.destination
为当前使用的扬声器。
gainNode.connect(audioCtx.destination);
5、修改处理节点的属性以修改输出效果。
// 设置静音处理
gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
了解完 Web Audio API 的使用特点,接下来介绍如何进行音频空间化处理。
三、实现 3D 音效
音频空间化的实现主要是通过 PannerNode
和 AudioListener
结合使用来处理声音效果。这两个类的实例对象进行设置空间方位信息后动态处理音频源并输出到左右声道。
- AudioListener 对象代表三维空间中的听者(用户),通过
AudioContext.listener
属性获取对应的实例对象;
- PannerNode 对象指的是三维空间中的声音源,通过 new 的方式或者
AudioContext.createPanner()
创建得到。
下面将介绍如何设置 AudioListener 和 PannerNode 的属性来改变 3D 音效效果。
1、设置 AudioListener
AudioListener
对象表示听者,这里可以定义听者在空间中的位置和他(她)们面向的方向,PannerNode
可以计算出声音相对于收听者位置的位置。
对于听者位置信息,AudioListener 提供了三个位置属性:positionX
、positionY
、positionZ
,它分别代表听者当前位置的 xyz 坐标,这里坐标系使用的是右手笛卡尔坐标系,x 轴和 z 轴在水平方向、y 轴在垂直方向。
// 为 listener 设置 position
const listener = audioCtx.listener;
listener.positionX = camera.position.x;
listener.positionY = camera.position.y;
listener.positionZ = camera.position.z;
(听者朝向向量的图示说明)
对于听者的朝向可通过 AudioListener 的forwardX
、forwardY
、forwardZ
这三个属性设置听者的正面朝向向量,默认值是 (0,0,-1) 。通过 AudioListener 的 upX
、upY
、upZ
这三个属性设置听者的头顶朝向方向向量,默认值是 (0,1,0) ,即垂直朝上的方向。通过这两个朝向向量的设置,即可确定听者左右耳的位置来生成立体声效果。
2、设置 PannerNode
PannerNode 是一个处理节点,提供了 3D 空间音频能力,PannerNode 通过相对于 AudioContext 的 AudioListener 的位置和朝向信息对声音进行空间化处理。
PannerNode 有以下几个常用属性:
- panningModel:音频空间化算法模型,默认值是 “equalpower”,即等幂平移算法,建议设置更为只能的 “HRTF” 。
- positionX/positionY/positionZ:声源位置坐标。
- orientationX/orientationY/orientationZ:声源朝向向量。
- coneInnerAngle:锥形角度,单位为度,默认是 360。
- rolloffFactor:声音随距离的衰减速度,默认值为 1。
- distanceModel:声音衰减算法模型,默认值是 “inverse”,即相反距离模型。
3、环绕音 Demo
了解了这些 Web Audio API,就可以开始实现一个音频空间化效果了。下面是一个播放环绕声歌曲的 demo 代码,模拟空间中一个音源在听者周围环绕。通过在播放过程中动态修改 PannerNode 的定位信息来生成环绕效果。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web Audio</title>
</head>
<body>
<audio loop autoplay crossorigin="anonymous"
src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/858/outfoxing.mp3"></audio>
<button onclick="startPlay()">开始播放</button>
<button onclick="spatialize()">开闭空间化</button>
<span>音效状态:</span><span id="status">关闭</span>
<script>
// 音源初始位置信息
const audioPosition = [0, 0, 1]
// 创建音频上下文
const AudioContext = window.AudioContext || window.webkitAudioContext;
const audioCtx = new AudioContext();
// 设置 AudioListener
const listener = audioCtx.listener;
listener.positionX.value = 0;
listener.positionY.value = 0;
listener.positionZ.value = 0;
listener.forwardX.value = 0;
listener.forwardY.value = 0;
listener.forwardZ.value = -1;
// 创建输入结点,解码 audio 标签的音频源;创建处理结点,处理音频
const audioEl = document.querySelector('audio');
const sourceNode = audioCtx.createMediaElementSource(audioEl);
// 创建和设置 PannerNode
const pannerNode = new PannerNode(audioCtx, {
panningModel: "HRTF", // 音频空间化算法模型
distanceModel: "linear", // 远离时的音量衰减算法
rolloffFactor: 1, // 衰减速度
coneInnerAngle: 360, // 声音 360 度扩散
positionX: audioPosition[0],
positionY: audioPosition[1],
positionZ: audioPosition[2],
maxDistance: 10000,
});
// 将输入节点直接连接到输出节点
sourceNode.connect(audioCtx.destination);
// 设置音源自动分别沿 xyz 三个轴来回移动效果,形成环绕效果
function autoMove(axis, interval, step = 100, maxDistance = 1000) {
let isAdd = true
const positionAxisMap = ["positionX", "positionY", "positionZ"]
setInterval(() => {
if (isAdd && audioPosition[axis] >= maxDistance) {
isAdd = false;
} else if (!isAdd && audioPosition[axis] <= -maxDistance) {
isAdd = true;
}
if (isAdd) {
audioPosition[axis] += step;
} else {
audioPosition[axis] -= step;
}
pannerNode[positionAxisMap[axis]].value = audioPosition[axis]
console.log('audioPosition', audioPosition);
}, interval)
}
// 沿 x 轴在 -1000 到 1000 之间来回移动
autoMove(0, 100, 100, 1000)
// 沿 z 轴在 -1000 到 1000 之间来回移动
autoMove(2, 200, 100, 1000)
// 沿 y 轴在 -100 到 100 之间来回移动
autoMove(1, 400, 10, 100)
// 开始播放音乐
function startPlay() {
audioCtx.resume();
// 设置静音播放。
audioEl.play();
}
// 开关 3D 音效
let isSpatialized = false
function spatialize() {
isSpatialized = !isSpatialized
document.querySelector("#status").innerText = isSpatialized ? "开启" : "关闭"
if (isSpatialized) {
sourceNode.disconnect();
sourceNode.connect(pannerNode);
// 将处理节点连接到 destination 输出节点进行效果输出。
pannerNode.connect(audioCtx.destination);
} else {
sourceNode.disconnect();
sourceNode.connect(audioCtx.destination);
}
}
</script>
</body>
</html>
四、结语
本文主要讲解了对于 Web Audio API 的基本使用及使用 AudioListener 和 PannerNode 实现环绕声效果。
Web Audio API 除了进行 3D 音效外还有很多强大的音频处理能力,可以查看 MDN 上的文档了解 Web Audio API 更多能力,链接:https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API#%E5%AE%9A%E4%B9%89%E9%9F%B3%E6%95%88 。
如果想要了解更多关于 ZEGO Express SDK 范围语音功能模块,可以查看 ZEGO 官网介绍文档,链接: https://doc-zh.zego.im/article/12045 。
也可以打开我们的范围语音 Demo 进行体验:https://zegoim.github.io/express-demo-web/src/Examples/Others/RangeAudio/index.html
如何在 Web 前端做 3D 音效处理的更多相关文章
- 如何在Web前端实现CAD图文字全文搜索功能之技术分享
现状 在CAD看图过程中我们经常会需要用到查找文字的功能,在AutoCAD软件查找一个文字时,可以通过打开左下角输入命令find,输入查找的文字,然后设置查找范围,就可以搜索到需要查询的文字.但在We ...
- “设计型web前端与开发型web前端”有哪些区别?
学web前端,你弄懂开发型web前端和设计型web前端的区别了吗?今天给大家梳理一下设计型web前端做什么?都要学习什么? 想必大家也会遇到这种情况,要做一个项目,产品经理说产品原型图已经画好了,让我 ...
- 学习WEB前端是应该自学还是参加培训机构?
先说观点,我强烈建议每个人都要自学,不要参加培训班. 我干web前端工程师这个职位已经有6年多的时间,之前在蚂蚁金服做过2年,后来离开是因为加班实在熬不住才走的,像这些已经上市的互联网公司几乎没有不加 ...
- 学web前端开发有前途吗
web前端开发现在如此火爆,可以说是引领了IT培训行业的一个潮流,那么web前端开发都要学些什么知识呢?为什么这么火有前途吗?现在行业很需要这种人才吗?还是大家盲目跟风,随大流,下面小编对web前端做 ...
- Web前端 Web前端和Web后端的区分
一.绪论 1. 前台:呈现给用户的视觉和基本的操作. 后台:用户浏览网页时,我们看不见的后台数据跑动.后台包括前端.后端. 前端:对应我们写的html.css.javascript 等网页语言作用在前 ...
- Web前端和Web后端的区分
版权声明:本文为CSDN博主「十豆三展」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/zz1399590022 ...
- [Web 前端] 如何在React中做Ajax 请求?
cp from : https://segmentfault.com/a/1190000007564792 如何在React中做Ajax 请求? 首先:React本身没有独有的获取数据的方式.实际上, ...
- Web前端可以转行做游戏吗?
作者:ManfredHu 链接:http://www.manfredhu.com/2018/03/15/31-laya-game-tips/index.html 声明:版权所有,转载请保留本段信息,谢 ...
- 什么是Web前端,Web前端是做什么的?
什么是Web前端 Web前端,顾名思义是来做Web的前端的.而Web前端开发应该就是来开发基于Web前端的相关应用的或者说是来开发前端的.那么,前端又是什么呢?我们这里所说的前端泛指Web前端,也就是 ...
- 绝对精品推荐做前端的看下:Web前端开发体会十日谈
20151208感悟: 前端人的角度来看的话,感觉像是阅读一个大牛前端的全部武功的一个秘籍说明,里面的思想高价值蛋白真是太多太多,推荐看. Web前端开发体会十日谈 一直想写这篇“十日谈”,聊聊我对W ...
随机推荐
- JVM是如何创建一个对象的?
哈喽,大家好,我是世杰. 本文我为大家介绍面试官经常考察的「Java对象创建流程」 照例在开头留一些面试考察内容~~ 面试连环call Java对象创建的流程是什么样? JVM执行new关键字时都有哪 ...
- c 语言学习第四天
if 语句 格式: // 1 // 其他语句... if(表达式){ // 其他语句... } // 其他语句... // 2 if(表达式){ }else{ } // 3 if(表达式1){ }el ...
- 洛谷P1063
[NOIP2006 提高组] 能量项链 题目描述 在 Mars 星球上,每个 Mars 人都随身佩带着一串能量项链.在项链上有 \(N\) 颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着 ...
- 算法金 | 来了,pandas 2.0
大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 今日 210+/10000,内含 Pandas 是一个强大的数据分析库,广泛应用于科学 ...
- 微调 Florence-2 - 微软的尖端视觉语言模型
Florence-2 是微软于 2024 年 6 月发布的一个基础视觉语言模型.该模型极具吸引力,因为它尺寸很小 (0.2B 及 0.7B) 且在各种计算机视觉和视觉语言任务上表现出色. Floren ...
- PHP 使用非对称加密算法
加密的类型: 在日常设计及开发中,为确保数据传输和数据存储的安全,可通过特定的算法,将数据明文加密成复杂的密文.目前主流加密手段大致可分为单向加密和双向加密. 单向加密:通过对数据进行摘要计算生成密文 ...
- webpack4.15.1 学习笔记(二) — 配置及开发环境构建
目录 基本安装 配置文件 管理资源 管理输出 构建一个开发环境 使用 source map 选择一个开发工具 观察模式 webpack-dev-server webpack-dev-middlewar ...
- 【2024最新】4000字搞懂sora!一张脑图贯穿!
话不多说,上图! 下面就是对sora的具体阐释: Sora是OpenAI推出的一款革命性的视频生成模型,能够根据文本指令.静态图像或视频生成长达60秒的完整视频.这一模型基于扩散式模型和自注意力深度学 ...
- ASP.NET Core 程序集注入(三)
前言: 在Autofac的使用中,提供了个种注入的API其中GetAssemblies()用着特别的舒坦. 1.core2.0也可以使用Autofac的包,但框架自身也提供了默认的注入Api,ISer ...
- 奇怪的回溯增加了 | leetcode131分割回文串
题目要求:给你一个字符串 s,请你将s分割成一些子串,使每个子串都是回文串.返回 s 所有可能的分割方案 示例 1: 输入:s = "aab" 输出:[["a" ...