JS—音频处理(傅里叶变换)

JS—音频处理

实现效果

在这里插入图片描述

思路:主要通过 canvas进行绘画

1.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>音频可视化</title>
    <link rel="stylesheet" href="./code.css">
</head>

<body>
    <canvas id="canvas"></canvas>
    <audio id="audio" src="./千千阙歌.mp3" controls></audio>
    <script src="./code.js"></script>
</body>

</html>
2.css
* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}

body {
    width: 100%;
    height: 100vh;
    background-color: rgb(0, 0, 0);
}

#canvas {
    display: block;
    width: 100%;
    height: 600px;
    border-bottom: 2px solid #fff;
}

#audio {
    display: block;
    margin: 0 auto;
    margin-top: 30px;
}
3.js

思路:通过对音频节点的处理,并通过傅里叶变换 来进行转换

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

// 初始化
let isInt = false;
let dataArray, analyser;
audioFile.onplay = () => {
    if (isInt) { return };
    const audCtx = new AudioContext(); //创建音频上下文,类似于建立一个房子
    const source = audCtx.createMediaElementSource(audioFile); // 创建音频节点
    analyser = audCtx.createAnalyser(); //对音频进行分析
    analyser.fftSize = 512 // 变换的窗口大小;默认2的几次方
    dataArray = new Uint8Array(analyser.frequencyBinCount); //代表数字里的每一项都是字节,长度为 快速傅里叶变换的图是对称的

    source.connect(analyser);
    analyser.connect(audCtx.destination); //将所有的节点连接起来

    // 初始化

    isInt = true; // 已初始化
}

// 将画出的波形绘制到 canvas
function draw() {
    requestAnimationFrame(draw); // 理解为不断的递归
    // 1.清空画布
    const { width, height } = cvs;
    ctx.clearRect(0, 0, width, height)
        // 如果没有初始化,则不渲染
    if (!isInt) { return };
    analyser.getByteFrequencyData(dataArray); //将分析出来的数据装订到数组中去
    // console.log(dataArray);
    // 拿到每一处理完音频的数据,因为低频太少,所有利用长度的方式给它增加视觉效果
    const len = dataArray.length / 2.5;
    const barWidth = width / len / 2; // 每一条柱状图的长度,除以2是为了让左右对称的图给画出来
    ctx.fillStyle = "skyblue";
    for (let index = 0; index < len; index++) {
        const element = dataArray[index]; // 字符的长度是小于256的
        const barHeight = element / 255 * height; // 用画布的同比例去获取
        const x1 = index * barWidth + width / 2;
        const x2 = width / 2 - (index + 1) * barWidth;
        const y = height - barHeight
        ctx.fillRect(x1, y, barWidth - 2, barHeight);
        ctx.fillRect(x2, y, barWidth - 2, barHeight);
    }
}

draw()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Record sounds / noises around you and turn them into music. It’s a work in progress, at the moment it enables you to record live audio straight from your browser, edit it and save these sounds as a WAV file. There's also a sequencer part where you can create small loops using these sounds with a drone synth overlaid on them. See it working: http://daaain.github.com/JSSoundRecorder Technology ---------- No servers involved, only Web Audio API with binary sound Blobs passed around! ### Web Audio API #### GetUserMedia audio for live recording Experimental API to record any system audio input (including USB soundcards, musical instruments, etc). ```javascript // shim and create AudioContext window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext; var audio_context = new AudioContext(); // shim and start GetUserMedia audio stream navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia; navigator.getUserMedia({audio: true}, startUserMedia, function(e) { console.log('No live audio input: ' + e); }); ``` #### Audio nodes for routing You can route audio stream around, with input nodes (microphone, synths, etc), filters (volume / gain, equaliser, low pass, etc) and outputs (speakers, binary streams, etc). ```javascript function startUserMedia(stream) { // create MediaStreamSource and GainNode var input = audio_context.createMediaStreamSource(stream); var volume = audio_context.createGain(); volume.gain.value = 0.7; // connect them and pipe output input.connect(volume); volume.connect(audio_context.destination); // connect recorder as well - see below var recorder = new Recorder(input); } ``` ### WebWorker Processing (interleaving) record buffer is done in the background to not block the main thread and the UI. Also WAV conversion for export is also quite heavy for longer recordings, so best left to run in the background. ```javascript this.context = input.context; this.node = this.context.createScriptProcessor(4096, 2, 2); this.node.onaudioprocess = function(e){ worker.postMessage({ command: 'record', buffer: [ e.inputBuffer.getChannelData(0), e.inputBuffer.getChannelData(1) ] }); } ``` ```javascript function record(inputBuffer){ var bufferL = inputBuffer[0]; var bufferR = inputBuffer[1]; var interleaved = interleave(bufferL, bufferR); recBuffers.push(interleaved); recLength += interleaved.length; } function interleave(inputL, inputR){ var length = inputL.length + inputR.length; var result = new Float32Array(length); var index = 0, inputIndex = 0; while (index < length){ result[index++] = inputL[inputIndex]; result[index++] = inputR[inputIndex]; inputIndex++; } return result; } ``` ```javascript function encodeWAV(samples){ var buffer = new ArrayBuffer(44 + samples.length * 2); var view = new DataView(buffer); /* RIFF identifier */ writeString(view, 0, 'RIFF'); /* file length */ view.setUint32(4, 32 + samples.length * 2, true); /* RIFF type */ writeString(view, 8, 'WAVE'); /* format chunk identifier */ writeString(view, 12, 'fmt '); /* format chunk length */ view.setUint32(16, 16, true); /* sample format (raw) */ view.setUint16(20, 1, true); /* channel count */ view.setUint16(22, 2, true); /* sample rate */ view.setUint32(24, sampleRate, true); /* byte rate (sample rate * block align) */ view.setUint32(28, sampleRate * 4, true); /* block align (channel count * bytes per sample) */ view.setUint16(32, 4, true); /* bits per sample */ view.setUint16(34, 16, true); /* data chunk identifier */ writeString(view, 36, 'data'); /* data chunk length */ view.setUint32(40, samples.length * 2, true); floatTo16BitPCM(view, 44, samples); return view; } ``` ### Binary Blob Instead of file drag and drop interface this binary blob is passed to editor. Note: BlobBuilder deprecated (but a lot of examples use it), you should use Blob constructor instead! ```javascript var f = new FileReader(); f. { audio_context.decodeAudioData(e.target.result, function(buffer) { $('#audioLayerControl')[0].handleAudio(buffer); }, function(e) { console.warn(e); }); }; f.readAsArrayBuffer(blob); ``` ```javascript function exportWAV(type){ var buffer = mergeBuffers(recBuffers, recLength); var dataview = encodeWAV(buffer); var audioBlob = new Blob([dataview], { type: type }); this.postMessage(audioBlob); } ``` ### Virtual File – URL.createObjectURL You can create file download link pointing to WAV blob, but also set it as the source of an Audio element. ```javascript var url = URL.createObjectURL(blob); var audioElement = document.createElement('audio'); var downloadAnchor = document.createElement('a'); audioElement.controls = true; audioElement.src = url; downloadAnchor.href = url; ``` TODO ---- * Sequencer top / status row should be radio buttons :) * Code cleanup / restructuring * Enable open / drag and drop files for editing * Visual feedback (levels) for live recording * Sequencer UI (and separation to a different module) Credits / license ----------------- Live recording code adapted from: http://www.phpied.com/files/webaudio/record.html Editor code adapted from: https://github.com/plucked/html5-audio-editor Copyright (c) 2012 Daniel Demmel MIT License

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值