Core MIDI その1 MIDIObject

Core MIDIに関してリアルタイムで調査中ですが、ちょこちょこと分かった事を書いて行こうと思います。ここのページにもいろいろと書いてありますので参考に。

まず用語解説的なところから始めまして、Core MIDIを使うときに必要なMIDIオブジェクトというものを見て行きます。MIDIオブジェクトは、

・MIDIDevice
・MIDIEntity
・MIDIEndpoint

・MIDIClient
・MIDIPort

という5つがあるのですが、上の3つは基本的にアプリケーション外部からCoreMIDI経由で取得するもの(MIDIEndpointは例外あり)で、下の2つのMIDIClientとMIDIPortはアプリケーション側に作るものです。

まず、上の方から見て行きます。MIDIDeviceというのは名前の通りMIDIのデバイスの事ですが、Core MIDIではMIDIインターフェース以外にも、アプリケーション同士を直接つなげるIACドライバとか、ネットワーク経由での接続とかもありまして、それらも全て同じMIDIDeviceとして取得できます。

まあ、実際見た方が分かりやすいと思いますので、Audio MIDI 設定を開いてみますと…

AudioMIDISetup.jpg

このように表示されているとしたら、この表示されている4つがMIDIDeviceになります。右から2つ目の「Onyx Firewire(0134)」ように実際つながっていなくてもAudio MIDI 設定で登録されていれば、MIDIDeviceとして取得できます。

MIDIDeviceはMIDIEntityというのを持っていまして、たとえば今回見ているAudio MIDI 設定のUA-25でいえば…

UA25.jpg

左下の「ポート」の中に表示されている「EDIROL UA-25」というのがエンティティになります。これはデバイスによって複数持つ場合もあり、「IACドライバ」なんかでは自由に増やせますから、

IAC.jpg

こんな風に2つ作っておくと、「IACドライバ」というMIDIDeviceの中から「バス1」と「バス2」という2つのMIDIEntityが取得できます。

MIDIEndpointというのは、MIDIEntityの中にあるMIDI入力や出力の事(Audio MIDI 設定ではポートの右にあるコネクタのところのMIDI入力と出力)になります。MIDIインターフェースに装備されているMIDI INやMIDI OUTのコネクタそのものだと考えてよいと思います。Core MIDIではアプリケーション側から見て入力はSource、出力はDestinationと表現されます。

アプリケーション内部の方に移りまして、MIDIClientというのはアプリケーション内部に作るMIDIデバイスのようなものです。MIDIClientを作成するときにMacのMIDIシステムの変更を受け取るコールバック関数を登録する事もできます。

アプリケーション外部とMIDIデータをやり取りするにはMIDIClientにMIDIPortというものを作成します。入力に関しては、MIDIEndpointをMIDIPortに登録すると同時にコールバックを設定して、リアルタイムでMIDIデータを受け取れます。

ちなみにMusicPlayerの再生とかCore Audio Clockのように、MIDIClientとかMIDIPortとかを作らずにMIDIEndpointを直接渡すだけで良い場合もあります。MIDIClientやMIDIPortは自分でMIDIの生のデータを処理したいときに使うという感じでしょうか。

といったところでサンプルです、。MIDIデバイスからMIDIエンティティを取得してさらに入力側のMIDIエンドポイントを取得します。FoundationToolで新規作成して、CoreMIDI.Frameworkを追加し実行すると、使用可能なデバイスの、エンドポイントの名前とオフラインかどうかを表示します。

#import <Foundation/Foundation.h>
#import <CoreMIDI/CoreMIDI.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
    OSStatus err;
    CFStringRef strDeviceRef = NULL;
    CFStringRef strEndPointRef = NULL;
    
    //MIDIデバイスの数を取得する
    ItemCount count = MIDIGetNumberOfDevices();
    
    for (ItemCount i = 0; i < count; i++) {
        
        //MIDIデバイスを取得する
        MIDIDeviceRef devRef = MIDIGetDevice(i);
        
        //MIDIデバイスの名前を取得する
        err = MIDIObjectGetStringProperty(
            devRef, kMIDIPropertyName, &strDeviceRef);
        if (err != noErr) {
            NSLog(@"err = %d", err);
        }
        
        //MIDIエンティティの数を取得する
        ItemCount numEntities = MIDIDeviceGetNumberOfEntities(devRef);
        
        for (NSInteger j = 0; j < numEntities; j++) {
            
            //MIDIエンティティを取得する
            MIDIEntityRef entityRef = MIDIDeviceGetEntity(devRef, j);
            
            //MIDIエンティティからMIDIエンドポイントのソースの数を取得する
            ItemCount sourceCount = MIDIEntityGetNumberOfSources(entityRef);
            
            for (NSInteger k = 0; k < sourceCount; k++) {
                
                //MIDIエンドポイントを取得する
                MIDIEndpointRef endPointRef = 
                    MIDIEntityGetSource(entityRef, k);
                
                //MIDIエンドポイントの名前を取得する
                err = MIDIObjectGetStringProperty(
                    endPointRef, kMIDIPropertyName, &strEndPointRef);
                if (err != noErr) {
                    NSLog(@"err = %d", err);
                }
                
                SInt32 isOffline;
                err = MIDIObjectGetIntegerProperty(
                    endPointRef, kMIDIPropertyOffline, &isOffline);
                if (err != noErr) {
                    NSLog(@"err = %d", err);
                }
                
                //ログに表示
                NSLog(@"Device = %@ / EndPoint = %@ / Offline = %d", 
                    strDeviceRef, strEndPointRef, isOffline);
                
                if (strEndPointRef) {
                    CFRelease(strEndPointRef);
                    strEndPointRef = NULL;
                }
            }
        }
        
        if (strDeviceRef) {
            CFRelease(strDeviceRef);
            strDeviceRef = NULL;
        }
    }
    
    [pool drain];
    return 0;
}

この方法で使用可能なMIDIエンドポイントを取得するときは、オフラインになっていない事もチェックしないといけなかったりしていろいろ面倒ですが、以下のようにMIDIGetNumberOfSourcesとMIDIGetSourceで、いきなりオンラインになっているMIDIエンドポイントを取得できます。

#import <Foundation/Foundation.h>
#import <CoreMIDI/CoreMIDI.h>

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    OSStatus err;
    CFStringRef strEndPointRef = NULL;
    
    ItemCount sourceCount = MIDIGetNumberOfSources();
    
    for (NSInteger i = 0; i < sourceCount; i++) {
        
        //MIDIエンドポイントを取得する
        MIDIEndpointRef endPointRef = MIDIGetSource(i);
        
        //MIDIエンドポイントの名前を取得する
        err = MIDIObjectGetStringProperty(
            endPointRef, kMIDIPropertyName, &strEndPointRef);
        
        if (err == noErr) {
            
            //ログに表示
            NSLog(@"EndPoint = %@", strEndPointRef);
            
            if (strEndPointRef) {
                CFRelease(strEndPointRef);
                strEndPointRef = NULL;
            }
            
        } else {
            
            NSLog(@"err = %d", err);
        }
    }
    
    [pool drain];
    return 0;
}

Core MIDI その1 MIDIObject」への1件のフィードバック

  1. ピンバック: 帰ってきたネコブログ » CoreMIDIでMIDIデータを受信する

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です