SlideShare a Scribd company logo
1 of 19
Download to read offline
Developing game audio with
the Web Audio API




                       2012_05_15 / nhn_๋ฐ•์žฌ์„ฑ
Index

 ๏‚ง Web Audio API
 ๏‚ง Modular routing
 ๏‚ง Basic usage
 ๏‚ง Background Music
 ๏‚ง Sound effects
 ๏‚ง 3D Positional sound
 ๏‚ง Room effects and filters
 ๏‚ง Detect clipping
์ œํ•œ์ ์ธ <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
Web Audio API

 ๏‚ง High-level JavaScript API for processing and synthesizing audio in web
   application.
   ๏ƒ  http://www.w3.org/TR/webaudio/

 ๏‚ง AudioContext๋Š” ๋ชจ๋“  ์‚ฌ์šด๋“œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌ ๋ฐ ์žฌ์ƒํ•œ๋‹ค.

 ๏‚ง ์žฌ์ƒ์„ ์œ„ํ•ด์„  ์‚ฌ์šด๋“œ ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•œ ํ›„, AudioContext ์ธ์Šคํ„ด์Šค์™€ ์—ฐ๊ฒฐํ•ด์•ผ
   ํ•œ๋‹ค.
Modular Routing
 ๏‚ง ์—ฐ๊ฒฐ์€ ๊ผญ ์ง์ ‘์ ์ผ ํ•„์š”๋Š” ์—†์œผ๋ฉฐ, ์ค‘๊ฐ„์— ์—ฌ๋Ÿฌ ๋‹จ๊ณ„์˜ AudioNode์™€
   ์—ฐ๊ฒฐ(Modular Routing) ๋  ์ˆ˜ ์žˆ๋‹ค.

 ๏‚ง ์ด๋ฅผ ํ†ตํ•ด ์ค‘๊ฐ„ ๋‹จ๊ณ„์˜ AudioNode๋ฅผ ํ†ตํ•ด ์Œ๋Ÿ‰ ์กฐ์ •, ํ•„ํ„ฐ ์ ์šฉ ๋“ฑ์„ ์ฒ˜๋ฆฌ
   ํ•˜๊ฒŒ ๋œ๋‹ค.
๋ธŒ๋ผ์šฐ์ € ์ง€์› ์—ฌ๋ถ€
 ๏‚ง ์‚ฌ์šฉํ•˜๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ audio ์ง€์›๊ณผ ๋ฒ”์œ„๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 ๏ƒ  http://areweplayingyet.org/




                                Source : http://caniuse.com/audio-api
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
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();
Background music

 ๏‚ง ๋ฐ˜๋ณต์ ์ด๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ BGM์€ ๋ถˆํŽธ๊ณผ ์งœ์ฆ์„ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๋‹ค.

 ๏‚ง ํŠน์ • ์‹œ์ (๋งˆ์ง€๋ง‰ ๋ณด์Šค์™€์˜ ๋Œ€๊ฒฐ๊ณผ ๊ฐ™์€)์— BGM๋„ ๊ทธ์— ๋”ฐ๋ผ ๊ฐ์„ฑ์ ์œผ๋กœ
   ๋ฐ˜์˜์ด ๋˜์–ด์•ผ ํ•œ๋‹ค.

 ๏‚ง ์—ฌ๋Ÿฌ ์‚ฌ์šด๋“œ์˜ ๋ฏน์‹ฑ์€ ์Œ์•… ํ”„๋กœ๊ทธ๋žจ์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ด๋‹ค.

 ๏‚ง Web Audio API๋ฅผ ํ™œ์šฉํ•ด XHR๋กœ ์ƒํ™ฉ์— ๋งž๋Š” ์†Œ์Šค๋ฅผ ๋กœ๋”ฉํ•ด ์žฌ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
   ๏ƒ  ๋กœ๋”ฉ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋ฏ€๋กœ, ์ตœ์ดˆ ํŽ˜์ด์ง€ ๋กœ๋”ฉ์‹œ ๋˜๋Š” ๊ฒŒ์ž„ ์ง„ํ–‰ ์ค‘
     ์ ์ง„์ ์œผ๋กœ ๋กœ๋”ฉ์„ ํ•˜๋„๋ก ํ•œ๋‹ค.
Background music
 ๏‚ง ์‚ฌ์šฉ๋  ๊ฐ ๋…ธ๋“œ๋“ค์— ๋Œ€ํ•œ ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ์—ฐ๊ฒฐํ•œ๋‹ค.

 ๏‚ง ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์‚ฌ์šด๋“œ๊ฐ€ ๋ฐ˜๋ณต ์žฌ์ƒ๋˜๋Š” ์ƒํƒœ์—์„œ, ํŠน์ • ์žฅ๋ฉด์— ์‚ฌ์šฉ๋˜๋Š” ์‚ฌ์šด๋“œ์˜
   ์Œ๋Ÿ‰์„ ํ‚ค์šฐ๊ณ  ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์‚ฌ์šด๋“œ์˜ ์Œ๋Ÿ‰์„ ์ค„์—ฌ cross-fade ํ•œ๋‹ค.
<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
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);
 }
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);
3D Positional sound

 ๏‚ง Positional model์€ OpenAL(Open Audio Library)์— ๊ธฐ๋ฐ˜ํ•œ๋‹ค.

 ๏ƒ  Distance model์€ ์†Œ์Šค๋กœ๋ถ€ํ„ฐ์˜ ๊ฑฐ๋ฆฌ์— ๋”ฐ๋ผ gain ๊ฐ’์„ ๋‹ค๋ฅด๊ฒŒ ๊ฐ–๋Š”๋‹ค.
 ๏ƒ  Directional model์€ ์™ธ๋ถ€ ๋˜๋Š” ๋‚ด๋ถ€ ๋ฐฉํ–ฅ์— ๋”ฐ๋ผ gain ๊ฐ’์„ ๋‹ค๋ฅด๊ฒŒ ๊ฐ–๋Š”๋‹ค.
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);
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) {
   โ€ฆ
 }
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;
        }
     }
 }
๋ช‡ ๊ฐ€์ง€ ๊ธฐ์–ตํ•  ์‚ฌํ•ญ

 ๏‚ง ์‹œ๊ทธ๋„์ด ๋ถ€๋“œ๋Ÿฝ๊ณ  ํŠ€์ง€ ์•Š๋„๋ก DynamicCompressorNode๋ฅผ ํ™œ์šฉํ•˜๋ผ.




 ๏‚ง ํŽ˜์ด์ง€๊ฐ€ ๋ณด์ด์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋Š” pageVisibility API๋ฅผ ํ™œ์šฉํ•ด ๋ถˆํ•„์š”ํ•œ ์‚ฌ์šด๋“œ
   ์žฌ์ƒ์„ ๋ง‰๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
๊ณ ๋ง™์Šต๋‹ˆ๋‹ค.

More Related Content

Similar to Developing game audio with the Web Audio API

Android Screen Recorder
Android Screen RecorderAndroid Screen Recorder
Android Screen RecorderSooHwan Ok
ย 
Windows Phone Mango ์•„ํ‚คํ…์ฒ˜-๋ฉ€ํ‹ฐํƒœ์Šคํ‚น(2)
Windows Phone Mango ์•„ํ‚คํ…์ฒ˜-๋ฉ€ํ‹ฐํƒœ์Šคํ‚น(2)Windows Phone Mango ์•„ํ‚คํ…์ฒ˜-๋ฉ€ํ‹ฐํƒœ์Šคํ‚น(2)
Windows Phone Mango ์•„ํ‚คํ…์ฒ˜-๋ฉ€ํ‹ฐํƒœ์Šคํ‚น(2)mosaicnet
ย 
๋ฆฌ์ŠคํŽ™ํ† ๋ง ์„ธ๋ฏธ๋‚˜ - ์›น ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘ ๊ฐœ๋…, Node.js๋ฅผ ํ†ตํ•œ ์„œ๋ฒ„ ์ดํ•ด, REST API
๋ฆฌ์ŠคํŽ™ํ† ๋ง ์„ธ๋ฏธ๋‚˜ - ์›น ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘ ๊ฐœ๋…, Node.js๋ฅผ ํ†ตํ•œ ์„œ๋ฒ„ ์ดํ•ด, REST API๋ฆฌ์ŠคํŽ™ํ† ๋ง ์„ธ๋ฏธ๋‚˜ - ์›น ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘ ๊ฐœ๋…, Node.js๋ฅผ ํ†ตํ•œ ์„œ๋ฒ„ ์ดํ•ด, REST API
๋ฆฌ์ŠคํŽ™ํ† ๋ง ์„ธ๋ฏธ๋‚˜ - ์›น ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘ ๊ฐœ๋…, Node.js๋ฅผ ํ†ตํ•œ ์„œ๋ฒ„ ์ดํ•ด, REST APIWooyoung Ko
ย 
Startup JavaScript 9 - Socket.IO ์‹ค์‹œ๊ฐ„ ํ†ต์‹ 
Startup JavaScript 9 - Socket.IO ์‹ค์‹œ๊ฐ„ ํ†ต์‹ Startup JavaScript 9 - Socket.IO ์‹ค์‹œ๊ฐ„ ํ†ต์‹ 
Startup JavaScript 9 - Socket.IO ์‹ค์‹œ๊ฐ„ ํ†ต์‹ Circulus
ย 
Startup JavaScript 7 - Node.JS ๊ธฐ์ดˆ
Startup JavaScript 7 - Node.JS ๊ธฐ์ดˆStartup JavaScript 7 - Node.JS ๊ธฐ์ดˆ
Startup JavaScript 7 - Node.JS ๊ธฐ์ดˆCirculus
ย 
Node.js at OKJSP
Node.js at OKJSPNode.js at OKJSP
Node.js at OKJSPJeongHun Byeon
ย 
Puppetแ„€แ…ช แ„Œแ…กแ„ƒแ…ฉแ†ผแ„’แ…ชแ„ƒแ…ฌแ†ซ แ„‰แ…ตแ„‰แ…ณแ„แ…ฆแ†ท แ„€แ…ชแ†ซแ„…แ…ต
Puppetแ„€แ…ช แ„Œแ…กแ„ƒแ…ฉแ†ผแ„’แ…ชแ„ƒแ…ฌแ†ซ แ„‰แ…ตแ„‰แ…ณแ„แ…ฆแ†ท แ„€แ…ชแ†ซแ„…แ…ตPuppetแ„€แ…ช แ„Œแ…กแ„ƒแ…ฉแ†ผแ„’แ…ชแ„ƒแ…ฌแ†ซ แ„‰แ…ตแ„‰แ…ณแ„แ…ฆแ†ท แ„€แ…ชแ†ซแ„…แ…ต
Puppetแ„€แ…ช แ„Œแ…กแ„ƒแ…ฉแ†ผแ„’แ…ชแ„ƒแ…ฌแ†ซ แ„‰แ…ตแ„‰แ…ณแ„แ…ฆแ†ท แ„€แ…ชแ†ซแ„…แ…ตKeon Ahn
ย 
Python server-101
Python server-101Python server-101
Python server-101Huey Park
ย 
3D์นดํˆฐ๋ฉ”์ด์ปค ์™„๋ฃŒ์„ธ๋ฏธ๋‚˜(๋ณต๊ตฌ๋จ)
3D์นดํˆฐ๋ฉ”์ด์ปค ์™„๋ฃŒ์„ธ๋ฏธ๋‚˜(๋ณต๊ตฌ๋จ)3D์นดํˆฐ๋ฉ”์ด์ปค ์™„๋ฃŒ์„ธ๋ฏธ๋‚˜(๋ณต๊ตฌ๋จ)
3D์นดํˆฐ๋ฉ”์ด์ปค ์™„๋ฃŒ์„ธ๋ฏธ๋‚˜(๋ณต๊ตฌ๋จ)Daniel Shin
ย 
Audio data preprocessing and data loading using torchaudio
Audio data preprocessing and data loading using torchaudioAudio data preprocessing and data loading using torchaudio
Audio data preprocessing and data loading using torchaudioSeungHeon Doh
ย 
2023 GDG Sondo DevFest - Flutter/ Flavor, PlatformChannel, Environment variab...
2023 GDG Sondo DevFest - Flutter/ Flavor, PlatformChannel, Environment variab...2023 GDG Sondo DevFest - Flutter/ Flavor, PlatformChannel, Environment variab...
2023 GDG Sondo DevFest - Flutter/ Flavor, PlatformChannel, Environment variab...MaRoKim4
ย 
Hyperledger Fabric practice (v2.0)
Hyperledger Fabric practice (v2.0) Hyperledger Fabric practice (v2.0)
Hyperledger Fabric practice (v2.0) wonyong hwang
ย 
HTML5 & CSS3 - Video,Audio
HTML5 & CSS3 - Video,AudioHTML5 & CSS3 - Video,Audio
HTML5 & CSS3 - Video,Audiohyun soomyung
ย 

Similar to Developing game audio with the Web Audio API (13)

Android Screen Recorder
Android Screen RecorderAndroid Screen Recorder
Android Screen Recorder
ย 
Windows Phone Mango ์•„ํ‚คํ…์ฒ˜-๋ฉ€ํ‹ฐํƒœ์Šคํ‚น(2)
Windows Phone Mango ์•„ํ‚คํ…์ฒ˜-๋ฉ€ํ‹ฐํƒœ์Šคํ‚น(2)Windows Phone Mango ์•„ํ‚คํ…์ฒ˜-๋ฉ€ํ‹ฐํƒœ์Šคํ‚น(2)
Windows Phone Mango ์•„ํ‚คํ…์ฒ˜-๋ฉ€ํ‹ฐํƒœ์Šคํ‚น(2)
ย 
๋ฆฌ์ŠคํŽ™ํ† ๋ง ์„ธ๋ฏธ๋‚˜ - ์›น ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘ ๊ฐœ๋…, Node.js๋ฅผ ํ†ตํ•œ ์„œ๋ฒ„ ์ดํ•ด, REST API
๋ฆฌ์ŠคํŽ™ํ† ๋ง ์„ธ๋ฏธ๋‚˜ - ์›น ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘ ๊ฐœ๋…, Node.js๋ฅผ ํ†ตํ•œ ์„œ๋ฒ„ ์ดํ•ด, REST API๋ฆฌ์ŠคํŽ™ํ† ๋ง ์„ธ๋ฏธ๋‚˜ - ์›น ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘ ๊ฐœ๋…, Node.js๋ฅผ ํ†ตํ•œ ์„œ๋ฒ„ ์ดํ•ด, REST API
๋ฆฌ์ŠคํŽ™ํ† ๋ง ์„ธ๋ฏธ๋‚˜ - ์›น ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘ ๊ฐœ๋…, Node.js๋ฅผ ํ†ตํ•œ ์„œ๋ฒ„ ์ดํ•ด, REST API
ย 
Startup JavaScript 9 - Socket.IO ์‹ค์‹œ๊ฐ„ ํ†ต์‹ 
Startup JavaScript 9 - Socket.IO ์‹ค์‹œ๊ฐ„ ํ†ต์‹ Startup JavaScript 9 - Socket.IO ์‹ค์‹œ๊ฐ„ ํ†ต์‹ 
Startup JavaScript 9 - Socket.IO ์‹ค์‹œ๊ฐ„ ํ†ต์‹ 
ย 
Startup JavaScript 7 - Node.JS ๊ธฐ์ดˆ
Startup JavaScript 7 - Node.JS ๊ธฐ์ดˆStartup JavaScript 7 - Node.JS ๊ธฐ์ดˆ
Startup JavaScript 7 - Node.JS ๊ธฐ์ดˆ
ย 
Node.js at OKJSP
Node.js at OKJSPNode.js at OKJSP
Node.js at OKJSP
ย 
Puppetแ„€แ…ช แ„Œแ…กแ„ƒแ…ฉแ†ผแ„’แ…ชแ„ƒแ…ฌแ†ซ แ„‰แ…ตแ„‰แ…ณแ„แ…ฆแ†ท แ„€แ…ชแ†ซแ„…แ…ต
Puppetแ„€แ…ช แ„Œแ…กแ„ƒแ…ฉแ†ผแ„’แ…ชแ„ƒแ…ฌแ†ซ แ„‰แ…ตแ„‰แ…ณแ„แ…ฆแ†ท แ„€แ…ชแ†ซแ„…แ…ตPuppetแ„€แ…ช แ„Œแ…กแ„ƒแ…ฉแ†ผแ„’แ…ชแ„ƒแ…ฌแ†ซ แ„‰แ…ตแ„‰แ…ณแ„แ…ฆแ†ท แ„€แ…ชแ†ซแ„…แ…ต
Puppetแ„€แ…ช แ„Œแ…กแ„ƒแ…ฉแ†ผแ„’แ…ชแ„ƒแ…ฌแ†ซ แ„‰แ…ตแ„‰แ…ณแ„แ…ฆแ†ท แ„€แ…ชแ†ซแ„…แ…ต
ย 
Python server-101
Python server-101Python server-101
Python server-101
ย 
3D์นดํˆฐ๋ฉ”์ด์ปค ์™„๋ฃŒ์„ธ๋ฏธ๋‚˜(๋ณต๊ตฌ๋จ)
3D์นดํˆฐ๋ฉ”์ด์ปค ์™„๋ฃŒ์„ธ๋ฏธ๋‚˜(๋ณต๊ตฌ๋จ)3D์นดํˆฐ๋ฉ”์ด์ปค ์™„๋ฃŒ์„ธ๋ฏธ๋‚˜(๋ณต๊ตฌ๋จ)
3D์นดํˆฐ๋ฉ”์ด์ปค ์™„๋ฃŒ์„ธ๋ฏธ๋‚˜(๋ณต๊ตฌ๋จ)
ย 
Audio data preprocessing and data loading using torchaudio
Audio data preprocessing and data loading using torchaudioAudio data preprocessing and data loading using torchaudio
Audio data preprocessing and data loading using torchaudio
ย 
2023 GDG Sondo DevFest - Flutter/ Flavor, PlatformChannel, Environment variab...
2023 GDG Sondo DevFest - Flutter/ Flavor, PlatformChannel, Environment variab...2023 GDG Sondo DevFest - Flutter/ Flavor, PlatformChannel, Environment variab...
2023 GDG Sondo DevFest - Flutter/ Flavor, PlatformChannel, Environment variab...
ย 
Hyperledger Fabric practice (v2.0)
Hyperledger Fabric practice (v2.0) Hyperledger Fabric practice (v2.0)
Hyperledger Fabric practice (v2.0)
ย 
HTML5 & CSS3 - Video,Audio
HTML5 & CSS3 - Video,AudioHTML5 & CSS3 - Video,Audio
HTML5 & CSS3 - Video,Audio
ย 

More from Jae Sung Park

[SOSCON 2018] ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ: Behind the scenes
[SOSCON 2018] ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ: Behind the scenes[SOSCON 2018] ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ: Behind the scenes
[SOSCON 2018] ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ: Behind the scenesJae Sung Park
ย 
[DEVIEW 2018] JavaScript ๋ฐฐํ‹€๊ทธ๋ผ์šด๋“œ๋กœ๋ถ€ํ„ฐ ์‚ด์•„๋‚จ๊ธฐ
[DEVIEW 2018] JavaScript ๋ฐฐํ‹€๊ทธ๋ผ์šด๋“œ๋กœ๋ถ€ํ„ฐ ์‚ด์•„๋‚จ๊ธฐ[DEVIEW 2018] JavaScript ๋ฐฐํ‹€๊ทธ๋ผ์šด๋“œ๋กœ๋ถ€ํ„ฐ ์‚ด์•„๋‚จ๊ธฐ
[DEVIEW 2018] JavaScript ๋ฐฐํ‹€๊ทธ๋ผ์šด๋“œ๋กœ๋ถ€ํ„ฐ ์‚ด์•„๋‚จ๊ธฐJae Sung Park
ย 
[SOSCON 2017] แ„‚แ…ฆแ„‹แ…ตแ„‡แ…ฅแ„‹แ…ด FE แ„‹แ…ฉแ„‘แ…ณแ†ซแ„‰แ…ฉแ„‰แ…ณ: jindoแ„‹แ…ฆแ„‰แ…ฅ billboard.js๊นŒ์ง€
[SOSCON 2017] แ„‚แ…ฆแ„‹แ…ตแ„‡แ…ฅแ„‹แ…ด FE แ„‹แ…ฉแ„‘แ…ณแ†ซแ„‰แ…ฉแ„‰แ…ณ: jindoแ„‹แ…ฆแ„‰แ…ฅ billboard.js๊นŒ์ง€[SOSCON 2017] แ„‚แ…ฆแ„‹แ…ตแ„‡แ…ฅแ„‹แ…ด FE แ„‹แ…ฉแ„‘แ…ณแ†ซแ„‰แ…ฉแ„‰แ…ณ: jindoแ„‹แ…ฆแ„‰แ…ฅ billboard.js๊นŒ์ง€
[SOSCON 2017] แ„‚แ…ฆแ„‹แ…ตแ„‡แ…ฅแ„‹แ…ด FE แ„‹แ…ฉแ„‘แ…ณแ†ซแ„‰แ…ฉแ„‰แ…ณ: jindoแ„‹แ…ฆแ„‰แ…ฅ billboard.js๊นŒ์ง€Jae Sung Park
ย 
[DEVIEW 2017] 14์ผ๋งŒ์— GitHub ์Šคํƒ€ 1K ๋ฐ›์€ ์ฐจํŠธ ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ๊ธฐ
[DEVIEW 2017] 14์ผ๋งŒ์— GitHub ์Šคํƒ€ 1K ๋ฐ›์€ ์ฐจํŠธ ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ๊ธฐ[DEVIEW 2017] 14์ผ๋งŒ์— GitHub ์Šคํƒ€ 1K ๋ฐ›์€ ์ฐจํŠธ ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ๊ธฐ
[DEVIEW 2017] 14์ผ๋งŒ์— GitHub ์Šคํƒ€ 1K ๋ฐ›์€ ์ฐจํŠธ ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ๊ธฐJae Sung Park
ย 
Front end dev 2016 & beyond
Front end dev 2016 & beyondFront end dev 2016 & beyond
Front end dev 2016 & beyondJae Sung Park
ย 
[DEVIEW 2016] ๋„ค์ด๋ฒ„์˜ ๋ชจ๋˜ ์›น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - egjs
[DEVIEW 2016] ๋„ค์ด๋ฒ„์˜ ๋ชจ๋˜ ์›น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - egjs[DEVIEW 2016] ๋„ค์ด๋ฒ„์˜ ๋ชจ๋˜ ์›น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - egjs
[DEVIEW 2016] ๋„ค์ด๋ฒ„์˜ ๋ชจ๋˜ ์›น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - egjsJae Sung Park
ย 
ํ˜„์‹ค์  PWA
ํ˜„์‹ค์  PWAํ˜„์‹ค์  PWA
ํ˜„์‹ค์  PWAJae Sung Park
ย 
How jQuery event works
How jQuery event worksHow jQuery event works
How jQuery event worksJae Sung Park
ย 
iOS9 ์†Œ๊ฐœ
iOS9 ์†Œ๊ฐœiOS9 ์†Œ๊ฐœ
iOS9 ์†Œ๊ฐœJae Sung Park
ย 
ํ˜„์‹ค์  Angular js
ํ˜„์‹ค์  Angular jsํ˜„์‹ค์  Angular js
ํ˜„์‹ค์  Angular jsJae Sung Park
ย 
๊ฐ€๋ณ๊ฒŒ ์‚ดํŽด๋ณด๋Š” AngularJS
๊ฐ€๋ณ๊ฒŒ ์‚ดํŽด๋ณด๋Š” AngularJS๊ฐ€๋ณ๊ฒŒ ์‚ดํŽด๋ณด๋Š” AngularJS
๊ฐ€๋ณ๊ฒŒ ์‚ดํŽด๋ณด๋Š” AngularJSJae Sung Park
ย 
Web Components & Polymer
Web Components & PolymerWeb Components & Polymer
Web Components & PolymerJae Sung Park
ย 
๋ชจ๋ฐ”์ผ ์›น ๋””๋ฒ„๊น…
๋ชจ๋ฐ”์ผ ์›น ๋””๋ฒ„๊น…๋ชจ๋ฐ”์ผ ์›น ๋””๋ฒ„๊น…
๋ชจ๋ฐ”์ผ ์›น ๋””๋ฒ„๊น…Jae Sung Park
ย 
ํ˜์‹ ์ ์ธ ์›น์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - Polymer
ํ˜์‹ ์ ์ธ ์›น์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - Polymerํ˜์‹ ์ ์ธ ์›น์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - Polymer
ํ˜์‹ ์ ์ธ ์›น์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - PolymerJae Sung Park
ย 
CSS Functions
CSS FunctionsCSS Functions
CSS FunctionsJae Sung Park
ย 
์šฐ๋ฆฌ๊ฐ€ ๋ชฐ๋ž๋˜ ํฌ๋กฌ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ
์šฐ๋ฆฌ๊ฐ€ ๋ชฐ๋ž๋˜ ํฌ๋กฌ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์šฐ๋ฆฌ๊ฐ€ ๋ชฐ๋ž๋˜ ํฌ๋กฌ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ
์šฐ๋ฆฌ๊ฐ€ ๋ชฐ๋ž๋˜ ํฌ๋กฌ ๊ฐœ๋ฐœ์ž ๋„๊ตฌJae Sung Park
ย 
What's new in IE11
What's new in IE11What's new in IE11
What's new in IE11Jae Sung Park
ย 
์Šค๋งˆํŠธ TV ์•ฑ ๊ฐœ๋ฐœ ๋ง›๋ณด๊ธฐ
์Šค๋งˆํŠธ TV ์•ฑ ๊ฐœ๋ฐœ ๋ง›๋ณด๊ธฐ์Šค๋งˆํŠธ TV ์•ฑ ๊ฐœ๋ฐœ ๋ง›๋ณด๊ธฐ
์Šค๋งˆํŠธ TV ์•ฑ ๊ฐœ๋ฐœ ๋ง›๋ณด๊ธฐJae Sung Park
ย 
How to create Aptana Ruble
How to create Aptana RubleHow to create Aptana Ruble
How to create Aptana RubleJae Sung Park
ย 
Web Audio API
Web Audio APIWeb Audio API
Web Audio APIJae Sung Park
ย 

More from Jae Sung Park (20)

[SOSCON 2018] ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ: Behind the scenes
[SOSCON 2018] ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ: Behind the scenes[SOSCON 2018] ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ: Behind the scenes
[SOSCON 2018] ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ: Behind the scenes
ย 
[DEVIEW 2018] JavaScript ๋ฐฐํ‹€๊ทธ๋ผ์šด๋“œ๋กœ๋ถ€ํ„ฐ ์‚ด์•„๋‚จ๊ธฐ
[DEVIEW 2018] JavaScript ๋ฐฐํ‹€๊ทธ๋ผ์šด๋“œ๋กœ๋ถ€ํ„ฐ ์‚ด์•„๋‚จ๊ธฐ[DEVIEW 2018] JavaScript ๋ฐฐํ‹€๊ทธ๋ผ์šด๋“œ๋กœ๋ถ€ํ„ฐ ์‚ด์•„๋‚จ๊ธฐ
[DEVIEW 2018] JavaScript ๋ฐฐํ‹€๊ทธ๋ผ์šด๋“œ๋กœ๋ถ€ํ„ฐ ์‚ด์•„๋‚จ๊ธฐ
ย 
[SOSCON 2017] แ„‚แ…ฆแ„‹แ…ตแ„‡แ…ฅแ„‹แ…ด FE แ„‹แ…ฉแ„‘แ…ณแ†ซแ„‰แ…ฉแ„‰แ…ณ: jindoแ„‹แ…ฆแ„‰แ…ฅ billboard.js๊นŒ์ง€
[SOSCON 2017] แ„‚แ…ฆแ„‹แ…ตแ„‡แ…ฅแ„‹แ…ด FE แ„‹แ…ฉแ„‘แ…ณแ†ซแ„‰แ…ฉแ„‰แ…ณ: jindoแ„‹แ…ฆแ„‰แ…ฅ billboard.js๊นŒ์ง€[SOSCON 2017] แ„‚แ…ฆแ„‹แ…ตแ„‡แ…ฅแ„‹แ…ด FE แ„‹แ…ฉแ„‘แ…ณแ†ซแ„‰แ…ฉแ„‰แ…ณ: jindoแ„‹แ…ฆแ„‰แ…ฅ billboard.js๊นŒ์ง€
[SOSCON 2017] แ„‚แ…ฆแ„‹แ…ตแ„‡แ…ฅแ„‹แ…ด FE แ„‹แ…ฉแ„‘แ…ณแ†ซแ„‰แ…ฉแ„‰แ…ณ: jindoแ„‹แ…ฆแ„‰แ…ฅ billboard.js๊นŒ์ง€
ย 
[DEVIEW 2017] 14์ผ๋งŒ์— GitHub ์Šคํƒ€ 1K ๋ฐ›์€ ์ฐจํŠธ ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ๊ธฐ
[DEVIEW 2017] 14์ผ๋งŒ์— GitHub ์Šคํƒ€ 1K ๋ฐ›์€ ์ฐจํŠธ ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ๊ธฐ[DEVIEW 2017] 14์ผ๋งŒ์— GitHub ์Šคํƒ€ 1K ๋ฐ›์€ ์ฐจํŠธ ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ๊ธฐ
[DEVIEW 2017] 14์ผ๋งŒ์— GitHub ์Šคํƒ€ 1K ๋ฐ›์€ ์ฐจํŠธ ์˜คํ”ˆ์†Œ์Šค ๊ฐœ๋ฐœ๊ธฐ
ย 
Front end dev 2016 & beyond
Front end dev 2016 & beyondFront end dev 2016 & beyond
Front end dev 2016 & beyond
ย 
[DEVIEW 2016] ๋„ค์ด๋ฒ„์˜ ๋ชจ๋˜ ์›น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - egjs
[DEVIEW 2016] ๋„ค์ด๋ฒ„์˜ ๋ชจ๋˜ ์›น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - egjs[DEVIEW 2016] ๋„ค์ด๋ฒ„์˜ ๋ชจ๋˜ ์›น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - egjs
[DEVIEW 2016] ๋„ค์ด๋ฒ„์˜ ๋ชจ๋˜ ์›น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - egjs
ย 
ํ˜„์‹ค์  PWA
ํ˜„์‹ค์  PWAํ˜„์‹ค์  PWA
ํ˜„์‹ค์  PWA
ย 
How jQuery event works
How jQuery event worksHow jQuery event works
How jQuery event works
ย 
iOS9 ์†Œ๊ฐœ
iOS9 ์†Œ๊ฐœiOS9 ์†Œ๊ฐœ
iOS9 ์†Œ๊ฐœ
ย 
ํ˜„์‹ค์  Angular js
ํ˜„์‹ค์  Angular jsํ˜„์‹ค์  Angular js
ํ˜„์‹ค์  Angular js
ย 
๊ฐ€๋ณ๊ฒŒ ์‚ดํŽด๋ณด๋Š” AngularJS
๊ฐ€๋ณ๊ฒŒ ์‚ดํŽด๋ณด๋Š” AngularJS๊ฐ€๋ณ๊ฒŒ ์‚ดํŽด๋ณด๋Š” AngularJS
๊ฐ€๋ณ๊ฒŒ ์‚ดํŽด๋ณด๋Š” AngularJS
ย 
Web Components & Polymer
Web Components & PolymerWeb Components & Polymer
Web Components & Polymer
ย 
๋ชจ๋ฐ”์ผ ์›น ๋””๋ฒ„๊น…
๋ชจ๋ฐ”์ผ ์›น ๋””๋ฒ„๊น…๋ชจ๋ฐ”์ผ ์›น ๋””๋ฒ„๊น…
๋ชจ๋ฐ”์ผ ์›น ๋””๋ฒ„๊น…
ย 
ํ˜์‹ ์ ์ธ ์›น์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - Polymer
ํ˜์‹ ์ ์ธ ์›น์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - Polymerํ˜์‹ ์ ์ธ ์›น์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - Polymer
ํ˜์‹ ์ ์ธ ์›น์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - Polymer
ย 
CSS Functions
CSS FunctionsCSS Functions
CSS Functions
ย 
์šฐ๋ฆฌ๊ฐ€ ๋ชฐ๋ž๋˜ ํฌ๋กฌ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ
์šฐ๋ฆฌ๊ฐ€ ๋ชฐ๋ž๋˜ ํฌ๋กฌ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์šฐ๋ฆฌ๊ฐ€ ๋ชฐ๋ž๋˜ ํฌ๋กฌ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ
์šฐ๋ฆฌ๊ฐ€ ๋ชฐ๋ž๋˜ ํฌ๋กฌ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ
ย 
What's new in IE11
What's new in IE11What's new in IE11
What's new in IE11
ย 
์Šค๋งˆํŠธ TV ์•ฑ ๊ฐœ๋ฐœ ๋ง›๋ณด๊ธฐ
์Šค๋งˆํŠธ TV ์•ฑ ๊ฐœ๋ฐœ ๋ง›๋ณด๊ธฐ์Šค๋งˆํŠธ TV ์•ฑ ๊ฐœ๋ฐœ ๋ง›๋ณด๊ธฐ
์Šค๋งˆํŠธ TV ์•ฑ ๊ฐœ๋ฐœ ๋ง›๋ณด๊ธฐ
ย 
How to create Aptana Ruble
How to create Aptana RubleHow to create Aptana Ruble
How to create Aptana Ruble
ย 
Web Audio API
Web Audio APIWeb Audio API
Web Audio API
ย 

Developing game audio with the Web Audio API

  • 1. Developing game audio with the Web Audio API 2012_05_15 / nhn_๋ฐ•์žฌ์„ฑ
  • 2. Index ๏‚ง Web Audio API ๏‚ง Modular routing ๏‚ง Basic usage ๏‚ง Background Music ๏‚ง Sound effects ๏‚ง 3D Positional sound ๏‚ง Room effects and filters ๏‚ง Detect clipping
  • 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. Web Audio API ๏‚ง High-level JavaScript API for processing and synthesizing audio in web application. ๏ƒ  http://www.w3.org/TR/webaudio/ ๏‚ง AudioContext๋Š” ๋ชจ๋“  ์‚ฌ์šด๋“œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌ ๋ฐ ์žฌ์ƒํ•œ๋‹ค. ๏‚ง ์žฌ์ƒ์„ ์œ„ํ•ด์„  ์‚ฌ์šด๋“œ ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•œ ํ›„, AudioContext ์ธ์Šคํ„ด์Šค์™€ ์—ฐ๊ฒฐํ•ด์•ผ ํ•œ๋‹ค.
  • 5. Modular Routing ๏‚ง ์—ฐ๊ฒฐ์€ ๊ผญ ์ง์ ‘์ ์ผ ํ•„์š”๋Š” ์—†์œผ๋ฉฐ, ์ค‘๊ฐ„์— ์—ฌ๋Ÿฌ ๋‹จ๊ณ„์˜ AudioNode์™€ ์—ฐ๊ฒฐ(Modular Routing) ๋  ์ˆ˜ ์žˆ๋‹ค. ๏‚ง ์ด๋ฅผ ํ†ตํ•ด ์ค‘๊ฐ„ ๋‹จ๊ณ„์˜ AudioNode๋ฅผ ํ†ตํ•ด ์Œ๋Ÿ‰ ์กฐ์ •, ํ•„ํ„ฐ ์ ์šฉ ๋“ฑ์„ ์ฒ˜๋ฆฌ ํ•˜๊ฒŒ ๋œ๋‹ค.
  • 6. ๋ธŒ๋ผ์šฐ์ € ์ง€์› ์—ฌ๋ถ€ ๏‚ง ์‚ฌ์šฉํ•˜๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ audio ์ง€์›๊ณผ ๋ฒ”์œ„๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ๏ƒ  http://areweplayingyet.org/ Source : http://caniuse.com/audio-api
  • 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. 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. Background music ๏‚ง ๋ฐ˜๋ณต์ ์ด๊ณ  ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ BGM์€ ๋ถˆํŽธ๊ณผ ์งœ์ฆ์„ ์œ ๋ฐœํ•  ์ˆ˜ ์žˆ๋‹ค. ๏‚ง ํŠน์ • ์‹œ์ (๋งˆ์ง€๋ง‰ ๋ณด์Šค์™€์˜ ๋Œ€๊ฒฐ๊ณผ ๊ฐ™์€)์— BGM๋„ ๊ทธ์— ๋”ฐ๋ผ ๊ฐ์„ฑ์ ์œผ๋กœ ๋ฐ˜์˜์ด ๋˜์–ด์•ผ ํ•œ๋‹ค. ๏‚ง ์—ฌ๋Ÿฌ ์‚ฌ์šด๋“œ์˜ ๋ฏน์‹ฑ์€ ์Œ์•… ํ”„๋กœ๊ทธ๋žจ์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ์ ์ธ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜์ด๋‹ค. ๏‚ง Web Audio API๋ฅผ ํ™œ์šฉํ•ด XHR๋กœ ์ƒํ™ฉ์— ๋งž๋Š” ์†Œ์Šค๋ฅผ ๋กœ๋”ฉํ•ด ์žฌ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๏ƒ  ๋กœ๋”ฉ์€ ์‹œ๊ฐ„์ด ์†Œ์š”๋˜๋ฏ€๋กœ, ์ตœ์ดˆ ํŽ˜์ด์ง€ ๋กœ๋”ฉ์‹œ ๋˜๋Š” ๊ฒŒ์ž„ ์ง„ํ–‰ ์ค‘ ์ ์ง„์ ์œผ๋กœ ๋กœ๋”ฉ์„ ํ•˜๋„๋ก ํ•œ๋‹ค.
  • 10. Background music ๏‚ง ์‚ฌ์šฉ๋  ๊ฐ ๋…ธ๋“œ๋“ค์— ๋Œ€ํ•œ ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฅผ ์—ฐ๊ฒฐํ•œ๋‹ค. ๏‚ง ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์‚ฌ์šด๋“œ๊ฐ€ ๋ฐ˜๋ณต ์žฌ์ƒ๋˜๋Š” ์ƒํƒœ์—์„œ, ํŠน์ • ์žฅ๋ฉด์— ์‚ฌ์šฉ๋˜๋Š” ์‚ฌ์šด๋“œ์˜ ์Œ๋Ÿ‰์„ ํ‚ค์šฐ๊ณ  ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” ์‚ฌ์šด๋“œ์˜ ์Œ๋Ÿ‰์„ ์ค„์—ฌ cross-fade ํ•œ๋‹ค.
  • 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. 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. 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. 3D Positional sound ๏‚ง Positional model์€ OpenAL(Open Audio Library)์— ๊ธฐ๋ฐ˜ํ•œ๋‹ค. ๏ƒ  Distance model์€ ์†Œ์Šค๋กœ๋ถ€ํ„ฐ์˜ ๊ฑฐ๋ฆฌ์— ๋”ฐ๋ผ gain ๊ฐ’์„ ๋‹ค๋ฅด๊ฒŒ ๊ฐ–๋Š”๋‹ค. ๏ƒ  Directional model์€ ์™ธ๋ถ€ ๋˜๋Š” ๋‚ด๋ถ€ ๋ฐฉํ–ฅ์— ๋”ฐ๋ผ gain ๊ฐ’์„ ๋‹ค๋ฅด๊ฒŒ ๊ฐ–๋Š”๋‹ค.
  • 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. 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. 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. ๋ช‡ ๊ฐ€์ง€ ๊ธฐ์–ตํ•  ์‚ฌํ•ญ ๏‚ง ์‹œ๊ทธ๋„์ด ๋ถ€๋“œ๋Ÿฝ๊ณ  ํŠ€์ง€ ์•Š๋„๋ก DynamicCompressorNode๋ฅผ ํ™œ์šฉํ•˜๋ผ. ๏‚ง ํŽ˜์ด์ง€๊ฐ€ ๋ณด์ด์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์—๋Š” pageVisibility API๋ฅผ ํ™œ์šฉํ•ด ๋ถˆํ•„์š”ํ•œ ์‚ฌ์šด๋“œ ์žฌ์ƒ์„ ๋ง‰๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.