by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=11293
本文可全文转载,独立域名个人网站无需授权,但需要保留原作者、出处以及文中链接,任何网站均可摘要聚合,商用请联系授权。
希望特效音可以有淡入淡出效果,同时能够在视频合成的时候体现在音轨中。
先讲下偏浅层应用的技术实现,那就是播放淡入淡出。
howlerjs这个项目(https://github.com/goldfire/howler.js)我多次提到过,凡是音频播放的需求(除了那种简单的点击播放),无需任何迟疑,也不用考虑其他,就是要howlerjs。
两三万Star的项目,品质保证。
下面演示下如何实现。
假设页面上有个按钮,点击按钮播放某音频,HTML示意:
<button id="button">点击播放</button>
则下面几行JavaScript代码可以实现音频播放淡入,结束淡出的效果。
const url = './htmlbook.wav'; const sound = new Howl({ src: [url] }); // 点击按钮,音频淡入淡出播放 button.onclick = function () { sound.play(); sound.fade(0, 1, 1000); setTimeout(() => { sound.fade(1, 0, 1000); }, sound.duration() * 1000 - 1500); }
根据我查找的资料,howlerjs并未提供内置的结尾淡出方法,只有一个fade()方法,因此,结束时候声音淡出使用了定时器。而之所以定时器offset的时间是1500ms而不是淡出的1000ms时间,是因为案例使用的htmlbook.wav末尾有一段声音是静音,为了让淡出效果明显,才如此处理的,不代表通用场景。
眼见为实,您可以狠狠地点击这里:使用Howler.js实现音频播放淡入淡出demo
点击下图所示的按钮,就可以听到WAV音频声音fade播放的效果了。
JS Web Audio API提供了原生的音量动态函数变化方法。包括:
下面,我们使用GainNode对象和linearRampToValueAtTime()
方法示意如何实现音频播放首尾淡入淡出效果,和上面按钮同样的HTML代码,就一个按钮,然后JS代码如下所示。
const url = './htmlbook.wav'; // 点击按钮,音频淡入淡出播放 button.onclick = function () { // 请求数据 fetch(url).then(res => res.arrayBuffer()).then(buffer => { const audioContext = new AudioContext(); audioContext.decodeAudioData(buffer, function (audioBuffer) { const source = audioContext.createBufferSource(); const gainNode = audioContext.createGain(); // 起始音量静音 gainNode.gain.value = 0; gainNode.connect(audioContext.destination); // buffer数据设置 source.buffer = audioBuffer; source.connect(gainNode); source.start(); gainNode.gain.linearRampToValueAtTime(1.0, audioContext.currentTime + 1); // 时长计算 const duration = audioBuffer.duration; setTimeout(() => { gainNode.gain.linearRampToValueAtTime(0.01, audioContext.currentTime + 1); }, duration * 1000 - 1200); }); }); }
此时,点击按钮,就可以听到声音淡入淡出播放的效果了。例如,点击下面这个按钮:
如果没有效果,多半是在第三方网站,狠击这里访问实例:使用GainNode实现音频淡入淡出播放demo
补充说明
根据自己和官方demo测试,exponentialRampToValueAtTime()
函数执行的时候,声音是突然变化的,不知道是不是我设备的问题。
如果我们希望对音频进行转换,也就是直接把原始音频转换成淡入淡出的音频,就需要处理音频的AudioBuffer数据。
这个就相对深入些了,原理什么的大家应该都不关心,不啰嗦,3,2,1,直接上代码,见:
const sliceAudio = function (buffer, start, end, fadeIn = 0, fadeOut = 0) { const sampleRate = buffer.sampleRate; const audioContext = new AudioContext(); const length = Math.round((end - start) * sampleRate); const offset = Math.round(start * sampleRate); const newBuffer = audioContext.createBuffer(buffer.numberOfChannels, length, sampleRate); for (let channel = 0; channel < buffer.numberOfChannels; channel++) { const inputData = buffer.getChannelData(channel); const outputData = newBuffer.getChannelData(channel); for (let i = 0; i < length; i++) { outputData[i] = inputData[offset + i]; // Apply fade in if (i < fadeIn * sampleRate) { outputData[i] *= i / (fadeIn * sampleRate); } // Apply fade out if (i > length - fadeOut * sampleRate) { outputData[i] *= (length - i) / (fadeOut * sampleRate); } } } return newBuffer; }
其中:
buffer.duration
。具体如何应用呢?可以参见下面的演示页面。
您可以狠狠地点击这里:MP3/Wav AudioBuffer转换成淡入淡出音频demo
点击“转换”按钮,下面的音频播放器播放的就是被淡入淡出处理后的音频,点击现在我们可以得到这个新的WAV音频文件。
主要应用代码示意(从点击按钮开始):
const url = './htmlbook.wav'; // 点击按钮,音频淡入淡出播放 button.onclick = function () { // 请求数据 fetch(url).then(res => res.arrayBuffer()).then(buffer => { const audioContext = new AudioContext(); audioContext.decodeAudioData(buffer, (audioBuffer) => { const convertBuffer = sliceAudio(audioBuffer, 0, audioBuffer.duration, 1, 1.5); // 转blob WAV const wavBuffer = audioBufferToWav(convertBuffer); const wavBlob = new Blob([wavBuffer], { type: 'audio/wav' }); const urlBlob = URL.createObjectURL(wavBlob); // create download link and append to Dom const downloadLink = document.createElement('a'); downloadLink.href = urlBlob; downloadLink.setAttribute('download', 'htmlbook-fade.wav'); downloadLink.textContent = '下载'; // 按钮禁用 this.disabled = true; // 试听支持 audio.src = urlBlob; // 下载支持 audio.after(downloadLink); }); }); }
更完整的处理代码,参见上面的演示页面的源代码(演示页面省略了AudioBuffer转Wav blob数据的代码)。
周三的时候,我的新书已经是京东日榜第1了,看来口碑发酵了,感谢大家的正版支持。
稍后补充,先发布。
本文为原创文章,会经常更新知识点以及修正一些错误,因此转载请保留原出处,方便溯源,避免陈旧错误知识的误导,同时有更好的阅读体验。
本文地址:https://www.zhangxinxu.com/wordpress/?p=11293
(本篇完)