typescript를 사용하여 오디오 시각화 도구를 만듭니다

오디오 시각화 도구를 만드는 것이 줄곧 나의 꿈이었다.내가 winamp의 시각화 효과를 본 이후로최근에 나는 내가 다시 한 번 시도할 것이라고 생각한다.분명히 이것은 보기에 그렇게 어렵지 않다.네트워크 오디오 API는 어려운 부분을 단순화합니다.

우리는 결국 무엇을 건설할 것인가


Click here to see what the end result looks like

The entire source code can be found at https://github.com/BharatKalluri/bharatkalluri.com/blob/main/components/AudioVisualizer.tsx


네트워크 오디오 API


우리가 구축하고 있는 주파수 그래프라고 불린다.
시각화 중인 모든 프레임을 그릴 때, 우리는 당시 오디오의 주파수를 정수로 얻을 수 있다.우리는 이 정수를 사용하여 그림에 줄무늬를 그렸다.노래 신호에 대한 빠른 부립엽 변환 (FFT) 을 통해 주파수를 검색합니다.
이것이 바로 문제가 복잡해진 부분이다.푸리엽 변환은 가장 아름다운 수학 방정식 중의 하나다.하지만 나는 아직 충분한 직감으로 설명할 수 없다.아마도 어느 날, 그것을 눌렀을 때, 나는 명확한 문자를 가지고 있을 것이다.이제 그 요점은 복잡한 신호를 받아들여 더 간단한 신호로 분해하는 것이다.우리는 그 중에서 주파수를 추출할 수 있다.(이것이 바로 나의 이해이다. 나는 여기서 100% 정확하지 않을 수도 있다.
우리는 어떻게 이런 주파수를 얻습니까?웹 오디오 API에는 analyzer라는 유틸리티가 있습니다.분석기에서 우리는 주파수 데이터를 얻을 수 있다.FFT (빠른 부립엽 변환) 의 크기를 설정한 다음 주파수를 되돌려야 합니다.따라서 FFT 크기가 1024로 설정되면 주파수를 나타내는 1024개의 숫자 그룹을 얻을 수 있습니다.이곳의 조건 중 하나는 그것이 반드시 32에서 32768 사이의 2의 멱이어야 한다는 것이다.
이해해야 할 또 다른 개념은 웹오디오가 노드 방면에서 작용한다는 것이다.이 단독 노드들은 하나의 그림을 형성하고 이 그림을 집행한다.예를 들어, 웹 audio API에는 이득 노드라는 노드가 있습니다.만약 우리가 이득치를 1로 설정한다면, 이것은 그것의 소리가 가장 크다는 것을 의미한다.0은 침묵을 의미한다.미디어 요소를 만들고 버프 노드를 이 요소에 연결할 수 있습니다.그리고 버프 노드가 목적지(즉 스피커)에 연결됩니다.따라서 프로그램이 실행될 때, 오디오는 목적지에 도착하기 전에 모든 노드를 통과한다.
분석기도 하나의 노드다.이런 방법의 장점 중 하나는 한 노드에 여러 개의 하위 노드가 있을 수 있다는 것이다.하나의 미디어 요소는 목적지와 분석기를 동시에 연결할 수 있다.이것은 소화해야 할 중요한 사상이다.

실제 가시화는 결코 어렵지 않다.모든 값이 캔버스에 사각형으로 그려지고 색상이 표시됩니다.이렇게여기서 주의해야 할 기능 중 하나는 requestAnimationFrame 입니다.이 방법은 브라우저에 애니메이션을 실행하고 싶은 것을 알려주고 지정한 함수를 호출해 달라고 요청합니다.일반적으로 이것은 모니터의 주사율과 일치한다.

인코딩해 봅시다!


현재 이 이론은 이미 시대에 뒤떨어졌다.먼저 HTML로 원하는 내용을 설명하는 템플릿을 만듭니다.
<input
    type="file"
    id="audioPicker"
    accept="audio/*"
/>
<audio>No support for audio</audio>
<canvas
    id="canvas"
></canvas>
오디오 파일을 선택할 수 있는 간단한 입력오디오 라벨은 실제 오디오를 재생하는 데 사용되고, 주파수 그래프를 그리는 데 사용됩니다.이제 타자 원고 부분으로 넘어갑시다.
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
const audioElement = document.getElementById("audio");
const audioPickerElement = document.getElementById("audioPicker");
const canvasElement = document.getElementById(
    "canvas"
) as HTMLCanvasElement;
canvasElement.width = window.innerWidth;
canvasElement.height = window.innerHeight;
const canvasCtx = canvasElement.getContext("2d");
몇몇 기본적인 성명은 우리가 먼저 얻었다AudioContext.이 인터페이스는 서로 다른 노드에서 구축된 오디오 프로세서를 표시합니다.그리고 우리는 getElementByIdaudioElement, audioPickerElement과 canvasElement을 가져옵니다.우리는 곧 그것들을 변이시킬 것이다.그리고 우리는 화포의 높이와 너비를 설정한다.마지막으로 화포의 상하문을 얻으면 우리는 그것으로 화포에 그림을 그릴 수 있다.
audioPickerElement.onchange = function () {
    // @ts-ignore
    const files = this.files;
    audioElement.src = URL.createObjectURL(files[0]);
    audioElement.load();
    audioElement.play();
}
간단하게 파일 변경을 시작합니다.첫 번째 파일을 검색하고 오디오 요소의 원본으로 설정합니다.그런 다음 audioElement을 로드하고 재생합니다.이 점에서, 너는 노래 한 곡을 선택하고, 여기에서 오디오를 재생할 수 있어야 한다.이제 웹오디오를 봅시다.
// ...from now the code you see here is a part of the onchange function of audiopicker in the above example
const track = audioContext.createMediaElementSource(
    audioElement
);
track.connect(audioContext.destination);

// Analyzer node
const analyser = audioContext.createAnalyser();
analyser.fftSize = 128;
track.connect(analyser);
이것은 도형 구조다.도표의 기본 요소는 createMediaElementSource인데 이것은 실제 오디오 원본이다.한쪽 목적지(오디오 출력/스피커)와 분석기를 연결합니다.이것은 앞의 삽화와 같다.간단하게 보기 위해서 우리는 이득 노드를 뛰어넘었다.analyzer 노드는 실시간 주파수와 시간 분석을 제공할 수 있습니다.잠시 후 주파수 데이터를 가져와야 합니다.FFT 크기가 128로 설정되어 있기 때문에 128개의 값만 얻을 수 있습니다. 우리는 이 값을 그릴 수 있습니다.너무 많은 값은 철근이 얇아진다는 것을 의미한다.
// Creating the array to store the frequency data
const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
여기서부터 모든 주파수 데이터를 저장하기 위해 Uint8Array 중의 fftSize를 만들어야 한다. 이 데이터는 계속 흐를 것이다.
// Some useful constants
const WIDTH = canvasElement.width;
const HEIGHT = canvasElement.height;
const barWidth = (WIDTH / bufferLength) * 2.5;
let barHeight;
let x = 0;

// Colors used for plotting
const MATTE_BLACK = "#1A202C";
const WHITE = "#FFFFFF";

// The function which will get called on each repaint
function draw() {
    requestAnimationFrame(draw);
    if (canvasCtx !== null) {
        x = 0;
        analyser.getByteFrequencyData(dataArray);
        canvasCtx.fillStyle = WHITE;
        canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
        for (let i = 0; i < bufferLength; i++) {
            barHeight = dataArray[i];
            canvasCtx.fillStyle = MATTE_BLACK;
            canvasCtx.fillRect(x, 0, barWidth, barHeight);
            x += barWidth + 3;
        }
    }
}
draw();
너비, 높이, 스트라이프 너비 (너비 곱하기 2.5는 스트라이프를 더 커 보이게 하기 위해서일 뿐, 사용하지 않으려면 2.5도 우리가 왜 이러는지 보자) 와 일부 색깔은 편의를 위해 정의된 것이다.이제 중요한 부분을 살펴보자.draw 함수는 실제 화포를 그리는 함수입니다.매번 호출할 때마다, 우리는 초당draw 함수를 약 60회 (60헤르츠 디스플레이가 있다면), 입력과 같은 함수 호출 requestAnimationFrame 을 사용합니다.기억해라, 이 모든 것은 비동기적으로 발생한 것이다.
함수 내부에서 우리는 x=0부터 시작하여 화포에서 (0,0)이다.그리고 우리는 분석기의 getByteFrequencyData 함수를 사용하여 주파수 데이터를 앞에서 설명한 dataArray에 채웁니다.실제 채워진 내용을 알아보기 위해 데이터 그룹을 살펴보는 것을 권장합니다. (주의: 이 동작을 실행할 때 노래 한 곡을 불러오고, draw 함수에 컨트롤러 로그가 있으면, 128 크기의 거대한 그룹은 초당 30회 이상 컨트롤러에 기록되며, 브라우저가 붕괴되거나 속도가 느려집니다.)
현재 데이터가 그룹에 있습니다. 캔버스 배경을 흰색으로 설정하십시오.배열의 각 요소에 사각형을 그립니다.좌표는 (x, y, width, height) => (0, 0,barWidth,barHeight)에서 시작합니다.MATTE_BLACK로 이 직사각형을 채우고 x를 증가barWidth + 3합니다.가령 스트라이프의 폭이 50px라고 가정하면 두 번째 사각형은 다음과 같은 좌표(53, 0, 스트라이프의 폭, 스트라이프의 높이)를 가지게 된다.수조의 모든 원소는 이렇다.이것이 바로 프레임을 그리는 방식이다.
이것은 1초에 >30번(모니터 주사율 기준)을 반복하여 부드럽고 연속적인 이동 그래픽임을 느끼게 합니다.🤯

The entire source code can be found at https://github.com/BharatKalluri/bharatkalluri.com/blob/main/components/AudioVisualizer.tsx


우리는 단지 표면에 닿았을 뿐, 매우 좋은 시각 효과가 많다.This is one of my favorites .
본 논문의 영감은 MDN의 visualizations with the Web Audio API에 관한 문장에서 나왔다.

좋은 웹페이지 즐겨찾기