19
2012_05_15 / nhn_박재성 Developing game audio with the Web Audio API

Developing game audio with the Web Audio API

Embed Size (px)

DESCRIPTION

Simple introduction of Web Audio API

Citation preview

Page 1: Developing game audio with the Web Audio API

2012_05_15 / nhn_박재성

Developing game audio with the Web Audio API

Page 2: Developing game audio with the Web Audio API

Web Audio API Modular routing Basic usage Background Music Sound effects 3D Positional sound Room effects and filters Detect clipping

Index

Page 3: Developing game audio with the Web Audio API

단순한 게임은 <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

제한적인 <audio>

Page 4: Developing game audio with the Web Audio API

High-level JavaScript API for processing and synthesizing audio in web application.

http://www.w3.org/TR/webaudio/ AudioContext는 모든 사운드 데이터를 관리 및 재생한다. 재생을 위해선 사운드 소스를 생성한 후, AudioContext 인스턴스와 연결해야 한다.

Web Audio API

Page 5: Developing game audio with the Web Audio API

연결은 꼭 직접적일 필요는 없으며, 중간에 여러 단계의 AudioNode와 연결(Modular Routing) 될 수 있다.

이를 통해 중간 단계의 AudioNode를 통해 음량 조정, 필터 적용 등을 처리 하게 된다.

Modular Routing

Page 6: Developing game audio with the Web Audio API

사용하는 브라우저의 audio 지원과 범위를 확인할 수 있다.

http://areweplayingyet.org/

브라우저 지원 여부

Source : http://caniuse.com/audio-api

Page 7: Developing game audio with the Web Audio API

// 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

Basic usage : create and routing

Page 8: Developing game audio with the Web Audio API

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();

Basic usage : loading file

Page 9: Developing game audio with the Web Audio API

반복적이고 예측 가능한 BGM은 불편과 짜증을 유발할 수 있다.

특정 시점(마지막 보스와의 대결과 같은)에 BGM도 그에 따라 감성적으로 반영이 되어야 한다.

여러 사운드의 믹싱은 음악 프로그램에서 제공하는 기본적인 기능 중 하나이다.

Web Audio API를 활용해 XHR로 상황에 맞는 소스를 로딩해 재생할 수 있다. 로딩은 시간이 소요되므로, 최초 페이지 로딩시 또는 게임 진행 중 점진적으로 로딩을 하도록 한다.

Background music

Page 10: Developing game audio with the Web Audio API

사용될 각 노드들에 대한 소스를 생성하고 이를 연결한다.

여러 개의 사운드가 반복 재생되는 상태에서, 특정 장면에 사용되는 사운드의 음량을 키우고 사용되지 않는 사운드의 음량을 줄여 cross-fade 한다.

Background music

Page 11: Developing game audio with the 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

<audio> to Web Audio API

Page 12: Developing game audio with the Web Audio API

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); }

Sound effects

Page 13: Developing game audio with the Web Audio API

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);

3D Positional sound

Page 14: Developing game audio with the Web Audio API

Positional model은 OpenAL(Open Audio Library)에 기반한다.

Distance model은 소스로부터의 거리에 따라 gain 값을 다르게 갖는다. Directional model은 외부 또는 내부 방향에 따라 gain 값을 다르게 갖는다.

3D Positional sound

Page 15: Developing game audio with the Web Audio API

동일한 소리를 장소에 따라 다르게 녹음된 데이터를 생성하는 것은 많은 비용을 필요로 한다.

동일한 사운드가 환경에 따라 다르게 들리는 것은 임펄스 응답(Impulse Response)의 차이라 할 수 있다.

ConvolverNode를 활용하면 임펄스 응답을 간단히 적용할 수 있다. var source = context.createBufferSource(); source.buffer = 사운드_데이터; var convolver = context.createConvolver(); convolver.buffer = 임펄스_데이터; source.connect(convolver); convolver.connect(context.destination);

Room effects and filters

Page 16: Developing game audio with the Web Audio API

연결된 많은 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) { … }

Detect clipping

Page 17: Developing game audio with the Web Audio API

// 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; } } }

Detect clipping

Page 18: Developing game audio with the Web Audio API

시그널이 부드럽고 튀지 않도록 DynamicCompressorNode를 활용하라.

페이지가 보이지 않는 경우에는 pageVisibility API를 활용해 불필요한 사운드 재생을 막는 것이 좋다.

몇 가지 기억할 사항

Page 19: Developing game audio with the Web Audio API

고맙습니다.