Web front-end audio visualization, typed array, hexadecimal random color, devicePixelRatio, AudioContext, createMediaElementSource, createAnalyser

Article directory


Preface

Get the source code for free in private chat: MJ682517
1. The audio must be correct. There is no sound when playing network audio. Only local audio can be
played. 2. The kgma format audio downloaded by Kugou is not supported.
3. I have tried the local mp3 format and it can be played normally.
4. Code Analysis is all in the code


renderings

512
web_audioVisualization_512


1024
web_audioVisualization_1024


html

<body class="bc_333">
  <div class="box d_f fd_c jc_c">
      <canvas></canvas>
      <hr class="w_100_ bc_dcdcdc h_1 b_n" />
      <audio class="w_86_ m_a" controls loop src="./1.mp3"></audio>
      <div class="m_t_10">
          <div id="idIntervalBtn" class="w_50_ m_lr_a d_f jc_sb"></div>
          <div id="idClothCoverBtn" class="w_50_ m_lr_a d_f jc_sb m_t_10"></div>
      </div>
  </div>
</body>

JavaScript

// 全局变量
let audioEle = document.querySelector('audio'),
    cvs = document.querySelector('canvas'),
    ctx = cvs.getContext('2d'),
    // 控制初始化
    isInit = false,
    dataArray = undefined,
    analyser = undefined,
    animation = undefined,
    // 按钮操作
    interval = 2,
    // 条形粗细
    clothCover = 1024;

// 初始化页面
initPage();
function initPage() {
    
    
    let intervalEl = '',
        clothCoverEl = '';

    for (let i = 2; i < 9; i++) intervalEl += `<button class="c_p w_68 radius_6 fw_700 ${
      
      interval === i ? 'color_blue' : ''}" οnclick="handleInterval(event, ${
      
      i})">${
      
      i}</button>`;

    for (let i = 9; i < 12; i++) {
    
    
        let val = 2 ** i;

        clothCoverEl += `<button class="c_p w_68 radius_6 fw_700 ${
      
      clothCover === val ? 'color_blue' : ''}" οnclick="handleClothCover(${
      
      val})">${
      
      val}</button>`;
    }

    idIntervalBtn.innerHTML = intervalEl;
    idClothCoverBtn.innerHTML = clothCoverEl;
}

// 初花canvas的尺寸
initCvs();
function initCvs() {
    
    
    cvs.width = window.innerWidth * devicePixelRatio;
    cvs.height = (window.innerHeight / 1.5) * devicePixelRatio;
}

// 播放
audioEle.onplay = handlePlay;

function handlePlay() {
    
    
    if (isInit) {
    
    
        analyser.fftSize = clothCover;

        return draw();
    }

    // 初始化
    // 创建音频上下文
    let audCtx = new AudioContext(),
        // 创建音频源节点
        source = audCtx.createMediaElementSource(audioEle);

    // 分析器节点
    analyser = audCtx.createAnalyser();
    // 设置变换窗口大小
    // 默认值为2048,必须是2的n次幂
    // 数值越大,则得到的值与音频频率更接近
    analyser.fftSize = clothCover;
    // 创建数组,用于接收分析器节点的分析数据
    // 类型化数组
    // 每一项代表一个字节
    // 表示数组里面的每一项是一个无符号的8位整数
    // new Uint8Array(512 / 2);
    // frequencyBinCount属性会自动把值除以2
    dataArray = new Uint8Array(analyser.frequencyBinCount);
    // 音频源与分析器连接
    source.connect(analyser);
    // 分析器连接到输出设备(输出声音)
    analyser.connect(audCtx.destination);
    isInit = true;
    draw();
}

// 暂停
audioEle.onpause = function () {
    
    
    cancelAnimationFrame(animation);
}

// 把分析出的波形绘制到canvas
function draw() {
    
    
    // 类似递归(循环绘制)
    animation = requestAnimationFrame(draw);
    let {
    
     width, height } = cvs,
        len = 0,
        barWidth = 0,
        gradient = undefined;

    // 清空画布
    ctx.clearRect(0, 0, width, height);
    if (!isInit) return console.log('未初始化!');
    // 让分析器节点分析出数据到数组中
    analyser.getByteFrequencyData(dataArray);

    len = dataArray.length / 2.5;
    barWidth = width / len / 2;
    // ctx.fillStyle = '#78c5f7';
    // 创建线性渐变对象(横向渐变)
    gradient = ctx.createLinearGradient(0, 0, width, 0);
    // 添加渐变色段
    gradient.addColorStop(0, hexadecimalColor());
    gradient.addColorStop(0.5, hexadecimalColor());
    gradient.addColorStop(1, hexadecimalColor());

    ctx.fillStyle = gradient;

    for (let i = 0; i < len; i++) {
    
    
        let data = dataArray[i],
            barHeight = data / 255 * height,
            // / 2 波形图取一半
            x1 = i * barWidth + width / 2,
            // 波形图另一半
            x2 = width / 2 - (i + 1) * barWidth,
            // x1和x2为对称图形
            // 只是x轴坐标不同
            // y轴一样
            y = height - barHeight;

        // - 2 让每个条之间有缝隙

        // 右半边
        ctx.fillRect(x1, y, barWidth - interval, barHeight);
        //  左半边
        ctx.fillRect(x2, y, barWidth - interval, barHeight);
    }
}

// 随机十六进制颜色
function hexadecimalColor() {
    
    
    let str = '0123456789abcdef',
        len = str.length,
        shuffleArray = undefined,
        arr = [],
        color = '#';

    str = str.split('');
    shuffleArray = (arr) => arr.sort(() => Math.random() - 0.5);
    arr = shuffleArray(str);
    str = arr.toString();
    str = str.replace(/,/g, '');

    for (let i = 0; i < 6; i++) {
    
    
        let j = Math.floor(Math.random() * len);
        color += str[j];
    }

    return color;
}

// 间隔设置
function handleInterval(event, value) {
    
    
    let el = document.querySelector('#idIntervalBtn').childNodes;

    for (let i = 0; i < el.length; i++) {
    
    
        const val = el[i].textContent;
        if (value == val) {
    
    
            event.target.classList.add('color_blue');
        } else {
    
    
            el[i].classList.remove('color_blue');
        }
    }
    interval = value;
}

// 条形粗细
function handleClothCover(value) {
    
    
    let el = document.querySelector('#idClothCoverBtn').childNodes;

    for (let i = 0; i < el.length; i++) {
    
    
        const val = el[i].textContent;
        if (value == val) {
    
    
            event.target.classList.add('color_blue');
        } else {
    
    
            el[i].classList.remove('color_blue');
        }
    }

    clothCover = value;

    handlePlay();
}

css

.bc_333 {
    
    
    background-color: #333333;
}

.bc_dcdcdc {
    
    
    background-color: #dcdcdc;
}

.h_1 {
    
    
    height: 1px;
}

.b_n {
    
    
    border: none;
}

.c_p {
    
    
    cursor: pointer;
}

.w_50_ {
    
    
    width: 50%;
}

.w_86_ {
    
    
    width: 86%;
}

.w_100_ {
    
    
    width: 100%;
}

.d_f {
    
    
    display: flex;
}

.fd_c {
    
    
    flex-direction: column;
}

.jc_sb {
    
    
    justify-content: space-between;
}

.jc_c {
    
    
    justify-content: center;
}

.m_a {
    
    
    margin: auto;
}

.m_lr_a {
    
    
    margin-left: auto;
    margin-right: auto;
}

.m_t_10 {
    
    
    margin-top: 10px;
}

.w_68 {
    
    
    width: 68px;
}

.radius_4 {
    
    
    border-radius: 4;
}

.radius_6 {
    
    
    border-radius: 6;
}

.color_blue {
    
    
    color: #0000ff;
}

.fw_700 {
    
    
    font-weight: 700;
}

Guess you like

Origin blog.csdn.net/weixin_51157081/article/details/132867718