PWM-1のMIDI対応のお話
昨日、慌ててMIDI対応してリリースしたんだけど、
IAAホストアプリにホストされている時の挙動が怪しかったので、
引き続き調査してみた。
何が問題だったかというと、
MIDIデバイスの接続/解除を検知すると、
自動で接続/解除を行うようにしていたんだけど、それが裏目に出た。
正確には、IAAにホストされてるときに検知しても、
アプリが裏に回ってる時はUIを更新してはいけない。
もう少し具体的に。
MIDIの初期化は、
iOS9.0から使えるMIDIClientCreateWithBlockを使ってるんだけど、
3つ目の引数で検知した時のコールバックをブロック(クロージャ?)で渡せる。
// どこぞの関数の中で初期化
//var status: OSStatus = noErr
//status = MIDIClientCreateWithBlock( self.midiInstName, &self.clientRef, MyMIDINotifyBlock )
//if status != noErr {
// print( "MIDIClientCreateWithBlock failed. \(status)" )
// return
//}
func MyMIDINotifyBlock(midiNotification: UnsafePointer<MIDINotification>) {
switch midiNotification.memory.messageID {
case .MsgObjectAdded:
break // 接続を検知
case .MsgObjectRemoved:
break // 解除を検知
case .MsgIOError:
break // エラーを検知
default:
break
}
}
PWM-1だと、viewDidLoadで初期化して、deinitで解放してる。
もちろん、MIDIClientCreateWithBlockのあとに、
MIDIInputPortCreateを呼んでるんだけど、
後者は、MIDIPacketを処理する都合上、ObjC側で呼び出している。
まずは、MIDIClientCreateWithBlockだけど、
PWM-1では、UIの更新をどうしたかというと、
// MyMIDINotifyBlockの中では、こんな感じでチェックする
if UIApplication.sharedApplication().applicationState == .Active {
// todo: UIを更新
}
上記とは別に、
//NSNotificationCenter.defaultCenter().addObserver(
// self,
// selector: #selector(ViewController.appWillEnterForeground(_:)),
// name: UIApplicationWillEnterForegroundNotification, object: nil )
func appWillEnterForeground(notification: NSNotification?) {
// todo: UIを更新
}
ついでに言うと、viewDidLoadの中からも、
appWillEnterForeground( nil )って書いて呼び出してる。
viewDidLoadの中でなら、UIにアクセスしても良いらしい。
IAAアプリによってPWM-1が起動した場合も、
viewDidLoadが呼ばれるが、UIを初期化しても大丈夫だった。
最後に、MIDIPacketだけど、
Swiftだと、配列だったメンバ変数がタプルに置き換えられてて、
これはどうにもならないなってことで、
最初はMIDIPacketをObjCに渡して処理してたけど、
まるっとObjC側でコールバックを登録して処理することにした。
シーケンサーみたいなアプリの場合、
いまどの辺りを鳴らしてるか表示するのに困るかも知れないけど、
とりあえず、PWM-1ではそれをしないので良しとした。
こんな文章じゃ良く分かんないよーって人は、
直接会って聞いていただければと思う。
おしまい。
Leave a Comment