プログラミング > Core Audio - Mac >

CoreAudio その3〜5改 AudioObjectでのプロパティ取得・設定


Mac OS X 10.6 Snow Leopardから、AudioHardware〜とかAudioDevice〜とかAudioStream〜とかのGet・Set系がことごとくDEPRECATEDになってしまいました。

僕の認識では、もともとAudioObject〜があって、そのコンビニエンスメソッドとしてAudioDeviceとかの関数があると思っていたのですけど、どうやら歴史的には逆だったようです。ヘッダをよく見てみたら、AudioObject系はわりと最近の10.4から増えてたんですね。

あと、AudioUnitがiPhoneと同じようにAudioComponentにいきなり変わっててびっくり。iPhoneで慣れ親しんでいたとはいえ、もちょっと緩やかに移行してくれてもいいんじゃないすかね。

プロパティの定数系も結構Deprecatedしてます。でも、これはXcodeで警告を出してくれないので注意が必要です。ヘッダのコメントに"Some Day Be Deprecated"なんてこっそりかかれてます。Device系だとkAudioDevicePropertyDeviceNameから始まるところとかです。10.7になっていきなりエラー出まくりなんて事のないようにしっかりチェックしておきましょう。

ということで、取得・設定系をAudioObjectを使ってやってみたいと思います。

AudioObjectでオーディオ情報の取得・設定をするにはAudioObjectGetPropertyDataやAudioObjectSetPropertyDataという関数を使います。これはいままでAudioHardware〜やAudioDevice〜など別々の関数でやっていたオーディオ情報の取得や設定を、ひとつでまかなえるものです。プロパティのサイズを調べるのにも、AudioObjectGetPropertyDataSizeという関数で行う事になります。

たとえば、プロパティの取得する関数はこんな感じで定義されています。

extern OSStatus
AudioObjectGetPropertyData(AudioObjectID inObjectID,
                           const AudioObjectPropertyAddress* inAddress,
                           UInt32 inQualifierDataSize,
                           const void* inQualifierData,
                           UInt32* ioDataSize,
                           void* outData) 

最初のAudioObjectIDというのはAudioDeviceIDやAudioStreamIDをそのまま渡します。前の記事のその3でも説明しましたが、AudioDeviceIDもAudioStreamIDもAudioObjectIDをtypedefしているだけのもので、つまり全てAudioObjectIDです(リファレンス的にAudioDeviceなどはAudioObjectのサブクラスってことらしい)。AudioHardware〜系の関数をつかっていたプロパティのときはkAudioObjectSystemObjectを渡します。

ちょっとひとつ飛ばしまして、inQualifierDataSizeとinQualifierDataは、サンプルで使っているものが無かったのでよくわかりません。基本0とNULLで大丈夫なようです。もしかしたらまだ機能していないかもしれません。ioDataSizeとoutDataは取得するプロパティのサイズと受け取るメモリ領域で、前と同じです。

で、新しく出てきたAudioObjectPropertyAddressは、

struct  AudioObjectPropertyAddress
{
    AudioObjectPropertySelector mSelector;
    AudioObjectPropertyScope    mScope;
    AudioObjectPropertyElement  mElement;
};
typedef struct AudioObjectPropertyAddress   AudioObjectPropertyAddress;

と定義されてます。プロパティの場所を特定するのに必要なものを集めたって感じですかね。

Selectorは〜PropertyIDの事です。なんでかセレクタって名前になってます。Scopeは、まあほとんどの場合はkAudioObjectPropertyScopeGlobalで、Deviceなどの入出力部分のときはInputとかOutputとかで指定したりって感じです。Elementは基本kAudioObjectPropertyElementMaster(= 0)でOKだと思います(これ以外指定するパターンがすぐに見つけられなかった。Channel的なところで0以外を使うのでは)。

では、サンプルソースです。Xcodeで新規プロジェクト→Command Line Tool→Foundationでプロジェクトを作成して、CoreAudio.Frameworkを追加して、main.mを以下のソースに差し替えてください。走らせると、デフォルトになっているオーディオデバイスの名前を表示して、サンプルレートを設定可能な中で変更します。

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

int main (int argc, const char * argv[]) {
    
    AudioDeviceID devID;
    UInt32 size;
    AudioObjectPropertyAddress address;
    AudioValueRange *sampleRates;
    CFStringRef deviceName = NULL;
	
    //デフォルトのアウトプットに設定されているオーディオデバイスを取得する
    address.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
    address.mScope = kAudioObjectPropertyScopeGlobal;
    address.mElement = kAudioObjectPropertyElementMaster;
    size = sizeof(devID);
    
    AudioObjectGetPropertyData(kAudioObjectSystemObject, &address, 0, NULL, &size, &devID);
    
    //アウトプットの名前を取得する
    address.mSelector = kAudioObjectPropertyName;
    size = sizeof(deviceName);
    
    AudioObjectGetPropertyData(devID, &address, 0, NULL, &size, &deviceName);
    
    //アウトプットのデバイスが対応しているサンプルレートを取得する
    address.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
    AudioObjectGetPropertyDataSize(devID, &address, 0, NULL, &size);
    
    UInt32 numOfSampleRates = size / sizeof(AudioValueRange);
    sampleRates = calloc(numOfSampleRates, sizeof(AudioValueRange));
    
    AudioObjectGetPropertyData(devID, &address, 0, NULL, &size, sampleRates);
    
    //現在のサンプルレートを取得する
    Float64 currentSampleRate;
    address.mSelector = kAudioDevicePropertyNominalSampleRate;
    size = sizeof(Float64);
    
    AudioObjectGetPropertyData(devID, &address, 0, NULL, &size, ¤tSampleRate);
    
    //サンプルレートを別のにする
    int currentIndex = 0;
    for (int i = 0; i < numOfSampleRates; i++) {
        if (sampleRates[i].mMinimum == currentSampleRate) {
            currentIndex = i;
            break;
        }
    }
    
    int newIndex = currentIndex + 1;
    if (newIndex >= numOfSampleRates) newIndex = 0;
    
    //サンプルレートを設定する
    Float64 newSampleRate = sampleRates[newIndex].mMinimum;
    size = sizeof(Float64);
    
    AudioObjectSetPropertyData(devID, &address, 0, NULL, size, &newSampleRate);
    
    NSLog(@"device name = %@", deviceName);
    NSLog(@"new samplerate = %f", newSampleRate);
    
    free(sampleRates);
    CFRelease(deviceName);
    
    return 0;
}

あ、そういえばwhenって無いなぁ。

トラックバック(0)

このブログ記事を参照しているブログ一覧: CoreAudio その3〜5改 AudioObjectでのプロパティ取得・設定

このブログ記事に対するトラックバックURL: http://objective-audio.jp/oa80/mt-tb.cgi/124

コメントする


画像の中に見える文字を入力してください。