본문 바로가기
  • ANALOG CODE
  • AnalogCode
개발(인터렉티브)

브라우저에서 마이크 입력 파형 보기

by 아날로그코더 2023. 4. 8.
반응형

재미삼아 브라우저에서 마이크 입력을 받아서 파형을 그려주는 페이지를 만들어보았다. 

마이크 접근을 허용하였다면 아래에 내 마이크 소리의 파형이 보인다.

 

 

 

 

 

코드 분석

1. 마이크 입력 스트림 획득

async function getMedia() {
  try {
    stream = await navigator.mediaDevices.getUserMedia({audio: true})
    createAudio()
    draw()
  } catch (err) {
    alert('UserMedia 접근 실패')
  }
}

getUserMedia() 를 호출하여 마이크 접근 권한을 획득하고 마이크 입력 스트림을 가져온다.

 

2. AudioContext 및 AnalyzerNode 생성

function createAudio() {
    audioCtx = new (window.AudioContext || window.webkitAudioContext)()
    analyser = audioCtx.createAnalyser()
    var source = audioCtx.createMediaStreamSource(stream)
    source.connect(analyser)

    analyser.fftSize = 2048
    bufferLength = analyser.frequencyBinCount
    audioDataArray = new Uint8Array(bufferLength)
}

AudioContext 

Web Audio를 사용하기 위해 가장먼저 필요한 객체이다. 노드의 생성과 오디오 프로세싱, 디코딩을 제어한다.

 

AnalyserNode

실시간 주파수와 시간 영역 분석 정보를 제공 가능한 노드.

AudioContext의 createAnalyser() 메소드를 통해 생성한다.

 

마이크 입력 스트림 소스 

마이크 입력 스트림 소스를 생성하고 AnalyserNode에 연결한다.

출력으로의 연결은 필요없다. 마이크 입력을 받아서 파형만 그리고 스피커로는 출력을 안할 것이기 때문이다.

var source = audioCtx.createMediaStreamSource(stream)
source.connect(analyser)

 

파형 데이터를 저장할 버퍼 생성

고정된 크기의 버퍼를 미리 생성해두고 나중에 실시간으로 파형 데이터를 버퍼로 가져와서 그릴것이다.

analyser.fftSize = 2048
bufferLength = analyser.frequencyBinCount
audioDataArray = new Uint8Array(bufferLength)

audioDataArray에 파형 데이터를 가져올 것이다.

 

3. 파형 데이터 그리기

HTML Canvas를 이용하여 파형 데이터를 그린다.

function draw() {
  // 파형 데이터 가져오기
  analyser.getByteTimeDomainData(audioDataArray)
  
  // 캔버스 초기화
  canvasCtx.fillStyle = 'rgb(0, 0, 0)'
  canvasCtx.fillRect(0, 0, canvas.width, canvas.height)

  // 파형 Line 그리기
  canvasCtx.lineWidth = 2
  canvasCtx.strokeStyle = 'rgb(255, 0, 0)'
  canvasCtx.beginPath()
  var sliceWidth = canvas.width * 1.0 / bufferLength
  var x = 0
  for(var i = 0; i < bufferLength; i++) {
    var v = audioDataArray[i] / 128.0
    var y = v * canvas.height / 2

    if(i === 0) {
      canvasCtx.moveTo(x, y)
    } else {
      canvasCtx.lineTo(x, y)
    }

    x += sliceWidth
  }
  
  canvasCtx.lineTo(canvas.width, canvas.height/2)
  canvasCtx.stroke()
  
  requestAnimationFrame(draw)
}

 

파형데이터 가져오기

AnalyserNode에서 getByteTimeDomainData()를 호출하여 파형 데이터를 가져온다.

아까 만들어둔 audioDataArray에 저장한다.

 

Canvas에 파형 데이터 그리기

canvas lineTo()를 이용하여 파형을 이어주는 선을 그려준다.

 

애니메이션

requestAnimationFrame() 을 계속 호출하여 파형데이터를 실시간으로 계속 그려주도록 한다.

 

정리

간단히 정리하면

  • mediaDevice로 마이크입력 stream을 가져와서
  • 마이크입력 stream을 AudioContext의 source로 연결해주고
  • sourceAnalyzerNode로 연결해준다
  • AnalyzerNode에서 파형데이터를 가져와서 Canvas에 그려준다.
  • requestAnimationFrame으로 계속 그려준다.

이상 재미삼아 만들어본 블로그 포스팅이었다.

 

반응형

댓글