OpalでJavaScriptのAPIラッパーを作る

  • 0
    いいね
  • 0
    コメント

    この記事は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
    

    Nativeincludeすることで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_datadestinationも定義しましょう。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のひとつの魅力だと思います。