MIDIチュートリアル:MIDIハードウェアによって制御されるブラウザベースのオーディオアプリケーションの作成

公開: 2022-03-11

特にHTML5ゲーム開発者の間でWebAudioAPIの人気が高まっている一方で、WebMIDIAPIはフロントエンド開発者の間ではまだほとんど知られていません。 これの大部分は、おそらく現在のサポートの欠如とアクセス可能なドキュメントに関係しています。 Web MIDI APIは現在、Google Chromeでのみサポートされており、特別なフラグを有効にする必要があります。 ブラウザメーカーは、ES7標準の一部になる予定であるため、現在このAPIにほとんど重点を置いていません。

80年代初頭にいくつかの音楽業界の代表者によって設計されたMIDI(Musical Instrument Digital Interfaceの略)は、電子音楽デバイスの標準的な通信プロトコルです。 それ以来、OSCなどの他のプロトコルが開発されていますが、 30年経った今でも、MIDIはオーディオハードウェアメーカーにとって事実上の通信プロトコルです。 スタジオで少なくとも1つのMIDIデバイスを所有していない現代の音楽プロデューサーを見つけるのは難しいでしょう。

Web Audio APIの迅速な開発と採用により、クラウドと物理的な世界の間のギャップを埋めるブラウザーベースのアプリケーションの構築を開始できるようになりました。 Web MIDI APIを使用すると、シンセサイザーやオーディオエフェクトを構築できるだけでなく、現在のフラッシュベースの対応するものと同様の機能とパフォーマンスを備えたブラウザーベースのDAW(デジタルオーディオワークステーション)の構築を開始することもできます(たとえば、Audiotoolをチェックしてください)。 )。

このMIDIチュートリアルでは、Web MIDI APIの基本を説明し、お気に入りのMIDIデバイスで再生できる簡単なモノシンセを作成します。 完全なソースコードはここから入手でき、ライブデモを直接テストできます。 MIDIデバイスをお持ちでない場合でも、GitHubリポジトリの「keyboard」ブランチをチェックしてこのチュートリアルに従うことができます。これにより、コンピューターのキーボードの基本的なサポートが可能になり、ノートを再生したり、オクターブを変更したりできます。 これは、ライブデモとして利用できるバージョンでもあります。 ただし、コンピューターハードウェアの制限により、コンピューターのキーボードを使用してシンセサイザーを制御する場合は、ベロシティとデチューンの両方が無効になります。 キー/ノートのマッピングについては、GitHubのreadmeファイルを参照してください。

ToptalのMIDIチュートリアル

MIDIチュートリアルの前提条件

このMIDIチュートリアルには、次のものが必要です。

  • #enable-web-midiフラグが有効になっているGoogle Chrome(バージョン38以降)
  • (オプション)コンピューターに接続された、ノートをトリガーできるMIDIデバイス

また、Angular.jsを使用して、アプリケーションに少し構造を持たせます。 したがって、フレームワークの基本的な知識が前提条件です。

入門

MIDIアプリケーションを3つのモジュールに分割することにより、ゼロからモジュール化します。

  • WebMIDI:コンピューターに接続されているさまざまなMIDIデバイスの処理
  • WebAudio:シンセのオーディオソースを提供します
  • WebSynth:Webインターフェイスをオーディオエンジンに接続する

Appモジュールは、Webユーザーインターフェイスとのユーザーインタラクションを処理します。 アプリケーションの構造は次のようになります。

 |- app |-- js |--- midi.js |--- audio.js |--- synth.js |--- app.js |- index.html

また、アプリケーションの構築に役立つ次のライブラリをインストールする必要があります:Angular.js、Bootstrap、およびjQuery。 おそらく、これらをインストールする最も簡単な方法は、Bowerを使用することです。

WebMIDIモジュール:実世界との接続

MIDIデバイスをアプリケーションに接続してMIDIの使用方法を理解しましょう。 そのために、単一のメソッドを返す単純なファクトリを作成します。 Web MIDI APIを介してMIDIデバイスに接続するには、 navigator.requestMIDIAccessメソッドを呼び出す必要があります。

 angular .module('WebMIDI', []) .factory('Devices', ['$window', function($window) { function _connect() { if($window.navigator && 'function' === typeof $window.navigator.requestMIDIAccess) { $window.navigator.requestMIDIAccess(); } else { throw 'No Web MIDI support'; } } return { connect: _connect }; }]);

そして、それはほとんどそれです!

requestMIDIAccessメソッドはpromiseを返すので、それを直接返し、アプリのコントローラーでpromiseの結果を処理できます。

 angular .module('DemoApp', ['WebMIDI']) .controller('AppCtrl', ['$scope', 'Devices', function($scope, devices) { $scope.devices = []; devices .connect() .then(function(access) { if('function' === typeof access.inputs) { // deprecated $scope.devices = access.inputs(); console.error('Update your Chrome version!'); } else { if(access.inputs && access.inputs.size > 0) { var inputs = access.inputs.values(), input = null; // iterate through the devices for (input = inputs.next(); input && !input.done; input = inputs.next()) { $scope.devices.push(input.value); } } else { console.error('No devices detected!'); } } }) .catch(function(e) { console.error(e); }); }]);

前述のように、 requestMIDIAccessメソッドはpromiseを返し、入力と出力の2つのプロパティを持つオブジェクトをthenメソッドに渡します。

Chromeの以前のバージョンでは、これら2つのプロパティは、入力デバイスと出力デバイスの配列を直接取得できるメソッドでした。 ただし、最新の更新では、これらのプロパティはオブジェクトになりました。 対応するデバイスのリストを取得するには、入力オブジェクトまたは出力オブジェクトのいずれかでvaluesメソッドを呼び出す必要があるため、これはかなりの違いになります。 このメソッドはジェネレーター関数として機能し、イテレーターを返します。 繰り返しますが、このAPIはES7の一部であることが意図されています。 したがって、ジェネレータのような動作を実装することは、元の実装ほど単純ではありませんが、理にかなっています。

最後に、イテレータオブジェクトのsizeプロパティを介してデバイスの数を取得できます。 少なくとも1つのデバイスがある場合は、イテレータオブジェクトのnextメソッドを呼び出し、各デバイスを$ scopeで定義された配列にプッシュすることで、結果を反復処理するだけです。 フロントエンドでは、使用可能なすべての入力デバイスを一覧表示する単純な選択ボックスを実装し、Webシンセを制御するためのアクティブデバイスとして使用するデバイスを選択できます。

 <select ng-model="activeDevice" class="form-control" ng-options="device.manufacturer + ' ' + device.name for device in devices"> <option value="" disabled>Choose a MIDI device...</option> </select>

この選択ボックスをactiveDeviceという$scope変数にバインドしました。この変数は、後でこのアクティブデバイスをシンセに接続するために使用します。

このアクティブなデバイスをシンセに接続します

WebAudioモジュール:ノイズを出す

WebAudio APIを使用すると、サウンドファイルを再生できるだけでなく、オシレーター、フィルター、ゲインノードなどのシンセサイザーの重要なコンポーネントを再作成することでサウンドを生成することもできます。

オシレーターを作成する

オシレーターの役割は、波形を出力することです。 波形にはさまざまな種類があり、そのうち4つがWebAudio APIでサポートされています。正弦、正方形、三角形、鋸歯です。 波形は特定の周波数で「振動」すると言われていますが、必要に応じて独自のカスタムウェーブテーブルを定義することもできます。 ある範囲の周波数は人間が聞くことができます-それらは音として知られています。 あるいは、低周波数で振動している場合、オシレーターはLFO(「低周波数オシレーター」)の構築にも役立ち、サウンドを変調できます(ただし、これはこのチュートリアルの範囲を超えています)。

サウンドを作成するために最初に行う必要があるのは、新しいAudioContextをインスタンス化することです。

 function _createContext() { self.ctx = new $window.AudioContext(); }

そこから、WebAudioAPIによって利用可能になったコンポーネントをインスタンス化できます。 各コンポーネントの複数のインスタンスを作成する可能性があるため、必要なコンポーネントの新しい一意のインスタンスを作成できるようにサービスを作成することは理にかなっています。 新しいオシレーターを生成するサービスを作成することから始めましょう。

 angular .module('WebAudio', []) .service('OSC', function() { var self; function Oscillator(ctx) { self = this; self.osc = ctx.createOscillator(); return self; } });

これで、前に作成したAudioContextインスタンスを引数として渡して、新しいオシレーターを自由にインスタンス化できます。 今後の作業を簡単にするために、いくつかのラッパーメソッド(単なる構文糖衣)を追加し、Oscillator関数を返します。

 Oscillator.prototype.setOscType = function(type) { if(type) { self.osc.type = type } } Oscillator.prototype.setFrequency = function(freq, time) { self.osc.frequency.setTargetAtTime(freq, 0, time); }; Oscillator.prototype.start = function(pos) { self.osc.start(pos); } Oscillator.prototype.stop = function(pos) { self.osc.stop(pos); } Oscillator.prototype.connect = function(i) { self.osc.connect(i); } Oscillator.prototype.cancel = function() { self.osc.frequency.cancelScheduledValues(0); } return Oscillator;

マルチパスフィルターとボリュームコントロールを作成する

基本的なオーディオエンジンを完成させるには、さらに2つのコンポーネントが必要です。サウンドに少し形を与えるマルチパスフィルターと、サウンドの音量を制御して音量のオンとオフを切り替えるゲインノードです。 これを行うには、オシレーターの場合と同じ方法で続行できます。いくつかのラッパーメソッドを使用して関数を返すサービスを作成します。 必要なのは、AudioContextインスタンスを提供し、適切なメソッドを呼び出すことだけです。

AudioContextインスタンスのcreateBiquadFilterメソッドを呼び出して、フィルターを作成します。

 ctx.createBiquadFilter();

同様に、ゲインノードの場合、 createGainメソッドを呼び出します。

 ctx.createGain();

WebSynthモジュール:配線

これで、シンセインターフェイスを構築し、MIDIデバイスをオーディオソースに接続する準備がほぼ整いました。 まず、オーディオエンジンを接続して、MIDIノートを受信できるようにする必要があります。 オーディオエンジンを接続するには、必要なコンポーネントの新しいインスタンスを作成し、各コンポーネントのインスタンスで使用可能なconnect方法を使用してそれらを「接続」するだけです。 connectメソッドは1つの引数を取ります。これは、現在のインスタンスを接続するコンポーネントです。 connectメソッドは1つのノードを複数のモジュレーターに接続できるため、より複雑なコンポーネントのチェーンを調整することができます(クロスフェードなどの実装が可能になります)。

 self.osc1 = new Oscillator(self.ctx); self.osc1.setOscType('sine'); self.amp = new Amp(self.ctx); self.osc1.connect(self.amp.gain); self.amp.connect(self.ctx.destination); self.amp.setVolume(0.0, 0); //mute the sound self.filter1.disconnect(); self.amp.disconnect(); self.amp.connect(self.ctx.destination); }

オーディオエンジンの内部配線を構築しました。 少し遊んで、配線のさまざまな組み合わせを試すことができますが、耳が聞こえなくなるのを避けるために音量を下げることを忘れないでください。 これで、MIDIインターフェイスをアプリケーションに接続し、MIDIメッセージをオーディオエンジンに送信できます。 デバイス選択ボックスにウォッチャーをセットアップして、シンセに仮想的に「プラグイン」します。 次に、デバイスからのMIDIメッセージをリッスンし、その情報をオーディオエンジンに渡します。

 // in the app's controller $scope.$watch('activeDevice', DSP.plug); // in the synth module function _onmidimessage(e) { /** * e.data is an array * e.data[0] = on (144) / off (128) / detune (224) * e.data[1] = midi note * e.data[2] = velocity || detune */ switch(e.data[0]) { case 144: Engine.noteOn(e.data[1], e.data[2]); break; case 128: Engine.noteOff(e.data[1]); break; } } function _plug(device) { self.device = device; self.device.onmidimessage = _onmidimessage; }

ここでは、デバイスからMIDIイベントをリッスンし、MidiEventオブジェクトからのデータを分析して、適切なメソッドに渡します。 イベントコードに基づいて、 noteOnまたはnoteOffのいずれか(noteOnの場合は144、noteOffの場合は128)。 これで、オーディオモジュールのそれぞれのメソッドにロジックを追加して、実際にサウンドを生成できます。

 function _noteOn(note, velocity) { self.activeNotes.push(note); self.osc1.cancel(); self.currentFreq = _mtof(note); self.osc1.setFrequency(self.currentFreq, self.settings.portamento); self.amp.cancel(); self.amp.setVolume(1.0, self.settings.attack); } function _noteOff(note) { var position = self.activeNotes.indexOf(note); if (position !== -1) { self.activeNotes.splice(position, 1); } if (self.activeNotes.length === 0) { // shut off the envelope self.amp.cancel(); self.currentFreq = null; self.amp.setVolume(0.0, self.settings.release); } else { // in case another note is pressed, we set that one as the new active note self.osc1.cancel(); self.currentFreq = _mtof(self.activeNotes[self.activeNotes.length - 1]); self.osc1.setFrequency(self.currentFreq, self.settings.portamento); } }

ここでいくつかのことが起こっています。 noteOnメソッドでは、最初に現在のメモをメモの配列にプッシュします。 モノシンセを作成している場合でも(つまり、一度に1つのノートしか演奏できない)、キーボード上で一度に複数の指を使用することができます。 したがって、1つのノートをリリースしたときに次のノートが再生されるように、これらすべてのノートをキューに入れる必要があります。 次に、オシレーターを停止して新しい周波数を割り当てる必要があります。新しい周波数は、MIDIノート(0から127までのスケール)から実際の周波数値に少し計算して変換します。

 function _mtof(note) { return 440 * Math.pow(2, (note - 69) / 12); }

noteOffメソッドでは、最初にアクティブなノートの配列からノートを見つけて削除することから始めます。 次に、それがアレイ内の唯一のノートである場合は、単に音量をオフにします。

setVolumeメソッドの2番目の引数は遷移時間です。これは、ゲインが新しいボリューム値に到達するまでにかかる時間を意味します。 音楽的には、ノートがオンの場合はアタックタイムに相当し、ノートがオフの場合はリリースタイムに相当します。

WebAnalyserモジュール:サウンドの視覚化

シンセに追加できるもう1つの興味深い機能は、アナライザーノードです。これにより、キャンバスを使用してサウンドの波形を表示し、レンダリングすることができます。 アナライザーノードの作成は、実際に分析を実行するためにscriptProcessorノードも作成する必要があるため、他のAudioContextオブジェクトよりも少し複雑です。 まず、DOMでcanvas要素を選択します。

 function Analyser(canvas) { self = this; self.canvas = angular.element(canvas) || null; self.view = self.canvas[0].getContext('2d') || null; self.javascriptNode = null; self.analyser = null; return self; }

次に、 connectメソッドを追加します。このメソッドでは、アナライザーとスクリプトプロセッサーの両方を作成します。

 Analyser.prototype.connect = function(ctx, output) { // setup a javascript node self.javascriptNode = ctx.createScriptProcessor(2048, 1, 1); // connect to destination, else it isn't called self.javascriptNode.connect(ctx.destination); // setup an analyzer self.analyser = ctx.createAnalyser(); self.analyser.smoothingTimeConstant = 0.3; self.analyser.fftSize = 512; // connect the output to the destination for sound output.connect(ctx.destination); // connect the output to the analyser for processing output.connect(self.analyser); self.analyser.connect(self.javascriptNode); // define the colors for the graph var gradient = self.view.createLinearGradient(0, 0, 0, 200); gradient.addColorStop(1, '#000000'); gradient.addColorStop(0.75, '#ff0000'); gradient.addColorStop(0.25, '#ffff00'); gradient.addColorStop(0, '#ffffff'); // when the audio process event is fired on the script processor // we get the frequency data into an array // and pass it to the drawSpectrum method to render it in the canvas self.javascriptNode.onaudioprocess = function() { // get the average for the first channel var array = new Uint8Array(self.analyser.frequencyBinCount); self.analyser.getByteFrequencyData(array); // clear the current state self.view.clearRect(0, 0, 1000, 325); // set the fill style self.view.fillStyle = gradient; drawSpectrum(array); } };

まず、scriptProcessorオブジェクトを作成し、それを宛先に接続します。 次に、アナライザー自体を作成し、オシレーターまたはフィルターからのオーディオ出力をフィードします。 オーディオ出力を宛先に接続して、それを聞くことができるようにする必要があることに注意してください。 また、グラフのグラデーションの色を定義する必要があります。これは、canvas要素のcreateLinearGradientメソッドを呼び出すことによって行われます。

最後に、scriptProcessorは間隔で「audioprocess」イベントを発生させます。 このイベントが発生すると、アナライザーによってキャプチャされた平均頻度を計算し、キャンバスをクリアして、 drawSpectrumメソッドを呼び出して新しい頻度グラフを再描画します。

 function drawSpectrum(array) { for (var i = 0; i < (array.length); i++) { var v = array[i], h = self.canvas.height(); self.view.fillRect(i * 2, h - (v - (h / 4)), 1, v + (h / 4)); } }

最後になりましたが、この新しいコンポーネントに対応するために、オーディオエンジンの配線を少し変更する必要があります。

 // in the _connectFilter() method if(self.analyser) { self.analyser.connect(self.ctx, self.filter1); } else { self.filter1.connect(self.ctx.destination); } // in the _disconnectFilter() method if(self.analyser) { self.analyser.connect(self.ctx, self.amp); } else { self.amp.connect(self.ctx.destination); }

これで、シンセの波形をリアルタイムで表示できる優れたビジュアライザーができました。 これにはセットアップに少し手間がかかりますが、特にフィルターを使用する場合は、非常に興味深く洞察に満ちています。

シンセの構築:ベロシティとデチューンの追加

MIDIチュートリアルのこの時点では、かなりクールなシンセがありますが、すべてのノートを同じ音量で再生します。 これは、ベロシティデータを適切に処理する代わりに、ボリュームを1.0の固定値に設定するだけだからです。 それを修正することから始めましょう。次に、最も一般的なMIDIキーボードにあるデチューンホイールを有効にする方法を見ていきます。

Velocityを有効にする

慣れていない場合、「ベロシティ」はキーボードのキーを押す強さに関係します。 この値に基づいて、作成されたサウンドは柔らかくまたは大きく見えます。

MIDIチュートリアルシンセでは、ゲインノードのボリュームを操作するだけでこの動作をエミュレートできます。 そのためには、まずMIDIデータを0.0〜1.0のfloat値に変換してゲインノードに渡すために、少し計算を行う必要があります。

 function _vtov (velocity) { return (velocity / 127).toFixed(2); }

MIDIデバイスのベロシティ範囲は0〜127であるため、その値を127で除算し、小数点以下2桁の浮動小数点値を返します。 次に、 _noteOnメソッドを更新して、計算された値をゲインノードに渡すことができます。

 self.amp.setVolume(_vtov(velocity), self.settings.attack);

以上です! シンセサイザーを演奏すると、キーボードのキーをどれだけ強く叩いたかによって音量が変化することがわかります。

MIDIキーボードでデチューンホイールを有効にする

ほとんどのMIDIキーボードはデチューンホイールを備えています。 ホイールを使用すると、現在再生されているノートの周波数をわずかに変更して、「デチューン」と呼ばれる興味深い効果を作成できます。 デチューンホイールは、周波数値を再計算してオシレーターを更新することでリッスンして処理できる独自のイベントコード(224)を使用してMidiMessageイベントも発生させるため、MIDIの使用方法を学ぶと、これはかなり簡単に実装できます。

まず、シンセでイベントをキャッチする必要があります。 そのために、 _onmidimessageコールバックで作成したswitchステートメントにケースを追加します。

 case 224: // the detune value is the third argument of the MidiEvent.data array Engine.detune(e.data[2]); break;

次に、オーディオエンジンでdetuneメソッドを定義します。

 function _detune(d) { if(self.currentFreq) { //64 = no detune if(64 === d) { self.osc1.setFrequency(self.currentFreq, self.settings.portamento); self.detuneAmount = 0; } else { var detuneFreq = Math.pow(2, 1 / 12) * (d - 64); self.osc1.setFrequency(self.currentFreq + detuneFreq, self.settings.portamento); self.detuneAmount = detuneFreq; } } }

デフォルトのデチューン値は64です。これは、デチューンが適用されていないことを意味します。したがって、この場合、現在の周波数をオシレーターに渡すだけです。

最後に、別のノートがキューに入れられた場合にデチューンを考慮に入れるために、 _noteOffメソッドも更新する必要があります。

 self.osc1.setFrequency(self.currentFreq + self.detuneAmount, self.settings.portamento);

インターフェイスの作成

これまでは、MIDIデバイスと波形ビジュアライザーを選択できる選択ボックスのみを作成しましたが、Webページを操作してサウンドを直接変更することはできません。 一般的なフォーム要素を使用して非常に単純なインターフェイスを作成し、それらをオーディオエンジンにバインドしてみましょう。

インターフェイスのレイアウトの作成

シンセのサウンドを制御するために、さまざまなフォーム要素を作成します。

  • オシレータタイプを選択するためのラジオグループ
  • フィルタを有効/無効にするチェックボックス
  • フィルタタイプを選択するためのラジオグループ
  • フィルタの周波数とレゾナンスを制御する2つの範囲
  • ゲインノードの攻撃と解放を制御するための2つの範囲

インターフェイス用のHTMLドキュメントを作成すると、次のようになります。

 <div class="synth container" ng-controller="WebSynthCtrl"> <h1>webaudio synth</h1> <div class="form-group"> <select ng-model="activeDevice" class="form-control" ng-options="device.manufacturer + ' ' + device.name for device in devices"> <option value="" disabled>Choose a MIDI device...</option> </select> </div> <div class="col-lg-6 col-md-6 col-sm-6"> <h2>Oscillator</h2> <div class="form-group"> <h3>Oscillator Type</h3> <label ng-repeat="t in oscTypes"> <input type="radio" name="oscType" ng-model="synth.oscType" value="{{t}}" ng-checked="'{{t}}' === synth.oscType" /> {{t}} </label> </div> <h2>Filter</h2> <div class="form-group"> <label> <input type="checkbox" ng-model="synth.filterOn" /> enable filter </label> </div> <div class="form-group"> <h3>Filter Type</h3> <label ng-repeat="t in filterTypes"> <input type="radio" name="filterType" ng-model="synth.filterType" value="{{t}}" ng-disabled="!synth.filterOn" ng-checked="synth.filterOn && '{{t}}' === synth.filterType" /> {{t}} </label> </div> <div class="form-group"> <!-- frequency --> <label>filter frequency:</label> <input type="range" class="form-control" min="50" max="10000" ng-model="synth.filterFreq" ng-disabled="!synth.filterOn" /> </div> <div class="form-group"> <!-- resonance --> <label>filter resonance:</label> <input type="range" class="form-control" min="0" max="150" ng-model="synth.filterRes" ng-disabled="!synth.filterOn" /> </div> </div> <div class="col-lg-6 col-md-6 col-sm-6"> <div class="panel panel-default"> <div class="panel-heading">Analyser</div> <div class="panel-body"> <!-- frequency analyser --> <canvas></canvas> </div> </div> <div class="form-group"> <!-- attack --> <label>attack:</label> <input type="range" class="form-control" min="50" max="2500" ng-model="synth.attack" /> </div> <div class="form-group"> <!-- release --> <label>release:</label> <input type="range" class="form-control" min="50" max="1000" ng-model="synth.release" /> </div> </div> </div>

ユーザーインターフェイスを装飾して見栄えを良くすることは、この基本的なMIDIチュートリアルでは取り上げません。 代わりに、後でユーザーインターフェイスを磨くための演習として保存できます。おそらく、次のようになります。

洗練されたMIDIユーザーインターフェイス

インターフェイスをオーディオエンジンにバインドする

これらのコントロールをオーディオエンジンにバインドするためのいくつかのメソッドを定義する必要があります。

オシレーターの制御

オシレーターの場合、オシレーターのタイプを設定できるメソッドのみが必要です。

 Oscillator.prototype.setOscType = function(type) { if(type) { self.osc.type = type; } }

フィルタの制御

フィルタには、3つのコントロールが必要です。1つはフィルタタイプ用、1つは周波数用、もう1つはレゾナンス用です。 _connectFilterメソッドと_disconnectFilterメソッドをチェックボックスの値に接続することもできます。

 Filter.prototype.setFilterType = function(type) { if(type) { self.filter.type = type; } } Filter.prototype.setFilterFrequency = function(freq) { if(freq) { self.filter.frequency.value = freq; } } Filter.prototype.setFilterResonance = function(res) { if(res) { self.filter.Q.value = res; } }

アタックとレゾナンスのコントロール

サウンドを少し形作るために、ゲインノードのアタックとリリースのパラメーターを変更できます。 これには2つの方法が必要です。

 function _setAttack(a) { if(a) { self.settings.attack = a / 1000; } } function _setRelease(r) { if(r) { self.settings.release = r / 1000; } }

ウォッチャーの設定

最後に、アプリのコントローラーで、数人のウォッチャーをセットアップし、作成したさまざまなメソッドにバインドするだけで済みます。

 $scope.$watch('synth.oscType', DSP.setOscType); $scope.$watch('synth.filterOn', DSP.enableFilter); $scope.$watch('synth.filterType', DSP.setFilterType); $scope.$watch('synth.filterFreq', DSP.setFilterFrequency); $scope.$watch('synth.filterRes', DSP.setFilterResonance); $scope.$watch('synth.attack', DSP.setAttack); $scope.$watch('synth.release', DSP.setRelease);

結論

このMIDIチュートリアルでは、多くの概念が取り上げられました。 ほとんどの場合、W3Cの公式仕様を除けば、かなり文書化されていないWebMIDIAPIの使用方法を発見しました。 Google Chromeの実装は非常に簡単ですが、入力デバイスと出力デバイスのイテレータオブジェクトに切り替えるには、古い実装を使用してレガシーコードを少しリファクタリングする必要があります。

WebAudio APIに関しては、これは非常に豊富なAPIであり、このチュートリアルではその機能の一部のみを取り上げました。 WebMIDI APIとは異なり、WebAudio APIは、特にMozillaDeveloperNetworkで非常によく文書化されています。 Mozilla Developer Networkには、多数のコード例と、各コンポーネントのさまざまな引数とイベントの詳細なリストが含まれています。これは、独自のカスタムブラウザベースのオーディオアプリケーションを実装するのに役立ちます。

両方のAPIが成長し続けるにつれて、JavaScript開発者にとって非常に興味深い可能性が開かれます。 同等のFlashと競合できる、フル機能のブラウザベースのDAWを開発できます。 また、デスクトップ開発者の場合、node-webkitなどのツールを使用して独自のクロスプラットフォームアプリケーションの作成を開始することもできます。 うまくいけば、これは、物理的な世界とクラウドの間のギャップを埋めることによってユーザーに力を与えるオーディオファンのための新世代の音楽ツールを生み出すでしょう。