纯JS实现多个音频的拼接或者合并 « 张鑫旭 | 您所在的位置:网站首页 › 如何把多段音频合并 › 纯JS实现多个音频的拼接或者合并 « 张鑫旭 |
by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11022 鑫空间-鑫生活 本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。 一、温故而知新3年前有更新过JS对audio音频剪裁的实现,昨天更新了JS改变原始音频信息来实现音量的调整,今天我们再讲讲如何使用JS实现多个音频的拼接(下图1)与合并(下图2)。 拼接: 合并: 这下子,纯JS操作MP3/WAV音频资源的活儿都齐全了。 操作过程本质上大同小异。 ArrayBuffer转AudioBuffer,然后读取音频信息,对采样信息进行处理。 话不多说,来看看如何实现的。 二、多个音频的拼接方法如下: // 拼接音频的方法 const concatAudio = (arrBufferList) => { // 获得 AudioBuffer const audioBufferList = arrBufferList; // 最大通道数 const maxChannelNumber = Math.max(...audioBufferList.map(audioBuffer => audioBuffer.numberOfChannels)); // 总长度 const totalLength = audioBufferList.map((buffer) => buffer.length).reduce((lenA, lenB) => lenA + lenB, 0); // 创建一个新的 AudioBuffer const newAudioBuffer = audioContext.createBuffer(maxChannelNumber, totalLength, audioBufferList[0].sampleRate); // 将所有的 AudioBuffer 的数据拷贝到新的 AudioBuffer 中 let offset = 0; audioBufferList.forEach((audioBuffer, index) => { for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) { newAudioBuffer.getChannelData(channel).set(audioBuffer.getChannelData(channel), offset); } offset += audioBuffer.length; }); return newAudioBuffer; }语法: concatAudio(arrBufferList);其中: arrBufferList 指需要合并的AudioBuffer数组。那如何获得音频的AudioBuffer数据呢? 可以使用 new AudioContext().decodeAudioData(arrayBuffer) 方法转换。 那如何得到arrayBuffer数据呢? 本地资源可以使用FileReader对象读取为ArrayBuffer,在线资源可以使用fetch请求获取。 这里演示使用Fetch API得到音频的AudioBuffer数据。 // AudioContext const audioContext = new AudioContext(); // 基于src地址获得 AudioBuffer 的方法 const getAudioBuffer = (src) => { return new Promise((resolve, reject) => { fetch(src).then(response => response.arrayBuffer()).then(arrayBuffer => { audioContext.decodeAudioData(arrayBuffer).then(buffer => { resolve(buffer); }); }) }) }假设现在有下面两个音频地址: const audioSrc = [ './assets/1.wav', './assets/2.wav' ];则使用下面几行JS就可以实现得到concat拼接后的新的音频的AudioBuffer数据了。 const arrBufferList = await Promise.all(audioSrc.map(src => getAudioBuffer(src)));有了AudioBuffer数据,我们就可以播放音频,或者转为可下载的音频格式。 眼见为实,您可以狠狠地点击这里:纯JS实现音频的合并或拼接demo 点击演示页面中的“拼接”按钮,如下图所示,此时,就可以看到在下面的色块区域内显示了拼接后的音频了: 三、多个音频的合并音频的合并指的是多个音频同时播放,但是是合在一个视频中。 我也弄了个JS函数方法: // 合并音频的方法 const mergeAudio = (arrBufferList) => { // 获得 AudioBuffer const audioBufferList = arrBufferList; // 最大播放时长 const maxDuration = Math.max(...audioBufferList.map(audioBuffer => audioBuffer.duration)); // 最大通道数 const maxChannelNumber = Math.max(...audioBufferList.map(audioBuffer => audioBuffer.numberOfChannels)); // 创建一个新的 AudioBuffer const newAudioBuffer = audioContext.createBuffer(maxChannelNumber, audioBufferList[0].sampleRate * maxDuration, audioBufferList[0].sampleRate); // 将所有的 AudioBuffer 的数据合并到新的 AudioBuffer 中 audioBufferList.forEach((audioBuffer, index) => { for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) { const outputData = newAudioBuffer.getChannelData(channel); const bufferData = audioBuffer.getChannelData(channel); for (let i = audioBuffer.getChannelData(channel).length - 1; i >= 0; i--) { outputData[i] += bufferData[i]; } newAudioBuffer.getChannelData(channel).set(outputData); } }); return newAudioBuffer; }其中: arrBufferList 指需要合并的AudioBuffer数组。mergeAudio 方法的语法和具体的使用和上面的 concatAudio 方法类似,这里就不再赘述了。 demo也是同一个页面:纯JS实现音频的合并或拼接demo 点击“合并”按钮,就可以得到背景音乐和段落音频合二为一后的新的音频了(右键播放器可以下载此视频): 完整的实现代码均在demo页面上。 相信国内没有比我这里更直观更容易上手的演示代码了。 四、使用开源的项目如果你对原生实现不怎么感兴趣,也可以使用开源项目。 其实还挺多的,之前找了一个,没记住,忘记了。 那就用这个项目吧,名字奇奇怪怪的,叫做crunker:https://github.com/jaggad/crunker 使用示意: let crunker = new Crunker(); crunker .fetchAudio('/song.mp3', '/another-song.mp3') .then((buffers) => { // => [AudioBuffer, AudioBuffer] return crunker.mergeAudio(buffers); }) .then((merged) => { // => AudioBuffer return crunker.export(merged, 'audio/mp3'); }) .then((output) => { // => {blob, element, url} crunker.download(output.blob); document.body.append(output.element); console.log(output.url); }) .catch((error) => { // => Error Message });如果你已经有了 AudioBuffer 资源,上面的 fetchAudio() 方法也是可以省略的。 另外,此JS还支持使用静音填充视频……嗯,直接剪裁不香么~ 五、结束啦下节预告好了,正文结束。 最近项目有用到,记录下,即方便以后的自己,也方便遇到类似需求的大家,毕竟国内类似的教程资源可不多见。 然后,预告下下篇文章内容,我都已经想好了。 已知 Shader、frag、vert 等资源,如何使用类似 P5.js 这样的JS库给图片资源应用对应的滤镜效果。 技术的成长就是这样子的,一点一点积累出来的。 三五年前,我看Web Audio API的时候,感觉是天书,妈呀,这么多概念,哪个是哪个啊。 但是接触多了,一个需求一个需求慢慢实现下来,反复了解其整个API体系,自然就懂得多了,遇到需求也就知道大致的实现思路。 之前玩过JS解析 3D LUT 滤镜,不过那还是2D层面,虽然效果好,但是性能不太行,所以,这次试试WebGL,之前还没做过类似的实践,好期待哦。 本文为原创文章,欢迎分享,勿全文转载,如果实在喜欢,可收藏,永不过期,且会及时更新知识点及修正错误,阅读体验也更好。 本文地址:https://www.zhangxinxu.com/wordpress/?p=11022 (本篇完) 相关文章JS改变AudioBuffer音量并下载为新audio音频 (0.732)使用JS提取视频中的音频资源 (0.622)不改变音调情况下Audio音频的倍速合成JS实现 (0.571)JS纯前端实现audio音频剪裁剪切复制播放与上传 (0.410)CSS实现文字下面波浪线动画效果 (0.322)JS audio加图片序列或canvas转webM/MP4的实现 (0.218)理解DOMString、Document、FormData、Blob、File、ArrayBuffer数据类型 (0.161)腾讯开源的酷炫动画播放解决方案Vap初体验 (0.161)JS视频解码JSMpeg和Broadway开箱测评 (0.161)借助Service Worker和cacheStorage缓存及离线开发 (0.107)二次元live2d看板娘效果中的web前端技术 (RANDOM - 0.057) |
CopyRight 2018-2019 实验室设备网 版权所有 |