canvas-声音的处理和分析-用canvas制作一个彩色线条随音乐频率动态变化的效果

 index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="/audio/index.css">
</head>

<body>
  <canvas></canvas>
  <audio src="不为谁而作的歌.ogg" controls></audio>
  <script src="./index.js"></script>
</body>

</html>

index.css

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
body {
  overflow: hidden;
  background: #000;
}

audio {
  margin: 0 auto;
  position: absolute;
  left: 50%;
  bottom: 30px;
  transform: translateX(-50%);
}
canvas {
  display: block;
  margin: 0 auto;
  background: transparent;
}

index.js

const audioEle = document.querySelector('audio');
const cvs = document.querySelector('canvas');
const ctx = cvs.getContext('2d');

// 初始化canvas的尺寸
function initCvs() {
  const size = 500;
  cvs.width = size * devicePixelRatio;
  cvs.height = size * devicePixelRatio;
  cvs.style.width = cvs.style.height = size + 'px';
}
initCvs();
function draw(datas, maxValue) {
  const r = cvs.width / 4 + 20 * devicePixelRatio;
  const center = cvs.width / 2;
  ctx.clearRect(0, 0, cvs.width, cvs.height);

  const hslStep = 360 / (datas.length - 1);
  const maxLen = cvs.width / 2 - r;
  const minLen = 2 * devicePixelRatio;
  for (let i = 0; i < datas.length; i++) {
    ctx.beginPath();
    const len = Math.max((datas[i] / maxValue) * maxLen, minLen);
    const rotate = hslStep * i;
    ctx.strokeStyle = `hsl(${rotate}deg, 65%, 65%)`;
    ctx.lineWidth = minLen;
    const rad = (rotate * Math.PI) / 180;
    const beginX = center + Math.cos(rad) * r;
    const beginY = center + Math.sin(rad) * r;
    const endX = center + Math.cos(rad) * (r + len);
    const endY = center + Math.sin(rad) * (r + len);
    ctx.moveTo(beginX, beginY);
    ctx.lineTo(endX, endY);
    ctx.stroke();
  }
}

draw(new Array(256).fill(0), 255);

let isInit = false;
let analyser, buffer;
audioEle.onplay = function () {
  if (isInit) {
    return;
  }
  const audioCtx = new AudioContext();
  // 创建一个音频分析器节点
  analyser = audioCtx.createAnalyser();
  analyser.fftSize = 512;
  buffer = new Uint8Array(analyser.frequencyBinCount);

  const source = audioCtx.createMediaElementSource(audioEle);
  // 连接分析器
  source.connect(analyser);

  // 连接喇叭
  analyser.connect(audioCtx.destination);
  isInit = true;
};

function update() {
  requestAnimationFrame(update);
  if (!isInit) {
    return;
  }
  analyser.getByteFrequencyData(buffer);
  const offset = Math.floor((buffer.length * 2) / 3);
  const datas = new Array(offset * 2);
  for (let i = 0; i < offset; i++) {
    datas[i] = datas[datas.length - i - 1] = buffer[i];
  }
  draw(datas, 255);
}

update();

从喇叭接收声音使变化index.js

const audioEle = document.querySelector('audio');
const cvs = document.querySelector('canvas');
const ctx = cvs.getContext('2d');

// 初始化canvas的尺寸
function initCvs() {
  const size = 500;
  cvs.width = size * devicePixelRatio;
  cvs.height = size * devicePixelRatio;
  cvs.style.width = cvs.style.height = size + 'px';
}
initCvs();
function draw(datas, maxValue) {
  const r = cvs.width / 4 + 20 * devicePixelRatio;
  const center = cvs.width / 2;
  ctx.clearRect(0, 0, cvs.width, cvs.height);

  const hslStep = 360 / (datas.length - 1);
  const maxLen = cvs.width / 2 - r;
  const minLen = 2 * devicePixelRatio;
  for (let i = 0; i < datas.length; i++) {
    ctx.beginPath();
    const len = Math.max((datas[i] / maxValue) * maxLen, minLen);
    const rotate = hslStep * i;
    ctx.strokeStyle = `hsl(${rotate}deg, 65%, 65%)`;
    ctx.lineWidth = minLen;
    const rad = (rotate * Math.PI) / 180;
    const beginX = center + Math.cos(rad) * r;
    const beginY = center + Math.sin(rad) * r;
    const endX = center + Math.cos(rad) * (r + len);
    const endY = center + Math.sin(rad) * (r + len);
    ctx.moveTo(beginX, beginY);
    ctx.lineTo(endX, endY);
    ctx.stroke();
  }
}

draw(new Array(256).fill(0), 255);

let isInit = false;
let analyser, buffer;
navigator.mediaDevices.getUserMedia({ audio: true }).then((stream) => {
  if (isInit) {
    return;
  }
  const audioCtx = new AudioContext();
  // 创建一个音频分析器节点
  analyser = audioCtx.createAnalyser();
  analyser.fftSize = 512;
  buffer = new Uint8Array(analyser.frequencyBinCount);

  const source = audioCtx.createMediaStreamSource(stream);
  source.connect(analyser);

  // analyser.connect(audioCtx.destination);
  isInit = true;
});

function update() {
  requestAnimationFrame(update);
  if (!isInit) {
    return;
  }
  analyser.getByteFrequencyData(buffer);
  const offset = Math.floor((buffer.length * 2) / 3);
  const datas = new Array(offset * 2);
  for (let i = 0; i < offset; i++) {
    datas[i] = datas[datas.length - i - 1] = buffer[i];
  }
  draw(datas, 255);
}

update();

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值