JS改变AudioBuffer音量并下载为新audio音频

这篇文章发布于 2023年10月9日,星期一,22:50,归类于 JS实例。 阅读 7056 次, 今日 4 次 6 条评论

 

音频波形图

如今的Web越来越强,几乎常见的音视频开发需求都能使用纯JS搞定了。

一、这里需要个标题

这里介绍一个不太常见的使用场景的技术实现。

啥呢,就是音频的音量调整,并转换成新文件。

如果仅仅是调整播放的音量,那很简单。

如果你使用的是 <audio> 元素,直接改变volume属性就好了。

audio.volume = 0.5;

over~

如果没有audio元素,而是使用的Web Audio API,希望在 AudioBuffer 层面设置播放的音量,则可以使用GainNodes实现。

假设我们有个在线的MP3音频叫做“bgmusic.mp3”,则可以这么处理。

// 定义一个AudioContext对象
// 因为 Web Audio API都是源自此对象
const audioContext = new AudioContext();
// 创建一个gainNode对象
// gainNode可以对音频输出进行一些控制
const gainNode = audioContext.createGain();
// 音量设置为20%
gainNode.gain.value = 0.2;
// 这个很有必要,建立联系
gainNode.connect(audioContext.destination);

// 创建AudioBufferSourceNode
let source = audioContext.createBufferSource();
// 获取音频资源
fetch('./bgmusic.mp3')
  .then(res => res.arrayBuffer())
  .then(buffer => audioContext.decodeAudioData(buffer))
  .then(audioBuffer => {
    source.buffer = audioBuffer;
    source.connect(gainNode);
  });

// 当需要播放的时候,执行
source.start(0);

您可以狠狠地点击这里体验效果:使用gainNode改变音频播放音量demo

上面的是原音频,音量还是很猛的。

点击下面的按钮,则会听到轻很多的声音,这个音量的降低就是GainNodes实现的。

demo页面的点击播放按钮

然而,GainNodes降低音量仅仅是在播放层面的控制,并不是改变原始的音频音量大小。

所以,如果现在有个需求,希望可以下载这个音量减小后的音频,那使用gainNode API 实现的方法就无效,此时,需要借助其他的方法。

二、采样与音频数据的重置

音频的本质是波,现实世界的波是连续的,但是音频却不是,本质上是一个一个的点采样来的。

如下图所示:

采样就是打点

例如在1s内打48000个点,那么采样率就是48000。

采样率越高,音频质量越好,音频文件的体积也就越大。

所以,想要改变音频原始的音量,可以获取到音频每个点的采样数据,然后和音量对应的比例相乘就好了。

OK,原理清楚了,那该怎么实现呢?

嗯……想了下,还是直接放代码吧,没多少人对ArrayBuffer,AudioBuffer,AudioData等概念有兴趣的。

就是这个,拿去复制粘贴吧。

// 音量
const volume = 0.2;
// 定义一个AudioContext对象
// 因为 Web Audio API都是源自此对象
const audioContext = new AudioContext();
// 降低音量后的audioBuffer数据
let newAudioBuffer = null;
// 获取音频资源
fetch('./bgmusic.mp3')
  .then(res => res.arrayBuffer())
  .then(buffer => audioContext.decodeAudioData(buffer))
  .then(audioBuffer => {
    newAudioBuffer = new AudioBuffer({
        length: audioBuffer.length,
        numberOfChannels: audioBuffer.numberOfChannels,
        sampleRate: audioBuffer.sampleRate
    });
    
    for (let channel = 0; channel < audioBuffer.numberOfChannels; channel += 1) {
        const channelData = audioBuffer.getChannelData(channel);
        const copiedChannelData = newAudioBuffer.getChannelData(channel);
    
        for (let sample = 0; sample < channelData.length; sample += 1) {
            copiedChannelData[sample] = channelData[sample] * volume;
        }
    }
});

此时,newAudioBuffer就是音量降低到20%时候的audioBuffer数据。

我们可以使用此数据进行音频的播放,或者编码,或者下载,都可以。

三、如何作为文件下载

这个以前其实分享过,纯JS合成音频,或者说AudioBuffer数据转音频,目前只支持wav格式(哪怕后缀是mp3,其实也是wav格式)。

// 转换 AudioBuffer 为 Wave 格式的 Blob 地址
function bufferToWave(abuffer, len) {
    // 略,详见下面的演示页面
}

您可以狠狠地点击这里:MP3音频在线音量降低并下载demo

点击按钮后,执行类似下面的JS代码:

const blob = bufferToWave(newAudioBuffer, newAudioBuffer.length);

就可以get到音量降低后的音频了,你也可以选择下载此音频。

点击按钮后的效果预览

四、本文只是开胃菜

本文只是开胃菜,下一篇文章,我们会更进一步,看看如何借助 Web Audio API 实现音频的拼接与合并。

噢啦,将捏。

“将捏”是再见的意思。

表示本文正文内容到此为止了。

要是本文的内容对你的工作或学习帮了大忙,想要聊表谢意,可以等什么时候京东搞活动的时候,入手我的《CSS世界》三部曲……之一就可以了。

当然,也欢迎点赞或

? ? ? ? ?

(本篇完)

分享到:


发表评论(目前6 条评论)

  1. noHandFish说道:

    如果同时需要调节速度 比如让音频二倍速能做到吗

  2. DH说道:

    正好最近在插件项目中使用到音量控制

  3. zhangxinxu说道:

    小刀拉屁股

  4. 某某某说道:

    何不试试 OfflineAudioContext? 不过,对于调音量是有些杀鸡用牛刀了。

  5. 小小说道:

    谢谢,开眼界了