64
2013.11.30 WebAudioAPI 実践的 プログラミング 藍 圭介 Practical Web Audio API Programming Ai Keisuke CC BY Temari 09 http://www.flickr.com/photos/34053291@N05/4658010136/ @aike1000 小樽商科大学

Practical Web Audio API Programming

  • Upload
    aike

  • View
    3.765

  • Download
    13

Embed Size (px)

DESCRIPTION

HTML5 Conference 2013 http://aikelab.net/webaudiodemo https://github.com/aike/webaudiodemo

Citation preview

Page 1: Practical Web Audio API Programming

2013.11.30

WebAudioAPI実践的プログラミング

藍 圭介

Practical Web Audio API Programming

Ai KeisukeCC BY Temari 09 http://www.flickr.com/photos/34053291@N05/4658010136/

@aike1000小樽商科大学

Page 2: Practical Web Audio API Programming

誰?

Page 3: Practical Web Audio API Programming

今日話すこと

•Web Audio APIは何がすごいのか?

•簡単なプログラミング例

•はまりやすい落とし穴

•楽器アプリ作ってみる

Page 4: Practical Web Audio API Programming

Web Audio APIは何がすごいのか?

Page 8: Practical Web Audio API Programming

WebAudioSynthアナログモデリングシンセ

http://aikelab.net/websynth

Page 9: Practical Web Audio API Programming

PG01Webメタルギターサンプリング音源

http://aikelab.net/pg01/

Page 10: Practical Web Audio API Programming

Beatonicaソーシャルグラフで音楽自動生成

http://beatonica.com/

Page 11: Practical Web Audio API Programming

でも、ウェブで音を鳴らすのって

前からあったよね?

Page 12: Practical Web Audio API Programming

<EMBED SRC="○○.mid">

FlashJava Applet

<Audio SRC=”○○.mp3”>

Page 13: Practical Web Audio API Programming

これらは基本的に、サウンド再生プログラムをブラックボックス化してHTMLに埋め込んでいたに過ぎない

CC BY-NC-SA Peter Dutton http://www.flickr.com/photos/joeshlabotnik/7778898726/

Page 14: Practical Web Audio API Programming

Web Audio API

http://www.w3.org/TR/webaudio/

Page 15: Practical Web Audio API Programming

ウェブブラウザが直接サポートする音声信号処理API

CC BY-ND Hector Lazo http://www.flickr.com/photos/hector-lazo/3101873296/

Page 16: Practical Web Audio API Programming

Web Audio API

•音そのものをJavaScriptで直接操作

•プラグイン不要で環境依存しにくい

•由緒正しい(W3C)

•注目度が高く進化が速い

CC BY-ND Hector Lazo http://www.flickr.com/photos/hector-lazo/4109744948/

Page 17: Practical Web Audio API Programming

モジュール指向

• オシレーター• オーディオバッファソース• ゲイン• フィルター• ディレイ• スクリプトプロセッサー

CC BY-NC cutwithflourish http://www.flickr.com/photos/26735065@N00/4229039436/

• パン• コンプレッサー• コンボルバー• アナライザー• ウェーブシェイパー

モジュール同士を接続してプログラミング

等のモジュールが用意されている

Page 18: Practical Web Audio API Programming

これによって何が変わるの?

Page 19: Practical Web Audio API Programming

これまでできなかった何かができるようになる

サウンドプログラミングのハードルが飛躍的に下がる!

Page 20: Practical Web Audio API Programming

Web Audio API• 特殊な開発環境不要

• 必要なのは普通のブラウザだけ

• 無料

• コンパイル不要

• 速いデバッグサイクルで試行錯誤しやすい

• 特殊な実行環境不要

• メールやウェブで共有した相手も同じ音が聞ける

Page 21: Practical Web Audio API Programming

サウンドプログラミング

の自由化

Public Domain Eugène_Delacroix http://en.wikipedia.org/wiki/Liberty_Leading_the_People

Page 22: Practical Web Audio API Programming

誰でも今すぐサウンド

プログラミングが始められる!

Page 23: Practical Web Audio API Programming

簡単なプログラミング例

Page 24: Practical Web Audio API Programming

オシレーターで音を出してみる

var ctx = new webkitAudioContext(); var osc = ctx.createOscillator(); osc.type = 1; // 矩形波 osc.connect(ctx.destination); osc.start(0);

http://aikelab.net/webaudiodemo/osc1/

Page 25: Practical Web Audio API Programming

CC BY-NC-SA Timothy Hart http://www.flickr.com/photos/tmhart/6229873723/

やかましい

Page 26: Practical Web Audio API Programming

ゲインノードで音量ダウン

var ctx = new webkitAudioContext(); var osc = ctx.createOscillator(); osc.type = 1; var vol = ctx.createGain(); vol.gain.value = 0.2; // 0.0 ~ 1.0

osc.connect(vol); vol.connect(ctx.destination) osc.start(0);

http://aikelab.net/webaudiodemo/osc2/

Page 27: Practical Web Audio API Programming

wavファイルを再生するBufferSource

CC BY Jason Ralston http://www.flickr.com/photos/jasonrphotography/2885155839/

Page 28: Practical Web Audio API Programming

var loadwav = function(file, callback) { var xhr = new XMLHttpRequest(); xhr.open("GET", file, true); xhr.responseType = "arraybuffer"; xhr.onload = function() { ctx.decodeAudioData(xhr.response,function(buf){ callback(buf); }, function(){}); }; xhr.send();}

wavファイルを再生(1/2)XHRでサーバからwavファイルを取得する関数

Page 29: Practical Web Audio API Programming

var kacha; loadwav('kacha.wav', function(buf) { kacha = buf; });

wavファイルを再生(2/2)このloadwav関数でwavをバッファに読み込み

var src = ctx.createBufferSource(); src.buffer = kacha; src.connect(ctx.destination); src.start(0);

BufferSourceを生成してバッファを指定(毎回必要)

Page 30: Practical Web Audio API Programming

キーを押すたびにwavを再生

window.document.onkeyup = function(evt){ var src = ctx.createBufferSource(); if (evt.keyCode == 13) src.buffer = tan; // returnキーは「ターン」 else src.buffer = kacha; // 他のキーは「カチャ」 src.connect(ctx.destination); src.start(0); return false;}

http://aikelab.net/webaudiodemo/kachatan/

Page 31: Practical Web Audio API Programming

WebRTCでマイク入力した音声を加工する

CC BY-NC-ND National Film and Sound Archive Australia http://www.flickr.com/photos/nfsa/4580070895/

Page 32: Practical Web Audio API Programming

マイク入力の基本

var audioproc = function(stream) { var mic = ctx.createMediaStreamSource(stream); mic.connect(delay); delay.connect(ctx.destination);};

navigator.webkitGetUserMedia({audio : true}, audioproc, function(e) { console.log(e); });

GetUserMedia()の第2引数に関数を渡す渡した関数でMediaStreamSourceノード生成

Page 33: Practical Web Audio API Programming

ディレイは声が遅れて聞こえるよ

でもなんか違くない?

MediaStreamSource(Mic)

Delay destination

http://aikelab.net/webaudiodemo/delay1/

Page 34: Practical Web Audio API Programming

ディレイとゲインでフィードバックループを作る

MediaStreamSource(Mic)

Delay destinationGain

Dry

Wet

Feedback

var mic = ctx.createMediaStreamSource(stream); mic.connect(delay); mic.connect(ctx.destination); delay.connect(gain); gain.connect(delay); gain.connect(ctx.destination);

http://aikelab.net/webaudiodemo/delay2/

Page 35: Practical Web Audio API Programming

コンボルバーで簡単リバーブ

var convolver = ctx.createConvolver(); var xhr = new XMLHttpRequest(); xhr.open("GET", "ir.wav", true); xhr.responseType = "arraybuffer"; xhr.onload = function() { ctx.decodeAudioData(xhr.response,function(buf){ convolver.buffer = buf; }, function(){}); }; xhr.send();

XHRでサーバからIRファイルを取得して設定

http://aikelab.net/webaudiodemo/reverb/

Page 36: Practical Web Audio API Programming

IRファイルとは、実在の残響音の特徴をwavファイル

として記録したもの

Page 37: Practical Web Audio API Programming

ある日のIR収録風景

Page 38: Practical Web Audio API Programming

波形を直接加工するScriptProcessor

CC BY-NC thaths http://www.flickr.com/photos/thaths/5852964925/

Page 39: Practical Web Audio API Programming

みんな大好きディストーション

var fuzz = ctx.createScriptProcessor(1024, 1, 1);fuzz.onaudioprocess = function(event) { var sin = event.inputBuffer.getChannelData(0); var sout = event.outputBuffer.getChannelData(0); var limit = 0.2; for (var i = 0; i < sin.length; i++) { var sig = sin[i] * 6; // Boost if (sig > limit) sig = limit; // Clip if (sig < -limit) sig = -limit; // Clip sout[i] = sig; }};

波形をブーストしてからクリップ

http://aikelab.net/webaudodemo/fuzz/

Page 40: Practical Web Audio API Programming

FFTでピッチチェンジャーvar pshift = function(val, indata) { this.fft.forward(indata); for (var i = 0; i < stream_length; i++) { a_real[i] = 0; a_imag[i] = 0; } for (var i = 0; i < stream_length; i++) { var index = parseInt(i * val); var eq = 1.0; if (i > stream_length / 2) { eq = 0; } if ((index >= 0) && (index < stream_length)) { a_real[index] += fft.real[i] * eq; a_imag[index] += fft.imag[i] * eq; } } return this.fft.inverse(this.a_real, this.a_imag);}

pitchShifter.onaudioprocess = function(event) { var sin = event.inputBuffer.getChannelData(0); var sout = event.outputBuffer.getChannelData(0); var data = pshift(2.0, sin); for (var i = 0; i < sin.length; i++) { sout[i] = data[i]; }};

https://github.com/corbanbrook/dsp.js/

DSP.js by cobanbrook

http://aikelab.net/webaudiodemo/pitch/

Page 41: Practical Web Audio API Programming

CC BY-NC-SA @notnixon http://www.flickr.com/photos/sansbury/3274031514/

はまりやすい落とし穴

Page 42: Practical Web Audio API Programming

OscillatorやBufferSourceは

1音鳴らすごとに使い捨て

Page 43: Practical Web Audio API Programming

wav,mp3ファイルを鳴らすにはWeb

サーバが必要

Page 44: Practical Web Audio API Programming

ベンダープレフィックス問題

window.AudioContext = window.AudioContext || window.webkitAudioContext;

var ctx = new AudioContext();

var ctx = new webkitAudioContext();

var ctx = new AudioContext();

Page 45: Practical Web Audio API Programming

旧API名問題

createJavaScriptNode

createGainNode

createDelayNode

createScriptProcessor

createGain

createDelay

Page 46: Practical Web Audio API Programming

Panが3次元

pan.setPosition( 1.0, 0, -1.0);

pan.setPosition(-1.0, 0, -1.0);

手軽な2次元Panを作るのはけっこう面倒だったり

こうするとそれっぽいけど普通の2次元Panとは微妙に違う

参考 http://www.g200kg.com/jp/docs/webaudio/panner.html

Page 47: Practical Web Audio API Programming

テストしづらい

•上限値、下限値のチェックなど音になる前のおおまかな検証は可能

•本当に意図した音色(波形)になっているかの自動チェックは難しい

Page 48: Practical Web Audio API Programming

バッドノウハウ集•ScriptProcessorの入力数0はNG

•特にiOSの場合ダミーで手前にBufferSourceを接続する必要あり

• iOSでは音を鳴らす前にユーザーのアクションが必須

• IRファイルは48kHzステレオのみ

※これらはAPIのバージョンアップによって今後変わる可能性もあります

Page 49: Practical Web Audio API Programming

楽器アプリ作ってみる

Page 50: Practical Web Audio API Programming

マルチトラックシーケンサー

CC BY-NC-SA Matthew Davidson http://www.flickr.com/photos/stretta/531963218/

Page 51: Practical Web Audio API Programming

簡易シーケンサーの作成 (ドラム音源)

var Drum = function(ctx) { this.ctx = ctx;

this.vol = ctx.createGain(); this.vol.gain.value = 0.4; this.vol.connect(ctx.destination);

this.kick = null; this.hat = null; var self = this; loadwav('wav/kick.wav', function(buf) { self.kick = buf; }); loadwav('wav/hat.wav', function(buf) { self.hat = buf; });}

ゲイン生成、wavファイル読み込み

Page 52: Practical Web Audio API Programming

簡易シーケンサーの作成 (ドラム音源)

Drum.prototype.play = function(n, tim) { if (n % 4 == 0) { var src = ctx.createBufferSource(); src.buffer = this.kick; src.connect(this.vol); src.start(tim); } if (n % 4 == 2) { var src = ctx.createBufferSource(); src.buffer = this.hat; src.connect(this.vol); src.start(tim); }}

16分音符4回ごとにBufferSource生成、キック、ハットを鳴らす

http://aikelab.net/webaudiodemo/seq1/

Page 53: Practical Web Audio API Programming

簡易シーケンサーの作成 (ベース音源)

var Bass = function(ctx) { this.ctx = ctx; this.vol = ctx.createGain(); // Gain Node this.vol.gain.value = 0.3; this.vol.connect(ctx.destination); this.seq = [ 33, 33, 40, 33, 33, 40, 33, 33, 33, 33, 40, 33, 33, 40, 33, 33, 31, 31, 31, 38, 38, 31, 31, 38, 29, 29, 36, 29, 36, 29, 29, 29 ];}

ゲインの生成、MIDIノートナンバーでシーケンス設定

Page 54: Practical Web Audio API Programming

簡易シーケンサーの作成 (ベース音源)

Bass.prototype.play = function(n, tim) { var osc = ctx.createOscillator(); osc.type = 2; // ノコギリ波 osc.frequency.value = 440.0 * Math.pow(2.0, (this.seq[n % 32] - 69.0) / 12.0); osc.connect(this.vol); osc.start(tim); osc.stop(tim + 0.08); }

毎回オシレーターノード生成MIDIノートナンバーから周波数算出

http://aikelab.net/webaudiodemo/seq2/

Page 55: Practical Web Audio API Programming

簡易シーケンサーの作成 (シンセ音源その1)

this.seq = [69, 72, 76, 74, 71, 69, 72, 76];}

Synth.prototype.play = function(n, tim) { var osc = ctx.createOscillator(); osc.type = 2; // ノコギリ波 osc.frequency.value = 440.0 * Math.pow(2.0, (this.seq[n % 32] - 69.0) / 12.0); osc.connect(this.vol); osc.start(tim); osc.stop(tim + 0.10); }

シーケンスが違うだけでベース音源とほぼ同じ

http://aikelab.net/webaudiodemo/seq3/

Page 56: Practical Web Audio API Programming

簡易シーケンサーの作成 (シンセ音源その2)

this.delay = ctx.createDelay(); this.delay.delayTime.value = 0.2; this.feedback = ctx.createGain(); this.feedback.gain.value = 0.3;

this.vol.connect(ctx.destination); this.vol.connect(this.delay); this.delay.connect(this.feedback); this.feedback.connect(this.delay); this.feedback.connect(ctx.destination);

ディレイを追加

http://aikelab.net/webaudiodemo/seq4/

Page 57: Practical Web Audio API Programming

簡易シーケンサーの作成 (シンセ音源その3)

Synth.prototype.play = function(n, tim) { for (i = 0; i < 3; i++) { // 3 Oscillators var osc = ctx.createOscillator(); osc.type = 2; var detune = 3 * i; // 3Hz周波数をずらす osc.frequency.value = 440.0 * Math.pow(2.0, (this.seq[n % 8] - 69.0) / 12.0) + detune; osc.connect(this.vol); osc.start(tim); osc.stop(tim + 0.10); }}

周波数をずらしたオシレーターを3個重ねる

http://aikelab.net/webaudiodemo/seq5/

Page 58: Practical Web Audio API Programming

簡易シーケンサーの作成 (シンセ音源その4)

this.lpf = ctx.createBiquadFilter(); this.lpf.type = 0; // LPF this.lpf.Q.value = 20; this.lpf.frequency.value = 4000; this.angle = 0.0; var self = this; this.lfo = function() { self.angle += 0.1; if (self.angle > 2 * Math.PI) self.angle -= 2 * Math.PI; self.lpf.frequency.value = 4000 + Math.sin(self.angle) * 3000; } setInterval(this.lfo, 100);

フィルターを追加してLFOでゆっくり動かす

http://aikelab.net/webaudiodemo/seq6/

Page 59: Practical Web Audio API Programming

できた。

Page 60: Practical Web Audio API Programming

簡易シーケンサーの作成 (完成版)

var drum = new Drum(ctx);var bass = new Bass(ctx);var synth = new Synth(ctx);

var play = function() { var t = ctx.currentTime; for (var i = 0; i < 128; i++) { t += 0.1; drum.play(i, t); bass.play(i, t); synth.play(i, t); }}

全部鳴らす

http://aikelab.net/webaudiodemo/seq7/

Page 61: Practical Web Audio API Programming

GUIをつけてパターンを選べるようにすれば

本格的な楽器になります

Page 62: Practical Web Audio API Programming

WebrhyGUIをつけてパターンを選べるようにしたらこんな感じ

http://aikelab.net/webrhy/

Page 63: Practical Web Audio API Programming

あとは自由な発想で音楽をハックするだけ

Public Domain Eugène_Delacroix http://en.wikipedia.org/wiki/Liberty_Leading_the_People