CodeSoom / ddomal

실어증 환우 분들을 위한 말연습 어플리케이션입니다
https://www.ddomal.com
10 stars 2 forks source link

Audio API 의 이해 #136

Closed gringrape closed 3 years ago

gringrape commented 3 years ago

Sound data 의 이해

기본 아이디어

Analogue, Digital

결론

내가 보게되는 데이터

배열 데이터를 보게된다. 44100Hz sample rate 라면, 1초의 재생분량에 44100개의 원소를 가진 배열일 것이다. 거기다가 각 원소인 진폭은 bit depth 가 16 bit 라면 65536 개의 서로 다른 값을 가질 수 있을 것이다.

gringrape commented 3 years ago

API 구성

기본 생각

더 친해질 친구들

현재 친해지면 유용한 친구들

참고

See https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Basic_concepts_behind_Web_Audio_API

gringrape commented 3 years ago

데이터 시각화(볼륨)

https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API/Visualizations_with_Web_Audio_API

예제

https://mdn.github.io/voice-change-o-matic/ 위의 예제를 보면 이해가 쏙쏙된다. sine wave 는 뭐하는지 모르겠고 frequency bar 를 보면 x 축 진동수에 y 축 진폭인데, 모든 진동수에 대해서 평균값을 구하면 볼륨 메터로 쓰기에 딱 좋을 것 같다.

웨이브폼은 그냥 데이터를 파형으로 중첩시킨거아닐까?

흐름 구상

WebRTC media stream source -> Analyzer node -> frequency array -> average -> visualize

gringrape commented 3 years ago

예제 만들기

참고 - https://github.com/mdn/voice-change-o-matic/blob/gh-pages/scripts/app.js 오래되었지만 여전히 잘동작하는 예제가 있다.

예제 1. 마이크 입력을 받아서 볼륨을 화면에 숫자로 표시하기

마이크 소스를 스트림으로 얻어서 애널라이저를 연결해주고 애널라이저에서 진동수 진폭 데이터를 setInterval 로 주기적으로 꺼내주면 간단하게 해결된다.

구글의 autoplay 정책 때문에, 버튼을 하나만들어서 다음코드가 버튼이 클릭되면 실행되도록 해야 정상적으로 작동한다.

https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia

    function handleClick() {
      const constraints = {
      audio: true,
    }

    const context = new AudioContext();
    const analyser = context.createAnalyser();
    analyser.fftSize = 2048;

    navigator.mediaDevices.getUserMedia(constraints)
      .then((stream) => {
        const source = context.createMediaStreamSource(stream);
        source.connect(analyser);

        const bufferLength = analyser.frequencyBinCount;
        const dataArray = new Uint8Array(bufferLength); // 결과물

        setInterval(() => {
          analyser.getByteFrequencyData(dataArray);

          const sum = dataArray.reduce((acc, curr) => acc + curr, 0); 

          document.getElementById('volume').innerText = `mic volume: ${sum}`; 
        }, 100);
      });
    }

test4

gringrape commented 3 years ago

예제만들기 2 - 마이크 볼륨 미터

    function handleClick() {
        const constraints = {
        audio: true,
      }

      const context = new AudioContext();
      const analyser = context.createAnalyser();
      analyser.fftSize = 2048;

      navigator.mediaDevices.getUserMedia(constraints)
        .then((stream) => {
          const source = context.createMediaStreamSource(stream);
          source.connect(analyser);

          const bufferLength = analyser.frequencyBinCount;
          const dataArray = new Uint8Array(bufferLength); // 결과물

          const canvas = document.getElementById('canvas');
          const ctx = canvas.getContext('2d');

          function draw() {
            let color = 'green';

            analyser.getByteFrequencyData(dataArray);

            const sum = dataArray.reduce((acc, curr) => acc + curr, 0); 
            console.log(sum);

            if (sum > 30000) {
              color = 'red';
            }

            else if (sum > 20000) {
              color = 'yellow';
            }

            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.fillStyle = color;
            ctx.fillRect(10, 10, sum / 100, 100);

            requestAnimationFrame(draw);
          }

          draw();
        });
    }

test5

gringrape commented 3 years ago

시각화

Canvas + React

https://medium.com/@pdx.lucasm/canvas-with-react-js-32e133c05258

gringrape commented 3 years ago

적용 결과

온몸 비틀기는 효과적이다... test6