vue-waveform
Version:
waveform audio player wavesurfer -waveform js html 音频audio波形图
148 lines (135 loc) • 7.21 kB
HTML
<html>
<head>
<meta charset="utf8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, maximum-scale=2.0 initial-scale=1.0, user-scalable=yes">
<meta name="keywords" content="acoustic wave propagation">
<meta name="description" content="声波传播,能量不断衰减,从而导致振幅先增大后减小,最终归零">
<title>声波传播(acoustic wave propagation)</title>
<style>
body {
color: white;
background-color: #333;
font-size: 16px;
}
controlDiv {
margin: 40px auto;
}
label {
/* 变为block之后后面的元素才会换行排列 */
display: block;
}
input[type=range] {
display: block;
}
#canvas {
display: block;
margin: 0 auto;
}
</style>
</head>
<body>
<div id="controlDiv">
<label id="attenuationCoefficientLabel">衰减系数: 2</label>
<label>(越大, 边缘衰减的就越多, 震动宽度相应也越窄)</label>
<input id="attenuationCoefficientRange" type="range" min="1" max="10" step="1" value="2"/>
<label id="halfWaveCountLabel">半波长个数-1: 3</label>
<input id="halfWaveCountRange" type="range" min="0" max="10" step="1" value="3"/>
<label id="amplitudePercentageLabel">振幅: 3%</label>
<input id="amplitudePercentageRange" type="range" min="0" max="100" step="1" value="90"/>
<label id="radianStepLabel">角速度: 0.05</label>
<label>(速度开始从右到左,先加快后减慢,最后变成左到右)</label>
<input id="radianStepRange" type="range" min="0" max="3.15" step="0.01" value="0.05"/>
</div>
<canvas id="canvas">Your browser can not support canvas</canvas>
<script>
var doublePI = Math.PI * 2;
var canvas;
var ctx;
//画布的高度的一半
var halfCanvasHeight = 100;
//水平边距
var horizontalMargin = 150;
//衰减系数(越大, 边缘衰减的就越多, 震动宽度相应也越窄)
var attenuationCoefficient = 2;
//半波长个数-1
var halfWaveCount = 3;
//振幅是画布高度的一般的百分比[0,1]
var amplitudePercentage = 0.9;
//每帧增加的弧度[0,2PI](作用于sin曲线, 正值相当于原点右移, 曲线左移)
var radianStep = 0.05;
//当前弧度的偏移
var radianOffset = 0;
//画布宽度
var canvasWidth;
function init() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
var attenuationCoefficientLabel = document.getElementById("attenuationCoefficientLabel");
var attenuationCoefficientRange = document.getElementById("attenuationCoefficientRange");
var halfWaveCountLabel = document.getElementById("halfWaveCountLabel");
var halfWaveCountRange = document.getElementById("halfWaveCountRange");
var amplitudePercentageRangeLabel = document.getElementById("amplitudePercentageRangeLabel");
var amplitudePercentageRangeRange = document.getElementById("amplitudePercentageRangeRange");
var radianStepLabel = document.getElementById("radianStepLabel");
var radianStepRange = document.getElementById("radianStepRange");
attenuationCoefficientRange.addEventListener("change", function() {
attenuationCoefficient = parseInt(event.target.value);
attenuationCoefficientLabel.innerHTML = "衰减系数AC: " + attenuationCoefficient;
});
halfWaveCountRange.addEventListener("change", function() {
halfWaveCount = parseInt(event.target.value);
halfWaveCountLabel.innerHTML = "半波长个数-1: " + halfWaveCount;
});
amplitudePercentageRange.addEventListener("change", function() {
amplitudePercentage = parseInt(event.target.value) / 100;
amplitudePercentageLabel.innerHTML = "振幅: " + event.target.value + "%";
});
radianStepRange.addEventListener("change", function() {
radianStep = parseFloat(event.target.value);
radianStepLabel.innerHTML = "角速度: " + radianStep;
});
window.addEventListener("resize", onResize);
canvas.height = halfCanvasHeight * 2;
onResize();
loop();
}
function onResize() {
//元素的大小不能加单位, 单位默认就是像素, 而style中的长度要加单位
canvasWidth = canvas.width = window.innerWidth - horizontalMargin;
}
//设K=attenuationCoefficient, 计算信号衰减 (4K/(4K+x^4))^2K<=1 (x belong [-K,K])
function calcAttenuation(x) {
return Math.pow(4 * attenuationCoefficient / (4 * attenuationCoefficient + Math.pow(x, 4)), 2 * attenuationCoefficient);
}
//heightPercentage为振幅的显示比例
function drawAcousticWave(heightPercentage, alpha, lineWidth) {
ctx.strokeStyle = "white";
ctx.globalAlpha = alpha;
ctx.lineWidth = lineWidth || 1;
ctx.beginPath();
ctx.moveTo(0, halfCanvasHeight);
var x,y;
for(var i=-attenuationCoefficient; i<=attenuationCoefficient; i+=0.01) {
//i是当前位置相对于整个长度的比率( x=width*(i+K)/(2*K))
x = canvasWidth * (i + attenuationCoefficient) / (2 * attenuationCoefficient);
//加offset相当于把sin曲线向右平移
y = halfCanvasHeight + halfCanvasHeight * amplitudePercentage * calcAttenuation(i) * heightPercentage * Math.sin(halfWaveCount * i + radianOffset);
ctx.lineTo(x, y);
}
ctx.stroke();
}
function loop() {
radianOffset = (radianOffset + radianStep) % doublePI;
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawAcousticWave(1, 1, 2);
for(var i=2; i<4; i++) {
var reciprocal = 1 / i;
drawAcousticWave(reciprocal, reciprocal/2);
drawAcousticWave(-reciprocal, reciprocal/2);
}
requestAnimationFrame(loop);
}
init();
</script>
</body>
</html>