写在前面:
接上篇博文:Web前端JS如何获取 Video/Audio 视音频声道(左右声道|多声道)、视音频轨道、音频流数据 讲解了如何根据视频链接地址,实现在播放时实时的显示该视频的音频轨道情况,并实时的将各音频轨道数据以可视化(响度跳表)的形式展现出来。
本篇博文主要讲解:Web前端JS如何控制 Video/Audio 视音频声道(左右声道|多声道)、视音频轨道、音频流数据。如:实现各个 视音频声道(左右声道|多声道)的 独立音量大小、静音的控制。
实现效果
需要注意的是,由于我们日常中活中大部份硬件设备,如:电视机、笔记本电脑、耳机等,只有两个扬声器(简音来说,就是只有左L 和 右R 两个喇叭,就只能听到两个音频轨道的声音)如果要测试多声道的话,至少满足以下两个条件:
- 1、播放的视音频文件必须是有多音轨的(就是两个以上的声道)
- 2、播放的硬件设备必须是有多个扬声器(就是两个以上的喇叭)
关键技术
在Web浏览器中,想要获取多媒体文件的相关数据信息,需要借助对应的API来完成,比如获取视音文件的音频信息,就需要用到Web Audio API,通过该API我们可以轻松做到播放声音、获取声音数据,修改声音数据、甚至还可以制造声音。
Web Audio API 之 GainNode接口
GainNode 接口表示音量的变化。它是一个 AudioNode 音频处理模块,在输出前使用给定增益应用到输入。一个 GainNode 始终只有一个输入和一个输出,两者拥有同样数量的声道。
增益是一个无单位的值,会对所有输入声道的音频进行相应的增加(相乘)。如果进行了修改,则会立即应用新增益,从而在结果音频中产生奇怪的“咔嗒”声。为了防止这种情况发生,请不要直接更改值,而应在 AudioParam 接口上使用指数插值方法。
GainNode接口:
https://developer.mozilla.org/zh-CN/docs/Web/API/GainNode
了解更多API:
https://www.w3.org/TR/webaudio、https://developer.mozilla.org/zh-CN/docs/Web/API/Web_Audio_API
实例代码
1. HTML标签
由于video和audio都有音频,所以我们可以video或者audio来获取输入源,除此以外,我们还可以通过 navigator.getUserMedia API 或 Ajax请求的方式来获取输入源。
<video loop controls>
<source src="./media/xxx.mp4" type="video/mp4" />
</video>
<audio loop controls>
<source src="./media/xxx.mp3" type="audio/mp3" />
</audio>
2.JavaScript代码
在创建AudioContext 上下文环境对象时, 由于浏览器安全策略要求音频上下文必须在用户事件(单击、键盘按键等)中启用。这意味着,如果您尝试在没有用户事件的情况下自动播放音乐,所以在loadedmetadata元数据已加载时再执行!!
// 创建一个 AudioContext 环境
const ac = new (window.AudioContext || window.webkitAudioContext)();
// 从 video 或 audio 标签元素中拿到输入源
const audio = document.querySelector("video");
// const audio = document.querySelector("audio");
// 创建并获取输入源
const audioSource = ac.createMediaElementSource(audio);
// 音频通道数 默认值是 2,最高能取 32
const channelCount = 2 || audioSource.channelCount;
// 创建音频处理器
const processor = ac.createScriptProcessor(2048, channelCount, channelCount);
// 链接音频处理器
audioSource.connect(processor).connect(ac.destination);
// 创建通道控制器
const volumeNodeL = new GainNode(ac, { gain: 1 });
const volumeNodeR = new GainNode(ac, { gain: 1 });
// 创建通道分配器
const splitterNode = new ChannelSplitterNode(ac, {
numberOfOutputs: channelCount,
});
splitterNode.connect(volumeNodeL, 0);
splitterNode.connect(volumeNodeR, 1);
// 控制链接到输入源
audioSource.connect(splitterNode);
// 创建通道合并器
const mergerNode = new ChannelMergerNode(ac, {
numberOfInputs: channelCount,
});
volumeNodeL.connect(mergerNode, 0, 0);
volumeNodeR.connect(mergerNode, 0, 1);
// 通道链接到扬声器
mergerNode.connect(ac.destination);
// 监听音频处理器每次处理的样本帧
processor.onaudioprocess = (evt) => {
//获取声轨1输入的缓冲区数据
let input =evt.inputBuffer.getChannelData(0);
//获取声轨1输出的缓冲区数据
let output = evt.outputBuffer.getChannelData(0);
};
// 静音左L声道
LBTN.onclick = function () {
volumeNodeL.gain.value = Number(!volumeNodeL.gain.value);
};
// 左L声道音量大小控制
VL.oninput = function () {
// volumeNodeL.gain.value = this.value;
volumeNodeL.gain.setValueAtTime(this.value, ac.currentTime);
VLV.innerText = '音量:' + this.value;
};
3. 完整实例代码
可以通过添加本地的视频 或 音频文件,来测试对应的声道,并实时的渲染到响度跳表中,需要注意的是,音频跳表从-60开始的原因主要是,当输出音量接近满载时,THD(总谐波失真)的表现会比较差,此时产生的谐波会盖掉原本存在的背景噪音,影响到测试成绩。因此,采用-60dB的测试信号。
音频跳表值通常在-60dB到+3dB之间。在音频设备测试中,跳表值反映了设备的频率响应和增益。不同的音频设备可能会有不同的跳表值范围,根据测试标准和设备要求而定。