제2회 hello world 오픈세미나 web audio api-가능성엿보기

36
2012.07.07 / 박재성_nhn Web Audio API가능성 엿보기 http://www.flickr.com/photos/meaganjean/4263943043/

Upload: naver-d2

Post on 05-Dec-2014

6.795 views

Category:

Technology


3 download

DESCRIPTION

 

TRANSCRIPT

Page 1: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

2012.07.07 / 박재성_nhn

Web Audio API의 가능성 엿보기

http://www.flickr.com/photos/meaganjean/4263943043/

Page 2: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

1. Introduction • <audio> tag • Web Audio API • Brief History • 브라우저 지원 여부 • Modular Routing

2. 인터페이스 3. 기본 사용방법 4. How to use? : 다양한 응용방법 • Background music • <audio> to Web Audio API • Sound effects • 3D Positional sound : AudioPannerNode • Room effects and filters : ConvolverNode • Detect clipping : JavaScriptNode

5. Somethig more • Automation • 몇 가지 기억할 것들

Index

Page 3: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

1. Introduction

Page 4: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

이미 HTML5 <audio> 태그를 통해 사운드를 재생할 수 있다. <audio controls loop> <source src=“music.wav"> </audio> • 로딩과 디코딩에 대한 별도의 작업 없이 스트리밍으로 재생가능 • 다양한 재생 컨트롤 API 제공 (음량 조절, 재생시간 조절, etc) • Media event를 통한 다양한 이벤트 처리

<audio> tag : 웹에서의 사운드

Page 5: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

그러나…

• 사운드 시그널에 필터를 적용할 수 없다.

• Raw PCM 데이터 접근이 불가능 하다.

• 청취자에 대한 개념이 없기 때문에, 음향에 대한 공간 및 방향 설정 자체가 불가능 하다.

<audio> tag : 한계

Page 6: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

웹 어플리케이션에서 오디오 데이터를 프로세싱 하거나 합성할 수 있는 하이레벨(High-level) JavaScript API. Specification : http://www.w3.org/TR/webaudio/ AudioContext는 모든 사운드 데이터를 관리 및 재생한다. 음향 데이터가 최종적으로 송출 되려면 사운드 소스는, AudioContext 인스턴스와 연결 되어야 한다.

Web Audio API?

Page 7: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

// 1. Audio Context 생성 var context = new webkitAudioContext(); // 2. 사운드 소스 생성 var source = context.createBufferSource(); source.buffer = AudioBuffer_데이터; // 3. 소스를 스피커와 연결 (또는 다른 모듈과 연결) source.connect(context.destination);

Web Audio API? : First step

Page 8: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

Google과 Mozilla는 서로 다른 2개의 초안을 제안 (2011/12/15)

Google : Web Audio API - 하이레벨 함수(이미 기능들이 정의된) 제공 Mozilla : MediaStream Processing API(Audio Data API) - 로우레벨 접근 - <audio> 태그 기반 http://wiki.mozilla.org/Audio_Data_API

Brief History

Page 9: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

크롬 (윈도우, MacOS X, Linux) ChromeOS 사파리 5.2 beta에서 지원예정 (nightly 빌드에서 이미 사용가능) iOS6 Safari

브라우저 지원 여부

http://developer.apple.com/technologies/ios6/

Page 10: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

연결은 꼭 스피커와 직접적일 필요는 없으며, 중간에 여러 단계의 AudioNode 들과 연결(Modular Routing)되어 파이프라이닝 될수 있다.

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

Modular Routing

Page 11: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

2. 인터페이스

Page 12: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

모듈(노드)을 의미하며, 각 모듈들은 특별한 기능을 수행한다.

interface AudioNode { void connect(in AudioNode destination, in unsigned long output = 0, in unsigned long input = 0); void disconnect(in int output = 0); readonly attribute AudioContext context; readonly attribute unsigned long numberOfInputs; readonly attribute unsigned long numberOfOutputs; } source.connect(destination_node);

인터페이스 : AudioNode

Page 13: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

각각의 AudioNode들은 AudioParam 형식의 메서드를 갖으며, 이는 자동화 처리와 관련된 메서드를 제공한다.

http://www.w3.org/TR/webaudio/#AudioParam interface AudioParam { attribute float value; readonly attribute float minValue; readonly attribute float maxValue; readonly attribute float defaultValue; readonly attribute DOMString name; // Should define units constants here (seconds, decibels, cents, etc.) readonly attribute short units; // Parameter automation. void setValueAtTime(in float value, in float time); void linearRampToValueAtTime(in float value, in float time); void exponentialRampToValueAtTime(in float value, in float time); // Exponentially approach the target value with a rate having the given time constant. void setTargetValueAtTime(in float targetValue, in float time, in float timeConstant); // Sets an array of arbitrary parameter values starting at time for the given duration. // The number of values will be scaled to fit into the desired duration. void setValueCurveAtTime(in Float32Array values, in float time, in float duration); // Cancels all scheduled parameter changes with times greater than or equal to startTime. void cancelScheduledValues(in float startTime); }

인터페이스 : AudioParam

Page 14: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

메모리에 올려진 디코딩된 사운드 데이터를 의미한다. http://www.w3.org/TR/webaudio/#AudioBuffer interface AudioBuffer { // linear gain (default 1.0) attribute AudioGain gain; readonly attribute float sampleRate; readonly attribute long length; // in seconds readonly attribute float duration; readonly attribute int numberOfChannels; Float32Array getChannelData(in unsigned long channel); }

인터페이스 : AudioBuffer

Page 15: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

AudioBuffer를 한번 재생할 수 있으며, 여러 개의 노드들은 동일한 AudioBuffer를 가리킬 수도 있다.

http://www.w3.org/TR/webaudio/#AudioBufferSourceNode interface AudioBufferSourceNode : AudioSourceNode { // Playback this in-memory audio asset // Many sources can share the same buffer attribute AudioBuffer buffer; readonly attribute AudioGain gain; attribute AudioParam playbackRate; attribute boolean loop; void noteOn(in double when); void noteGrainOn(in double when, in double grainOffset, in double grainDuration); void noteOff(in double when); } var source = context.createBufferSource(); source.buffer = AudioBuffer_데이터; source.loop = true | false; // 반복여부

인터페이스 : AudioBufferSourceNode

Page 16: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

3. 기본 사용방법

Page 17: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

// Audio Context 생성 var context = new webkitAudioContext(); // 사운드 소스 생성 var source = context.createBufferSource(); source.buffer = AudioBuffer_데이터; 스피커와 직접 연결 : 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

기본 사용방법 : 컨텍스트 생성과 루팅

Page 18: 제2회 hello world 오픈세미나 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, // 로드 콜백 함수 function(buffer) { ... }, // 에러 콜백 함수 function(e) { console.log(e); } ); }; request.send();

기본 사용방법 : 소스 데이터 로딩

Page 19: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

4. How to use? : 다양한 응용방법

Page 20: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

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

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

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

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

Background music

Page 21: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

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

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

Background music

Page 22: 제2회 hello world 오픈세미나 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 23: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

게임에서 여러 캐릭터가 다수 등장하는 배틀 장면인 경우에는 동시에 수많은 이펙트가 재생될 수 있다.

동일한 사운드 재생을 방지하기 위해 여러 종류의 사운드 풀을 준비해 사용할 수도 있지만, 모든 상황을 대비하도록 구성하는 것은 어렵다.

동일한 사운드를 재생시점을 다르게 지정해 풀을 구성하지 않고도, 동일한 이펙트를 만들 수 있다. // currentTime은 컨텍스트가 생성된 시점을 기준으로 0의 값으로 시작하며, 실시간 증가되는 값이다.

var time = context.currentTime; for (var i = 0; i < rounds; i++) { var source = AudioBufferSource; source.noteOn(time + i * interval); }

Sound effects : 재생 시점이 다른 반복 재생

Page 24: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

DelayNode를 사용하면 오디오 시그널의 통과를 지연시킨다.

var delayNode = context.createDelayNode(), now = context.currentTime; delayNode.delayTime.setValueAtTime(0, now); delayNode.delayTime.linearRampToValueAtTime(2, now + time);

Sound effects : 시그널 지연

Page 25: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

BiquadFilterNode를 사용해, 사운드 시그널의 주파수를 필터링해 주파수의 응답을 변경할 수 있다.

var filter = context.createBiquadFilter(); source.connect(filter); // 0:LOWPASS, 1:HIGHPASS, 2:BANDPASS, 3:LOWSHELF, 4:HIGHSHELF, 5:PEAKING, 6:NOTCH, 7:ALLPASS

filter.type = 0; filter.Q.value = 12.06; filter.frequency.value = 400; filter.connect(context.destination);

Sound effects : 필터

Page 26: 제2회 hello world 오픈세미나 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 27: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

Positional model은 OpenAL(Open Audio Library)에 기반한다. http://connect.creativelabs.com/openal/default.aspx

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

Demo: http://www.html5rocks.com/en/tutorials/webaudio/positional_audio/

3D Positional sound

Page 28: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

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

동일한 사운드가 환경에 따라 다르게 들리는 것은 임펄스 응답(Impulse

Response)의 차이라 할 수 있다.

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

Room effects and filters

Page 29: 제2회 hello world 오픈세미나 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 30: 제2회 hello world 오픈세미나 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 31: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

5. Something more

Page 32: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

AudioNode의 AudioParam의 메서드를 이용해 특정 시간에 다른 값을 같도록 처리할 수 있다.

음량조절을 스케줄링하면, 페이드 처리가 자동으로 발생하도록 할수 있다. var now = context.currentTime; // 지정된 시간에 특정 값을 같도록 한다. source.gain.setValueAtTime(0, now); // 특정 시간까지 값을 리니어하게 변경하도록 스케줄링 한다. source.gain.linearRampToValueAtTime(1.0, now + value); source.gain.linearRampToValueAtTime(0.0, now + value);

Automation

Page 33: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

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

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

Web Audio API에서 모든 시간 단위는 밀리세컨드(millisecond)가 아닌 초(second) 단위 이다.

몇 가지 기억할 것들

Page 34: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

Oscillator

RealtimeAnalyserNode

AudioChannelSplitter

AudioChannelMerger

WaveShaperNode

다루지 못한 주제들

Page 35: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

Google I/O 2012 – Turning the Web Up to 11 Presentaiton : http://webaudio-io2012.appspot.com Video : http://youtu.be/hFsCG7v9Y4c

Getting started with Web Audio API http://www.html5rocks.com/en/tutorials/webaudio/intro/

Developing game audio with the Web Audio API http://www.html5rocks.com/en/tutorials/webaudio/games/..

Mixing positional audio and WebGL http://www.html5rocks.com/en/tutorials/webaudio/positional_audio/

Web Audio Playground http://webaudioplayground.appspot.com/

Web Audio Example http://chromium.googlecode.com/svn/trunk/samples/audio/index.html

Reference

Page 36: 제2회 hello world 오픈세미나 Web Audio API-가능성엿보기

http://www.flickr.com/photos/robinfeder/3482072805/