React에서 Web Audio API 사용하여 mp3 파일 재생하기

solda-blue·2023년 4월 17일
0

Intro

음정이나 코드를 들려주고 맞추는 간단한 청음프로그램을 만들려고 했는데 처음엔 그냥 아무것도 모르고 HTML의 audio 태그를 이용해서 로컬에 있는 mp3파일을 note들로 사용했었는데 데스크탑 브라우저 환경에서는 별 무리없이 동작하였으나 모바일로 테스트 해본 결과 코드는 싱크가 밀린다던가 음정 같은 경우는 아예 첫음이 들리지 않는 등 문제가 많아서 구글링을 해본 결과 Web Audio API라고 audio파일을 전문적으로 다루는 자바스크립트 기술이 있었다.

그래서 기존의 음원 재생 방법을 Firebase Storage에 음원을 올려두고 거기서 http로 가져와서 Web Audio API를 통해서 재생하는 걸로 바꾸는 작업을 하였다.

Firebase Storage에 음원 업로드하고 url 가져오기

Firebase는 이번에 처음 써봤는데 직관적이고 깔끔하게 잘 되어 있는 것 같다. 프로젝트를 시작하고 스토리지에 파일 등록하는 건 간단하니 넘어가고 http 요청을 위해서 cors 설정을 해주어야 한다

https://console.cloud.google.com/

FB 콘솔이 아니라 구글 클라우드 플랫폼 콘솔로 가야 한다.

cors 설정은 이분의 포스트를 참고 했다

https://stove99.github.io/etc/2021/06/09/firebase-storage-cors-setting/

그 뒤 파일들을 업로드 해주고 url 주소를 가져와야 하는데 오른쪽 아래에 엑세스 토큰 부분을 클릭하면 get 요청을 날렸을 때 재생이 가능한 전체 url 주소를 복사할 수 있다.

그렇게 복사한 주소와 note에 관한 정보를 json형식으로 저장했다.

Web Audio API를 활용해서 가져온 음원 재생하기

어제 밤에 너무 늦게 자서 피곤한 관계로 일단 그냥 전체 코드를 통으로 올리고 나중에 시간되면 수정하기로...

코드가 길어서 그렇지 생각보다 별거 없다 AudioContext 인스턴스 만들고 버퍼에 음원들 가져와서 디코딩하고 다시 플레이 버튼 눌렀을 때 담아둔 음원들을 버퍼소스 노드에 집어넣고 AudioContext에 connect해서 순차적으로 재생해주면 됨

import axios from "axios";
import React, { useEffect, useState } from "react";

const Answer1 = (props) => {
    const exChord = props.exChord;
    const [audios, setAudios] = useState([]);

    useEffect(() => {
        const fetchAudio = async () => {
            const audioContext = new (window.AudioContext || window.webkitAudioContext)();
            const buffers = [];
            for(let i = 0; i < exChord.length; i++) {
                const res = await axios({
                    method : "get",
                    url : exChord[i].url,
                    responseType : "arraybuffer"
                });
                const buffer = await audioContext.decodeAudioData(res.data);
                buffers.push(buffer);
            };
            setAudios(buffers);
        };
        fetchAudio();
    },[exChord]);

    useEffect(() => {
        const play = () => {
            console.log(audios);
            const audioContext = new (window.AudioContext || window.webkitAudioContext)();
            audios.forEach((audio) => {
                const source = audioContext.createBufferSource();
                source.buffer = audio;
                source.connect(audioContext.destination);
                source.start(0);
            })
        }
        if (audios.length > 0) {
            play();
        }
    }, [audios])

    return (
        <div>
            <h6>answer</h6>

            <button onClick={() => setAudios([...audios])}>재생</button>
        </div>
    )
}

export default Answer1;

0개의 댓글