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