この記事はOpal Advent Calendar 2016の12日目の投稿として書いています。
今日は、10日目の続きでWeb Audio APIのラッパーを作ろうと思います。
Web Audio APIのすべてを実装すると良いとは思うのですが、記事にするにはボリュームが大きすぎると思います。
ある程度のものを作って大体のつくりかたが分るところまでできれば本記事としてはよいでしょう。9日目に作ったサンプルが動く程度のものを作ってみましょう。
まずはAudioContextをつくりましょう。
module Audio
class Context
include Native
def initialize
super `new AudioContext()`
end
end
end
Native
をinclude
することでJavaScriptのネイティブオブジェクトをラップしたクラスを作ることができます。
イニシャライザはネイティブオブジェクトを引数に取るので、ここではラップしたコンテキストクラスでAudioContext
オブジェクトを生成してsuper
に渡すことにします。
exampleのほうも更新しましょう。
examples/app/application.rb
require 'opal'
require 'opal/audio'
context = Audio::Context.new
source = context.createBufferSource
request = Native(`new XMLHttpRequest()`)
request.open('GET', 'sound.mp3', true)
request.responseType = 'arraybuffer'
request.send
request.onload = Proc.new do
res = request.response
context.decodeAudioData(res) do |buf|
source.buffer = buf
end
end
source.connect(context.destination)
source.start(0)
sound.mp3
を読めるようにするためにSinatraを使うようにしましょう。
examples/config.ru等を[8日目」(http://qiita.com/youchan@github/items/735ffad1a5c406ebb30c)の記事を参考にSinatra版に変更しましょう。
このまま実行すると、createBufferSource
というメソッドがないと怒られます。
createBufferSource
メソッドを追加しましょう。
そのまえに、メソッド名はそのままでよいでしょうか?ここはRubyなのでスネークケースのメソッド名にしたいところです。
create_buffer_source
という名前でネイティブのcreateBufferSource
を呼ぶようにしましょう。
Native
にはこういうときに便利なalias_native
メソッドがあります。
alias_native :create_buffer_source, :createBufferSource
ほかにも、decode_audio_data
とdestination
も定義しましょう。destination
のほうは、JavaScript側ではプロパティとしてもっているのでnative_reader
を使います。
alias_native :decode_audio_data, :decodeAudioData
native_reader :destination
examples/app/application.rbのほうも直して実行しましょう。
音が鳴りましたか?
AudioContext
だけをラップしましたが、他のオブジェクトのラッパーは書いていません。たとえばcreate_buffer_source
の戻り値はいったい何なのでしょう?
p
で表示してみると、どうやらNative
クラスのオブジェクトのようです。
このようにOpalは特にラッパークラスを書かなくてもいい感じにラップしたオブジェクトを返してくれます。
今回のケースのようにスネークケースにしたいとかよりRubyishなラッパーにしたい場合にはラッパークラスを書けばよいでしょう。
OpalはRubyとJavaScriptのコードの間の橋渡しがとても良くできていると思います。JavaScriptのプロジェクトに一部Rubyを使うということも可能でしょう。これはOpalのひとつの魅力だと思います。