前言
AudioContext设计的API简直太多了,而且目前好多API还处在实验阶段,并未被所有浏览器完全支持, 所以本文不打算覆盖所有知识,只简单学习几个常用的API。先知其然,再知其所以然,也不失为一种学习方法嘛。 (其实好多我是真的不懂 😂)
简介
一个简单而典型的web audio流程如下:
创建音频上下文
在音频上下文里创建源 — 例如 aduio, 振荡器, 流
创建效果节点,例如混响、双二阶滤波器、平移、压缩
为音频选择一个目的地,例如你的系统扬声器
连接源到效果器,对目的地进行效果输出
效果视频
代码就不放了需要的可以点击这里看
实现
首先实现简单的播放音乐
html媒体标签有<HTML>,<video>等。其余如<input>标签需要转换为arraryBfuuer对象或者HTMLMediaElement对象处理后使用。
从html标签获得媒体源播放
媒体标签元素
<!-- 通过html标签获得音频源 -->
<audio id='medio' controls src="https://jsdelivr.007666.xyz/gh/1802024110/GitHub_Oss@main/music/群青.mp3"></audio>
<!-- 或者video,input等标签也可 -->
<button onclick="play()">播放</button>
const medioAudio = document.getElementById('medio');
// 获得音频源标签
medioAudio.crossOrigin = 'anonymous';
//结局跨域没声音问题
function play() {
const ca = new (AudioContext || webkitAudioContext);
/*
因为所有事情都是在上下文中发生的。
建议创建一个AudioContext对象并复用它,
而不是每次初始化一个新的AudioContext对象,
并且可以对多个不同的音频源和管道同时使用一个AudioContext对象。
*/
const source = ca.createMediaElementSource(medioAudio);
// 创建一个MediaElementSource对象,并将音频源添加到其中
source.connect(ca.destination);
// 将音频源添加到AudioContext的destination属性中
medioAudio.play();
// 播放音频源
}
非媒体标签元素
<input type="file" accept="video/*,audio/*" id="medio2">
<script>
const ca = new (AudioContext || webkitAudioContext);
const input = document.getElementById('medio2');
input.addEventListener('change', function () {
// 上传文件触发事件
input.files[0].arrayBuffer().then(function (buffer) {
// 获得文件的arrayBuffer
ca.decodeAudioData(buffer).then(function (data) {
// 解码arrayBuffer
const source = ca.createBufferSource();
source.buffer = data;
source.connect(ca.destination);
source.start();
})
})
})
</script>
从网络获得媒体源播放
<button onclick="play()">播放</button>
<script>
function play() {
const ca = new (AudioContext || webkitAudioContext);
fetch('https://jsdelivr.007666.xyz/gh/1802024110/GitHub_Oss@main/music/群青.mp3')
// fetch类似ajax/axios,返回一个Response对象
.then(res => {
res.arrayBuffer().then(arrayBuffer => {
// res.arrayBuffer()返回一个ArrayBuffer对象
ca.decodeAudioData(arrayBuffer).then(audioBuffer => {
// audioBuffer是AudioBuffer对象
const source = ca.createBufferSource();
// 创建一个流对象
source.buffer = audioBuffer;
// 把音频数据放入流对象
source.connect(ca.destination);
// 把流对象连接到输出设备
source.start();
// 播放
});
})
})
}
</script>
从设备录音播放(手机大部分不可用)
<button id='medio' >开始录音</button>
if (navigator.mediaDevices === undefined) {
alert('您的浏览器不支持录音功能,请更换浏览器');
}
// 检查是否支持API
const medio = document.getElementById('medio');
medio.addEventListener('click', function () {
// button的点击事件
navigator.mediaDevices.getUserMedia({
//设置获取设备
audio: {
sampleRate: 44100,
channelCount: 2,
},
video: false
}).then(function (stream) {
// 录音得到的是MediaStream对象
const ac = new (AudioContext || webkitAudioContext);
const soure = ac.createMediaStreamSource(stream);
soure.connect(ac.destination);
// 链接到播放器
}).catch(function (err) {
switch (err.name) {
case 'NotFoundError':
alert('没有找到设备');
break;
case 'SecurityError':
alert('安全错误');
break;
case 'NotAllowedError':
alert('您以拒绝访问麦克风');
break;
case 'AbortError':
alert('硬件出错');
break;
default:
alert('未知错误');
break;
}
});
})
获得音频数据
<input type="file" accept="video/*,audio/*" id="medio3">
<!-- svg展示波形,可忽略 -->
<svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg"></svg>
<script>
const ca = new (AudioContext || webkitAudioContext);
const input = document.getElementById('medio3');
input.addEventListener('change', function () {
input.files[0].arrayBuffer().then(function (buffer) {
ca.decodeAudioData(buffer).then(function (data) {
const source = ca.createBufferSource();
source.buffer = data;
const analyser = ca.createAnalyser();
// 创建一个音频分析器
analyser.fftSize = 512;
setInterval(() => {
let arr = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(arr)
arr = arr.slice(5, 170);
// 取arr里165个数据因为其最活跃
draw(arr);
// 往svg画画,不重要
}, 50);
source.connect(analyser);
// 流对象连接到分析器
analyser.connect(ca.destination);
// 分析器连接到输出设备
source.start();
// 播放
})
})
})
function draw(arr) {
/* 绘制音频图 */
const svg = document.querySelector('svg');
// 删除svg中的所有元素
svg.innerHTML = '';
// svg插入line
// 创建一个line
for (i = 1; i < arr.length; i++) {
const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
// 屏幕宽度
const width = window.innerWidth;
// x坐标为百分比屏幕宽除数组长度
line.setAttribute('x1', (i * (width / arr.length)));
line.setAttribute('y1', 255);
line.setAttribute('x2', i * (width / arr.length));
line.setAttribute('y2', arr[i]);
line.setAttribute('stroke', `rgb(${arr[i]},99,${arr[i]})`);
line.setAttribute('stroke-width', 1 + 'px');
svg.appendChild(line);
}
}
</script>
Markdown显示效果不好