2015年1月28日水曜日

Android用のBLE MIDIライブラリのご紹介

去年から、Android端末上でBLE MIDI通信を使えるようにするライブラリを作っていました。(→前回の記事を参照)
AppleがBluetooth Low Energy MIDI Specification(PDF)を公開していたのを先日見つけたので、その仕様に合うよう実装してみました。

このライブラリを使って出来ること:
  • AndroidアプリとBLE MIDIなデバイスとが接続でき、演奏やイベントの記録などをすることができます。
  • iOSやOS X上で動くBLE MIDIなアプリとも接続できます。
  • Android LollipopかつPeripheral機能がサポートされている端末では、端末をBLE MIDIデバイスとして振る舞わせることができます。
注意:
このAppleの仕様は、まだMIDI公式から承認されていません。以前問い合わせをしたところ、「ドラフトの仕様はあるが絶賛議論中だよ。議論を見たかったら会員になってね」とのことでした。公式としてリリースされる仕様ではAppleのものとの食い違いが出てくるかもしれません。頑張って追従します。

ライブラリの機能

このライブラリを使うことで、AndroidはBLE MIDI CentralとPeripheralの機能を使えるようになります。

BLE MIDI Central機能とは

AndroidアプリがBLE MIDIデバイスを探して、接続します。アプリはデバイスとMIDIメッセージを送受信できます。
この機能にはAndroid JellyBean MR2(4.3 / API Level 18)以降が必要です。ペアリング機能を使うにはAndroid KitKat(4.4 / API Level 19)以降が必要です。

BLE MIDI Peripheral機能とは

AndroidアプリがBLE MIDIデバイスとして振舞います。アプリは他の端末上(Android, iOS, OS X)のCentralなアプリから接続して使用されます。


BLE Peripheralの機能はAndroid Lollipopでサポートされたので、この機能はAndroid Lollipop(5.0 / API Level 21)以降が必要です。また、端末に搭載されているBluetoothデバイスがBLE Peripheralに対応している必要があります。現状ではNexus6, Nexus9, Sumsung SM-G900F/Vが対応機種のようです。

BLE Peripheralに対応しているかどうかは、↓のサンプルアプリでも確認できます。PeripheralのActivityが起動すればOKで、起動させたときに「利用できません」的なダイアログが出たら使えません。

サンプルアプリを試す

Miselu C.24 keyboardと接続しているの図

サンプルアプリはGoogle Playで公開しています。 
このアプリはノートON/OFFのMIDIイベントを送信できます。また、受信した全てのMIDIイベントをListViewに表示します。


テストしたAndroid端末と安定性

ライブラリはNexus 7(2013)とNexus 6とでテストしています。いずれもAndroid Lollipop 5.0.1です。
  • Nexus 7(2013)
    • Nexus 7(2013)はBLE Peripheral機能をサポートしていません。
    • BLEの接続どうも不安定です。高頻度で切断→再接続が起きて、接続された状態を維持することができません。
      • ライブラリのバグかもしれないので調査中です。
  • Nexus 6
    • BLE CentralとPeripheralの機能のどちらもサポートしています。
    • BLEの接続はとても安定しています。

コードを参照する

ソースコードはgithubのリポジトリで公開しています。このリポジトリはライブラリとサンプルプロジェクトを含んでいます。
masterブランチは最新のリリースバージョン、develop(もしくはfeature)ブランチは最新の開発バージョンです。

現在このライブラリは活発に開発中なので、まだまだ問題があるかと思います。バグや改善点を見つけたり要望などありましたらgithubのissueか、emailでご連絡ください。

ライブラリを使う

アプリを実装する場合の手順です。Android Studioの利用が前提です。

プロジェクトのGradle設定を編集する

プロジェクトの直下にある、'build.gradle' ファイルを開きます。
  1. 'repositories.maven' の設定にURLを追加します。
  2. 'dependencies' の設定に依存性情報を追加します。

BLE MIDI機能を提供する「Provider」を初期化する

ライブラリにはBLE MIDI機能を提供するための 'BleMidiCentralProvider' と 'BleMidiPeripheralProvider' という2種類のクラスがあります。
まず最初に、アプリの Activity にProviderのフィールドを追加します。

BleMidiCentralProviderの場合

'startScanDevice(int timeout)' メソッドを使用して、周辺のBLE MIDIデバイスを検索します。引数timeoutの単位はミリ秒です。0かマイナス値だと、止めるまでずっとデバイスを検索します。
BLE MIDIデバイスの検索を停止するときは 'stopScanDevice()' メソッドを呼びます。

BleMidiPeripheralProviderの場合

'startAdvertising()' メソッドを使用して、周辺の機器に対してBLE MIDIデバイスが存在することを通知します。
通知を止める場合には 'stopAdvertising()' メソッドを呼びます。

「Provider」を破棄する処理を追加

アプリの Activity が終了するときに、Providerの 'terminate' メソッドを呼ぶ必要があります。

BLE MIDIデバイスとの接続

Provider には 'setOnMidiDeviceAttachedListener' というメソッドがあります。 'OnMidiDeviceAttachedListener' クラスのインスタンスをnewしたものを、このメソッドを使ってProviderへと関連付けます。


新しいデバイスが検知されたら、このリスナーのメソッド 'onMidiInputDeviceAttachedもしくは 'onMidiOutputDeviceAttached' が呼ばれて通知されます。

BLE MIDIデバイスからの接続解除

Providerの 'setOnMidiDeviceDetachedListener' メソッドを呼ぶことで、 'OnMidiDeviceDetachedListener' のインスタンスを関連付けることができます。デバイスの接続が解除されたときに 'onMidiInputDeviceDetached' もしくは 'onMidiOutputDeviceDetached' メソッドが呼ばれて通知されます。

もし、ユーザーの操作により明示的にデバイスを接続解除したい場合には、Providerの 'disconnectDevice' メソッドを呼びます。デバイスは接続解除され、次いで 'OnMidiDeviceDetachedListener' メソッドが呼ばれます。

    bleMidiCentralProvider.disconnectDevice(midiOutputDevice);

MIDIイベントの送信

Providerは接続されている全てのデバイス情報を保持しています。 'getMidiOutputDevices' メソッドを呼ぶことで、アプリは 'MidiOutputDevice' の一式を取得できます。 'MidiOutputDevice' のインスタンスは 'sendMidiNoteOn' メソッドのような、MIDI送信のためのメソッドを持っています。

MIDIイベントの受信

まず最初にイベントリスナー 'OnMidiInputEventListener' を実装します。このインタフェースには 'onMidiNoteOn' メソッドのような、全てのMIDI受信イベントに対応したメソッドが定義されています。
このメソッドたちの最初の引数は 'MidiInputDevice' のインスタンスなので、アプリのActivityは1つの 'OnMidiInputListener' インスタンスを持つだけで良いです。
次に、 'MidiInputDevice' のインスタンスに 'OnMidiInputEventListener' を関連付けます。アプリがMIDIイベントを受信すると、対応するメソッドが呼ばれます。

注意:

全てのイベントリスナーのメソッドはUIスレッドの外から呼ばれます。なので、テキストやリストビューなどのUI要素を変更したい場合には、UIスレッドに所属する 'Handler' を経由する必要があります。