Web Audio API

현재 번역은 완벽하지 않습니다. 한국어로 문서 번역에 동참해주세요.

Web Audio API는 웹에서 오디오를 제어하기 위한 강력하고 다양한 기능을 제공합니다. Web Audio API를 이용하면 오디오 소스를 선택할 수 있도록 하거나, 오디오에 이펙트를 추가하거나, 오디오를 시각화하거나, 패닝과 같은 공간 이펙트를 적용시키는 등의 작업이 가능합니다.

Web audio의 개념과 사용법

Web Audio API는 오디오 컨텍스트 내부의 오디오 조작을 핸들링하는 것을 포함하며, 모듈러 라우팅을 허용하도록 설계되어 있습니다. 기본적인 오디오 연산은 오디오 노드를 통해 수행되며, 오디오 노드는 서로 연결되어 오디오 라우팅 그래프를 형성합니다. 다른 타입의 채널 레이아웃을 포함한 개별 오디오 소스는 단일 컨텍스트 내에서도 지원됩니다. 이 모듈식 설계는 역동적이고 복합적인 오디오 기능 생성을 위한 유연성을 제공합니다.

오디오 노드는 각각의 입력과 출력을 통해 체인과 간단한 망으로 연결됩니다. 이들은 일반적으로 하나 이상의 소스로 시작합니다. 소스들은 초당 수만 개 가량의 아주 작은 시간 단위의 음향 인텐시티(샘플) 배열로 제공됩니다. 이것은 OscillatorNode와 같이 수학적으로 계산되거나, AudioBufferSourceNode와 같은 사운드/비디오 파일, MediaElementAudioSourceNodeMediaStreamAudioSourceNode와 같은 오디오 스트림으로 녹화될 수 있습니다. 사실, 사운드 파일은 마이크나 전자기기로 생성된 음향 인텐시티가 녹음된 것에 불과하며, 하나의 복합적인 파동으로 믹싱됩니다.

오디오 노드의 출력은 다른 노드와 입력과 연결될 수 있습니다. 이 입력은 노드의 사운드 샘플 스트림을 다른 스트림으로 믹스하거나 변경합니다. 일반적인 변경은 GainNode와 같이 샘플에 소리를 더 키우거나 줄이는 값을 곱하는 것입니다. 사운드가 의도된 이펙트를 위해 충분히 처리되면, 이를 AudioContext.destination의 입력에 연결해 사운드를 스피커와 헤드폰으로 출력합니다. 이 연결은 사용자가 오디오를 듣도록 하기 위한 용도로만 필요합니다.

웹 오디오의 간단하고 일반적인 작업 흐름은 다음과 같습니다 :

  1. 오디오 컨텍스트를 생성합니다.
  2. 컨텍스트 내에 소스를 생성합니다.(ex - <audio>, 발진기, 스트림)
  3. 이펙트 노드를 생성합니다. (ex - 잔향 효과,  바이쿼드 필터, 패너, 압축기 등)
  4. 오디오의 최종 목적지를 선택합니다. (ex - 시스템 스피커)
  5. 사운드를 이펙트에 연결하고, 이펙트를 목적지에 연결합니다.

A simple box diagram with an outer box labeled Audio context, and three inner boxes labeled Sources, Effects and Destination. The three inner boxes have arrow between them pointing from left to right, indicating the flow of audio information.

타이밍은 정확도 높고 빠르게 컨트롤되므로, 개발자는 높은 샘플 레이트에서도 특정 샘플을 대상으로 이벤트에 정확하게 응답하는 코드를 작성할 수 있습니다. 따라서 드럼 머신이나 시퀀서 등의 어플리케이션을 충분히 구현 가능합니다.

Web Audio API는 오디오가 어떻게 공간화될지 컨트롤할 수 있도록 합니다. 소스-리스너 모델을 기반으로 하는 시스템을 사용하면 패닝 모델거리-유도 감쇄 혹은 움직이는 소스(혹은 움직이는 청자)를 통해 유발된 도플러 시프트 컨트롤이 가능합니다.

Basic concepts behind Web Audio API 아티클에서 Web Audio API 이론에 대한 더 자세한 내용을 읽을 수 있습니다.

Web Audio API Interfaces

Web Audio API는 다양한 인터페이스와 연관 이벤트를 가지고 있으며, 이는 9가지의 기능적 범주로 나뉩니다.

일반 오디오 그래프 정의

Web Audio API 사용범위 내에서 오디오 그래프를 형성하는 일반적인 컨테이너와 정의입니다.

AudioContext
AudioContext 인터페이스는 오디오 모듈이 서로 연결되어 구성된 오디오 프로세싱 그래프를 표현하며, 각각의 그래프는 AudioNode로 표현됩니다. AudioContext는 자신이 가지고 있는 노드의 생성과 오디오 프로세싱 혹은 디코딩의 실행을 제어합니다. 어떤 작업이든 시작하기 전에 AudioContext를 생성해야 합니다. 모든 작업은 컨텍스트 내에서 이루어집니다.
AudioNode
AudioNode 인터페이스는 오디오 소스(<audio><video>엘리먼트), 오디오 목적지, 중간 처리 모듈(BiquadFilterNode이나 GainNode)과 같은 오디오 처리 모듈을 나타냅니다.
AudioParam
AudioParam 인터페이스는 AudioNode중 하나와 같은 오디오 관련 파라미터를 나타냅니다. 이는 특정 값 또는 값 변경으로 세팅되거나, 특정 시간에 발생하고 특정 패턴을 따르도록 스케쥴링할 수 있습니다.
The ended event

ended 이벤트는 미디어의 끝에 도달하여 재생이 정지되면 호출됩니다.

오디오 소스 정의하기

Web Audio API에서 사용하기 위한 오디오 소스를 정의하는 인터페이스입니다.

OscillatorNode
OscillatorNode 인터페이스는 삼각파 또는 사인파와 같은 주기적 파형을 나타냅니다. 이것은 주어진 주파수의 파동을 생성하는 AudioNode 오디오 프로세싱 모듈입니다.
AudioBuffer
AudioBuffer 인터페이스는 AudioContext.decodeAudioData()메소드를 사용해 오디오 파일에서 생성되거나 AudioContext.createBuffer()를 사용해 로우 데이터로부터 생성된 메모리상에 적재되는 짧은 오디오 자원을 나타냅니다. 이 형식으로 디코딩된 오디오는 AudioBufferSourceNode에 삽입될 수 있습니다.
AudioBufferSourceNode
AudioBufferSourceNode 인터페이스는 AudioBuffer에 저장된 메모리상의 오디오 데이터로 구성된 오디오 소스를 나타냅니다. 이것은 오디오 소스 역할을 하는 AudioNode입니다.
MediaElementAudioSourceNode
MediaElementAudioSourceNode 인터페이스는 <audio> 나 <video> HTML 엘리먼트로 구성된 오디오 소스를 나타냅니다. 이것은 오디오 소스 역할을 하는 AudioNode입니다.
MediaStreamAudioSourceNode
MediaStreamAudioSourceNode 인터페이스는 WebRTC MediaStream(웹캡, 마이크 혹은 원격 컴퓨터에서 전송된 스트림)으로 구성된 오디오 소스를 나타냅니다. 이것은 오디오 소스 역할을 하는 AudioNode입니다.

오디오 이펙트 필터 정의하기

오디오 소스에 적용할 이펙트를 정의하는 인터페이스입니다.

BiquadFilterNode
BiquadFilterNode 인터페이스는 간단한 하위 필터를 나타냅니다. 이것은 여러 종류의 필터나 톤 제어 장치 혹은 그래픽 이퀄라이저를 나타낼 수 있는 AudioNode입니다. BiquadFilterNode는 항상 단 하나의 입력과 출력만을 가집니다. 
ConvolverNode
ConvolverNode 인터페이스는 주어진 AudioBuffer에 선형 콘볼루션을 수행하는 AudioNode이며, 리버브 이펙트를 얻기 위해 자주 사용됩니다. 
DelayNode
DelayNode 인터페이스는 지연선을 나타냅니다. 지연선은 입력 데이터가 출력에 전달되기까지의 사이에 딜레이를 발생시키는 AudioNode 오디오 처리 모듈입니다.
DynamicsCompressorNode
DynamicsCompressorNode 인터페이스는 압축 이펙트를 제공합니다, 이는 신호의 가장 큰 부분의 볼륨을 낮추어 여러 사운드를 동시에 재생할 때 발생할 수 있는 클리핑 및 왜곡을 방지합니다.
GainNode
GainNode 인터페이스는 음량의 변경을 나타냅니다. 이는 출력에 전달되기 전의 입력 데이터에 주어진 음량 조정을 적용하기 위한 AudioNode 오디오 모듈입니다.
StereoPannerNode
StereoPannerNode 인터페이스는 오디오 스트림을 좌우로 편향시키는데 사용될 수 있는 간단한 스테레오 패너 노드를 나타냅니다.
WaveShaperNode
WaveShaperNode 인터페이스는 비선형 왜곡을 나타냅니다. 이는 곡선을 사용하여 신호의 파형 형성에 왜곡을 적용하는 AudioNode입니다. 분명한 왜곡 이펙트 외에도 신호에 따뜻한 느낌을 더하는데 자주 사용됩니다.
PeriodicWave
OscillatorNode의 출력을 형성하는데 사용될 수 있는 주기적 파형을 설명합니다.

오디오 목적지 정의하기

처리된 오디오를 어디에 출력할지 정의하는 인터페이스입니다.

AudioDestinationNode
AudioDestinationNode 인터페이스는 주어진 컨텍스트 내의 오디오 소스의 최종 목적지를 나타냅니다. 주로 기기의 스피커로 출력할 때 사용됩니다.
MediaStreamAudioDestinationNode
MediaStreamAudioDestinationNode 인터페이스는 단일 AudioMediaStreamTrack 을 가진 WebRTC MediaStream로 구성된 오디오 목적지를 나타내며, 이는 getUserMedia()에서 얻은 MediaStream과 비슷한 방식으로 사용할 수 있습니다. 이것은 오디오 목적지 역할을 하는 AudioNode입니다.

데이터 분석 및 시각화

오디오에서 재생시간이나 주파수 등의 데이터를 추출하기 위한 인터페이스입니다.

AnalyserNode
AnalyserNode 인터페이스는 데이터를 분석하고 시각화하기 위한 실시간 주파수와 시간영역 분석 정보를 제공하는 노드를 나타냅니다.

오디오 채널을 분리하고 병합하기

오디오 채널들을 분리하거나 병합하기 위한 인터페이스입니다.

ChannelSplitterNode
ChannelSplitterNode 인터페이스는 오디오 소스의 여러 채널을 모노 출력 셋으로 분리합니다.
ChannelMergerNode
ChannelMergerNode 인터페이스는 여러 모노 입력을 하나의 출력으로 재결합합니다. 각 입력은 출력의 채널을 채우는데 사용될 것입니다.

오디오 공간화

오디오 소스에 오디오 공간화 패닝 이펙트를 추가하는 인터페이스입니다.

AudioListener
AudioListener 인터페이스는 오디오 공간화에 사용되는 오디오 장면을 청취하는 고유한 시청자의 위치와 방향을 나타냅니다.
PannerNode
PannerNode 인터페이스는 공간 내의 신호 양식을 나타냅니다. 이것은 자신의 오른손 직교 좌표 내의 포지션과, 속도 벡터를 이용한 움직임과, 방향성 원뿔을 이용한 방향을 서술하는 AudioNode 오디오 프로세싱 모듈입니다.

자바스크립트에서 오디오 처리하기

자바스크립트에서 오디오 데이터를 처리하기 위한 코드를 작성할 수 있습니다. 이렇게 하려면 아래에 나열된 인터페이스와 이벤트를 사용하세요.

이것은 Web Audio API 2014년 8월 29일의 스펙입니다. 이 기능은 지원이 중단되고 Audio_Workers로 대체될 예정입니다.

ScriptProcessorNode
ScriptProcessorNode 인터페이스는 자바스크립트를 이용한 오디오 생성, 처리, 분석 기능을 제공합니다. 이것은 현재 입력 버퍼와 출력 버퍼, 총 두 개의 버퍼에 연결되는 AudioNode 오디오 프로세싱 모듈입니다. AudioProcessingEvent인터페이스를 구현하는 이벤트는 입력 버퍼에 새로운 데이터가 들어올 때마다 객체로 전달되고, 출력 버퍼가 데이터로 채워지면 이벤트 핸들러가 종료됩니다.
audioprocess (event)
audioprocess 이벤트는 Web Audio API ScriptProcessorNode의 입력 버퍼가 처리될 준비가 되었을 때 발생합니다.
AudioProcessingEvent
Web Audio API AudioProcessingEvent 는 ScriptProcessorNode 입력 버퍼가 처리될 준비가 되었을 때 발생하는 이벤트를 나타냅니다.

오프라인/백그라운드 오디오 처리하기

다음을 이용해 백그라운드(장치의 스피커가 아닌 AudioBuffer으로 렌더링)에서 오디오 그래프를 신속하게 처리/렌더링 할수 있습니다.

OfflineAudioContext
OfflineAudioContext 인터페이스는 AudioNode로 연결되어 구성된 오디오 프로세싱 그래프를 나타내는 AudioContext 인터페이스입니다. 표준 AudioContext 와 대조적으로, OfflineAudioContext 는 실제로 오디오를 렌더링하지 않고 가능한 빨리 버퍼 내에서 생성합니다. 
complete (event)
complete 이벤트는 OfflineAudioContext의 렌더링이 종료될때 발생합니다.
OfflineAudioCompletionEvent
OfflineAudioCompletionEvent 이벤트는 OfflineAudioContext 의 처리가 종료될 때 발생하는 이벤트를 나타냅니다. complete 이벤트는 이 이벤트를 구현합니다.

오디오 워커

오디오 워커는 web worker 컨텍스트 내에서 스크립팅된 오디오 처리를 관리하기 위한 기능을 제공하며, 두어가지 인터페이스로 정의되어 있습니다(2014년 8월 29일 새로운 기능이 추가되었습니다). 이는 아직 모든 브라우저에서 구현되지 않았습니다. 구현된 브라우저에서는 Audio processing in JavaScript에서 설명된 ScriptProcessorNode를 포함한 다른 기능을 대체합니다.

AudioWorkerNode
AudioWorkerNode 인터페이스는 워커 쓰레드와 상호작용하여 오디오를 직접 생성, 처리, 분석하는 AudioNode를 나타냅니다. 
AudioWorkerGlobalScope
AudioWorkerGlobalScope 인터페이스는 DedicatedWorkerGlobalScope 에서 파생된 오디오 처리 스크립트가 실행되는 워커 컨텍스트를 나타내는 객체입니다. 이것은 워커 쓰레드 내에서 자바스크립트를 이용하여 직접 오디오 데이터를 생성, 처리, 분석할 수 있도록 설계되었습니다.
AudioProcessEvent
이것은 처리를 수행하기 위해 AudioWorkerGlobalScope 오브젝트로 전달되는 Event 오브젝트입니다.

Obsolete interfaces

The following interfaces were defined in old versions of the Web Audio API spec, but are now obsolete and have been replaced by other interfaces.

JavaScriptNode
Used for direct audio processing via JavaScript. This interface is obsolete, and has been replaced by ScriptProcessorNode.
WaveTableNode
Used to define a periodic waveform. This interface is obsolete, and has been replaced by PeriodicWave.

Example

This example shows a wide variety of Web Audio API functions being used. You can see this code in action on the Voice-change-o-matic demo (also check out the full source code at Github) — this is an experimental voice changer toy demo; keep your speakers turned down low when you use it, at least to start!

The Web Audio API lines are highlighted; if you want to find out more about what the different methods, etc. do, have a search around the reference pages.

var audioCtx = new (window.AudioContext || window.webkitAudioContext)(); // define audio context
// Webkit/blink browsers need prefix, Safari won't work without window.

var voiceSelect = document.getElementById("voice"); // select box for selecting voice effect options
var visualSelect = document.getElementById("visual"); // select box for selecting audio visualization options
var mute = document.querySelector('.mute'); // mute button
var drawVisual; // requestAnimationFrame

var analyser = audioCtx.createAnalyser();
var distortion = audioCtx.createWaveShaper();
var gainNode = audioCtx.createGain();
var biquadFilter = audioCtx.createBiquadFilter();

function makeDistortionCurve(amount) { // function to make curve shape for distortion/wave shaper node to use
  var k = typeof amount === 'number' ? amount : 50,
    n_samples = 44100,
    curve = new Float32Array(n_samples),
    deg = Math.PI / 180,
    i = 0,
    x;
  for ( ; i < n_samples; ++i ) {
    x = i * 2 / n_samples - 1;
    curve[i] = ( 3 + k ) * x * 20 * deg / ( Math.PI + k * Math.abs(x) );
  }
  return curve;
};

navigator.getUserMedia (
  // constraints - only audio needed for this app
  {
    audio: true
  },

  // Success callback
  function(stream) {
    source = audioCtx.createMediaStreamSource(stream);
    source.connect(analyser);
    analyser.connect(distortion);
    distortion.connect(biquadFilter);
    biquadFilter.connect(gainNode);
    gainNode.connect(audioCtx.destination); // connecting the different audio graph nodes together

    visualize(stream);
    voiceChange();

  },

  // Error callback
  function(err) {
    console.log('The following gUM error occured: ' + err);
  }
);

function visualize(stream) {
  WIDTH = canvas.width;
  HEIGHT = canvas.height;

  var visualSetting = visualSelect.value;
  console.log(visualSetting);

  if(visualSetting == "sinewave") {
    analyser.fftSize = 2048;
    var bufferLength = analyser.frequencyBinCount; // half the FFT value
    var dataArray = new Uint8Array(bufferLength); // create an array to store the data

    canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);

    function draw() {

      drawVisual = requestAnimationFrame(draw);

      analyser.getByteTimeDomainData(dataArray); // get waveform data and put it into the array created above

      canvasCtx.fillStyle = 'rgb(200, 200, 200)'; // draw wave with canvas
      canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

      canvasCtx.lineWidth = 2;
      canvasCtx.strokeStyle = 'rgb(0, 0, 0)';

      canvasCtx.beginPath();

      var sliceWidth = WIDTH * 1.0 / bufferLength;
      var x = 0;

      for(var i = 0; i < bufferLength; i++) {

        var v = dataArray[i] / 128.0;
        var y = v * 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();
    };

    draw();

  } else if(visualSetting == "off") {
    canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);
    canvasCtx.fillStyle = "red";
    canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
  }

}

function voiceChange() {
  distortion.curve = new Float32Array;
  biquadFilter.gain.value = 0; // reset the effects each time the voiceChange function is run

  var voiceSetting = voiceSelect.value;
  console.log(voiceSetting);

  if(voiceSetting == "distortion") {
    distortion.curve = makeDistortionCurve(400); // apply distortion to sound using waveshaper node
  } else if(voiceSetting == "biquad") {
    biquadFilter.type = "lowshelf";
    biquadFilter.frequency.value = 1000;
    biquadFilter.gain.value = 25; // apply lowshelf filter to sounds using biquad
  } else if(voiceSetting == "off") {
    console.log("Voice settings turned off"); // do nothing, as off option was chosen
  }

}

// event listeners to change visualize and voice settings

visualSelect.onchange = function() {
  window.cancelAnimationFrame(drawVisual);
  visualize(stream);
}

voiceSelect.onchange = function() {
  voiceChange();
}

mute.onclick = voiceMute;

function voiceMute() { // toggle to mute and unmute sound
  if(mute.id == "") {
    gainNode.gain.value = 0; // gain set to 0 to mute sound
    mute.id = "activated";
    mute.innerHTML = "Unmute";
  } else {
    gainNode.gain.value = 1; // gain set to 1 to unmute sound
    mute.id = "";    
    mute.innerHTML = "Mute";
  }
}

Specifications

Specification Status Comment
Web Audio API Working Draft  

Browser compatibility

Feature Chrome Edge Firefox (Gecko) Internet Explorer Opera Safari (WebKit)
Basic support 14 webkit (Yes) 23 No support 15 webkit
22 (unprefixed)
6 webkit
Feature Android Chrome Edge Firefox Mobile (Gecko) Firefox OS IE Phone Opera Mobile Safari Mobile
Basic support No support 28 webkit (Yes) 25 1.2 No support No support webkit

See also

문서 태그 및 공헌자

 이 페이지의 공헌자: chant
 최종 변경: chant,