朋友们,美好的一天!我想分享音频方面的经验。“音频”是指HTMLAudioElement和Web Audio API。我们做什么?我们将为某首曲目创建一个播放器(在以下文章之一中,关于成熟的播放器)。条件:- 单击按钮或通过拖放从硬盘上任何位置下载文件的功能。
- 圆形图形和文本进度指示器。
- 音量的文本指示符。
- 可视化音频数据。
- 使用键盘控制播放器。
网络上充斥着HTMLAudioElement和WAAPI的资料,因此我将重点介绍实际组件。除了音频,我们还将使用拖放和canvas。没有进一步介绍...是的,我几乎忘记了:我把哈布罗夫斯克的一位公民的工作作为“可视化工具”的基础。我无法通过搜索找到它。请提供参考。我们的标记如下所示:<p>click or drag</p>
<div dropzone>
<img src="https://thebestcode.ru/media/audioProgress&Visualizer/plus.png" alt="#">
<input type="file" accept="audio/*">
</div>
<canvas></canvas>
我们有一个工具提示(段落),一个按钮(图片+“输入”,在容器中具有accept属性,并具有dropzone属性)和画布。如您所见,没有什么异常。风格上也没有什么超自然的。CSS:@font-face {
font-family: "Nova Mono", monospace;
src: url("https://thebestcode.ru/media/audioProgress&Visualizer/font.ttf");
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
height: 100vh;
background: radial-gradient(circle, #666, #222);
display: flex;
justify-content: center;
align-items: center;
}
p {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -70px);
color: #ddd;
text-align: center;
text-transform: uppercase;
font-family: "Nova Mono", monospace;
font-size: 0.8em;
font-weight: bold;
letter-spacing: 2px;
user-select: none;
}
span {
display: block;
font-size: 1.6em;
}
div {
width: 100px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
border: 1px dashed #ddd;
border-radius: 10%;
cursor: pointer;
}
img {
width: 70px;
height: 70px;
filter: invert();
}
input {
display: none;
}
canvas {
display: none;
}
我们传递给JS。我们声明主要变量:let dropZone = document.querySelector("div"),
input = document.querySelector("input"),
file,
text,
progress,
volume,
audio,
frequencyArray;
我们使用拖放操作:
dropZone.ondrop = e => {
e.preventDefault();
if (e.dataTransfer.items[0].kind == "file") {
file = e.dataTransfer.items[0].getAsFile();
} else return;
playTrack(file);
};
dropZone.ondragover = e => {
e.preventDefault();
};
dropZone.onclick = () => {
input.click();
input.onchange = () => {
file = input.files[0];
playTrack(file);
};
};
我们继续前进。为画布声明变量:let C = document.querySelector("canvas"),
$ = C.getContext("2d"),
W = (C.width = innerWidth),
H = (C.height = innerHeight),
centerX = W / 2,
centerY = H / 2,
radius,
piece,
bars = 200,
x,
y,
xEnd,
yEnd,
barWidth = 2,
barHeight,
lineColor;
我们继续执行main函数(所有进一步的代码将在此函数中):function playTrack(file) {
}
我们删除区域(不再需要它),更改段落的文本,初始化声音和进度的变量:dropZone.style.display = "none";
text = document.querySelector("p");
text.style.transform = "translate(-50%,-50%)";
text.innerHTML = `progress: <span class="progress"></span> <br> volume: <span class="volume"></span>`;
volume = document.querySelector(".volume");
progress = document.querySelector(".progress");
令人联想到声音:audio = new Audio();
context = new AudioContext();
analyser = context.createAnalyser();
audio.src = URL.createObjectURL(file);
source = context.createMediaElementSource(audio);
source.connect(analyser);
analyser.connect(context.destination);
frequencyArray = new Uint8Array(analyser.frequencyBinCount);
audio.play();
audio.loop = true;
添加控制播放器的功能(我们没有按钮,因此您只能使用键盘来控制播放器):document.addEventListener("keydown", e => {
try {
e.preventDefault()
if (e.keyCode == 32) {
audio.paused ? audio.play() : audio.pause();
} else if (e.keyCode == 13) {
audio.load();
} else if (e.keyCode == 39) {
audio.currentTime += 10;
} else if (e.keyCode == 37) {
audio.currentTime -= 10;
} else if (e.keyCode == 40) {
audio.volume -= 0.1;
} else if (e.keyCode == 38) {
audio.volume += 0.1;
}
} catch {
return;
}
});
console.log(
" Use Keyboard: \n Space to Play/Pause \n Enter to Stop \n Arrows to Change \n Time and Volume"
);
下一部分是动画。我们调用相应的函数:startAnimation();
该函数本身如下:function startAnimation() {
C.style.display = "block";
piece = audio.currentTime / audio.duration;
radius = 105;
$.clearRect(0, 0, W, H);
$.beginPath();
$.arc(centerX, centerY, radius, 0, Math.PI * (2 * piece));
$.lineWidth = 30;
$.stroke();
volume.innerText = Math.trunc(audio.volume * 100) + "%";
progress.innerText = Math.trunc(piece * 100) + "%";
analyser.getByteFrequencyData(frequencyArray);
for (let i = 0; i < bars; i++) {
radius = 120;
rads = Math.PI * 2 / bars;
barHeight = frequencyArray[i] * 0.6;
x = centerX + Math.cos(rads * i) * radius;
y = centerY + Math.sin(rads * i) * radius;
xEnd = centerX + Math.cos(rads * i) * (radius + barHeight);
yEnd = centerY + Math.sin(rads * i) * (radius + barHeight);
drawBar(x, y, xEnd, yEnd, barWidth, frequencyArray[i]);
}
requestAnimationFrame(startAnimation);
}
最后-渲染列:
function drawBar(x1, y1, x2, y2, width, frequency) {
lineColor = "rgb(" + frequency + ", " + frequency + ", " + 205 + ")";
$.strokeStyle = lineColor;
$.lineWidth = width;
$.beginPath();
$.moveTo(x1, y1);
$.lineTo(x2, y2);
$.stroke();
}
结果可以在这里看到。感谢您的关注。