Developing game audio with the Web Audio API

2,089 views

Published on

Simple introduction of Web Audio API

0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,089
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
26
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Developing game audio with the Web Audio API

  1. 1. Developing game audio withthe Web Audio API 2012_05_15 / nhn_박재성
  2. 2. Index  Web Audio API  Modular routing  Basic usage  Background Music  Sound effects  3D Positional sound  Room effects and filters  Detect clipping
  3. 3. 제한적인 <audio>  단순한 게임은 <audio>로 가능하지만, 제한적이다. <audio controls loop> <source src=“music.wav"> </audio> <audio> can’t :  No ability to apply filters to the sound signal  No way to access the raw PCM data  No concept of position and direction of sources and listeners  No fine-grained timing
  4. 4. Web Audio API  High-level JavaScript API for processing and synthesizing audio in web application.  http://www.w3.org/TR/webaudio/  AudioContext는 모든 사운드 데이터를 관리 및 재생한다.  재생을 위해선 사운드 소스를 생성한 후, AudioContext 인스턴스와 연결해야 한다.
  5. 5. Modular Routing  연결은 꼭 직접적일 필요는 없으며, 중간에 여러 단계의 AudioNode와 연결(Modular Routing) 될 수 있다.  이를 통해 중간 단계의 AudioNode를 통해 음량 조정, 필터 적용 등을 처리 하게 된다.
  6. 6. 브라우저 지원 여부  사용하는 브라우저의 audio 지원과 범위를 확인할 수 있다.  http://areweplayingyet.org/ Source : http://caniuse.com/audio-api
  7. 7. Basic usage : create and routing // Audio Context 생성 var context = new webkitAudioContext(); // 사운드 소스 생성 var source = context.createBufferSource(); source.buffer = 버퍼_데이터;  직접 연결 : source.connect(context.destination);  gainNode 연결 : var gainNode = context.createGainNode(); source.connect(gainNode); gainNode.connect(context.destination);  GainNode를 Compressor와 연결 : var compressor = context.createDynamicsCompressor(); gainNode.connect(compressor); compressor.connect(context.destination); source.noteOn(0); // play
  8. 8. Basic usage : loading file var request = new XMLHttpRequest(); request.open(GET, sUrl, true); request.responseType = arraybuffer; // 전송받을 data가 바이너리이므로 arraybuffer로 설정 // XHR load callback request.onload = function() { // 비동기 디코딩 된다. 디코딩이 완료되면 디코딩된 PCM audio data를 사용할 수 있도록 준비된다. context.decodeAudioData(request.response, // load callback function(buffer) { ... }, // error callback function(e) { console.log(e); } ); }; request.send();
  9. 9. Background music  반복적이고 예측 가능한 BGM은 불편과 짜증을 유발할 수 있다.  특정 시점(마지막 보스와의 대결과 같은)에 BGM도 그에 따라 감성적으로 반영이 되어야 한다.  여러 사운드의 믹싱은 음악 프로그램에서 제공하는 기본적인 기능 중 하나이다.  Web Audio API를 활용해 XHR로 상황에 맞는 소스를 로딩해 재생할 수 있다.  로딩은 시간이 소요되므로, 최초 페이지 로딩시 또는 게임 진행 중 점진적으로 로딩을 하도록 한다.
  10. 10. Background music  사용될 각 노드들에 대한 소스를 생성하고 이를 연결한다.  여러 개의 사운드가 반복 재생되는 상태에서, 특정 장면에 사용되는 사운드의 음량을 키우고 사용되지 않는 사운드의 음량을 줄여 cross-fade 한다.
  11. 11. <audio> to Web Audio API  <audio>는 소스를 모두 다운로드 받지 않아도 실시간 스트리밍으로 재생된다.  스트리밍 소스를 Web Audio API와 연결하면 스트리밍을 분석하거나 조작할 수 있게 된다.  <audio>를 Web Audio context로 가져오는 것도 가능하다. var audioElement = document.querySelector(audio); var mediaSourceNode = context.createMediaElementSource(audioElement); mediaSourceNode.connect(context.destination); audioElement.play();  createAnalyser() creates a RealtimeAnalyserNode which provide real-time frequency and time- domain analysis information.  context.createAnalyser()를 통한 equalizer graph 데모 : http://html5-demos.appspot.com/static/webaudio/createMediaSourceElement.html
  12. 12. Sound effects  BGM과 마찬가지로 비슷한 종류의 반복은 지루하고 짜증스럽다.  이를 방지하기 위해 여러 종류의 사운드 풀을 준비해 사용할 수 있다.  여러 캐릭터가 다수 등장하는 배틀 장면인 경우에는 동시에 수많은 이펙트가 재생될 수 있다. // currentTime, starts at zero when the context is created and increases in real-time. var time = context.currentTime; for (var i = 0; i < rounds; i++) { var source = this.makeSource(this.buffers[M4A1]); source.noteOn(time + i * interval); }
  13. 13. 3D Positional sound  AudioPannerNode를 활용해 위치와 공간을 프로세싱 한다. var panner = context.createPanner(); // Directional model panner.coneOuterGain = 0.5; panner.coneOuterAngle = 180; panner.coneInnerAngle = 0; // Position, orientaion and velocity panner.setPosition(x, y, z); // 3D cartesian coordinate relative to the listener attribute panner.setOrientation(x, y, z); // pointing in the 3D cartesian coordinate space panner.setVelocity(x, y, z); // direction of travel and the speed in 3D space source.connect(panner); panner.connect(context.destination);
  14. 14. 3D Positional sound  Positional model은 OpenAL(Open Audio Library)에 기반한다.  Distance model은 소스로부터의 거리에 따라 gain 값을 다르게 갖는다.  Directional model은 외부 또는 내부 방향에 따라 gain 값을 다르게 갖는다.
  15. 15. Room effects and filters  동일한 소리를 장소에 따라 다르게 녹음된 데이터를 생성하는 것은 많은 비용을 필요로 한다.  동일한 사운드가 환경에 따라 다르게 들리는 것은 임펄스 응답(Impulse Response)의 차이라 할 수 있다.  ConvolverNode를 활용하면 임펄스 응답을 간단히 적용할 수 있다. var source = context.createBufferSource(); source.buffer = 사운드_데이터; var convolver = context.createConvolver(); convolver.buffer = 임펄스_데이터; source.connect(convolver); convolver.connect(context.destination);
  16. 16. Detect clipping  연결된 많은 AudioNode의 소리들이 normalize 되지 않으면 스피커 송출 용량을 넘어설 수 있다.  특정 채널의 시그널이 허용된 범위를 초과한 경우 clipping이 발생되며, -1 또는 1의 값으로 표현된다.  이를 위해 JavaScriptAudioNode를 사용한다. JavaScriptAudioNode는 audio를 JavaScript에서 직접 생성, 프로세스 또는 분석 할수 있게 한다. var meter = context.createJavaScriptNode( buffer_size, number_input_channel, number_output_channel ); meter.onaudioprocess = function(e) { … }
  17. 17. Detect clipping // Assume entire sound output is being piped through the mix node. var mix = context.createGainNode(); var meter = context.createJavaScriptNode(2048, 1, 1); // Porcess audio event binding meter.onaudioprocess = function (e) { var leftBuffer = e.inputBuffer.getChannelData(0); var rightBuffer = e.inputBuffer.getChannelData(1); checkClipping(leftBuffer); checkClipping(rightBuffer); }; mix.connect(meter); meter.connect(context.destination); mix.connect(context.destination); // Check if buffer exceeds function checkClipping(buffer) { var isClipping = false; // Iterate through buffer to check if any of the |values| exceeds 1. for (var i = 0; i < buffer.length; i++) { var absValue = Math.abs(buffer[i]); if (absValue >= 1) { isClipping = true; break; } } }
  18. 18. 몇 가지 기억할 사항  시그널이 부드럽고 튀지 않도록 DynamicCompressorNode를 활용하라.  페이지가 보이지 않는 경우에는 pageVisibility API를 활용해 불필요한 사운드 재생을 막는 것이 좋다.
  19. 19. 고맙습니다.

×