9

Audio Unit を使用してオーディオ データを記録する OSX アプリを使用しています。Audio Unit の入力は、組み込み入力を含む、入力のある利用可能なソースに設定できます。問題は、内蔵入力から得られるオーディオがしばしばクリッピングされるのに対し、Audacity (または Quicktime) などのプログラムでは、入力レベルを下げることができ、クリッピングが発生しないことです。

もちろん、サンプル フレームに分数を掛けてもうまくいきません。ボリュームが小さくなるためです。ただし、サンプル自体は入力時にクリップされたままです。

クリッピングの問題を回避するために、内蔵入力の入力レベルまたはゲインを設定するにはどうすればよいですか?

4

1 に答える 1

15

これは、MacBook Pro(2011モデル)で入力音量を設定するのに役立ちます。少しファンキーです。マスターチャンネルの音量を設定してから、それぞれの独立したステレオチャンネルの音量を設定して、機能するものが見つかるまで試してみる必要がありました。私のコードのコメントを見てください。コードが機能しているかどうかを判断する最良の方法は、機能するget / set-propertyの組み合わせを見つけてから、get / set(何か他のもの)/getのようなことをしてセッターが機能しています。

もちろん、ここで行っているように、getProperty呼び出し全体でアドレスの値が同じままであることに依存しないことを指摘します。動作しているように見えますが、関数を参照して構造体の値を渡すときに、構造体の値が同じであることに依存することは間違いなく悪い習慣です。これはもちろんサンプルコードですので、私の怠惰を許してください。;)

//
//  main.c
//  testInputVolumeSetter
//

#include <CoreFoundation/CoreFoundation.h>
#include <CoreAudio/CoreAudio.h>

OSStatus setDefaultInputDeviceVolume( Float32 toVolume );

int main(int argc, const char * argv[]) {
    OSStatus                        err;

    // Load the Sound system preference, select a default
    // input device, set its volume to max.  Now set
    // breakpoints at each of these lines.  As you step over
    // them you'll see the input volume change in the Sound
    // preference panel.
    //
    // On my MacBook Pro setting the channel[ 1 ] volume
    // on the default microphone input device seems to do
    // the trick.  channel[ 0 ] reports that it works but
    // seems to have no effect and the master channel is
    // unsettable.
    //
    // I do not know how to tell which one will work so
    // probably the best thing to do is write your code
    // to call getProperty after you call setProperty to
    // determine which channel(s) work.
    err = setDefaultInputDeviceVolume( 0.0 );
    err = setDefaultInputDeviceVolume( 0.5 );
    err = setDefaultInputDeviceVolume( 1.0 );
}

// 0.0 == no volume, 1.0 == max volume
OSStatus setDefaultInputDeviceVolume( Float32 toVolume ) {
    AudioObjectPropertyAddress      address;
    AudioDeviceID                   deviceID;
    OSStatus                        err;
    UInt32                          size;
    UInt32                          channels[ 2 ];
    Float32                         volume;

    // get the default input device id
    address.mSelector = kAudioHardwarePropertyDefaultInputDevice;
    address.mScope = kAudioObjectPropertyScopeGlobal;
    address.mElement = kAudioObjectPropertyElementMaster;

    size = sizeof(deviceID);
    err = AudioObjectGetPropertyData( kAudioObjectSystemObject, &address, 0, nil, &size, &deviceID );

    // get the input device stereo channels
    if ( ! err ) {
        address.mSelector = kAudioDevicePropertyPreferredChannelsForStereo;
        address.mScope = kAudioDevicePropertyScopeInput;
        address.mElement = kAudioObjectPropertyElementWildcard;
        size = sizeof(channels);
        err = AudioObjectGetPropertyData( deviceID, &address, 0, nil, &size, &channels );
    }

    // run some tests to see what channels might respond to volume changes
    if ( ! err ) {
        Boolean                     hasProperty;

        address.mSelector = kAudioDevicePropertyVolumeScalar;
        address.mScope = kAudioDevicePropertyScopeInput;

        // On my MacBook Pro using the default microphone input:

        address.mElement = kAudioObjectPropertyElementMaster;
        // returns false, no VolumeScalar property for the master channel
        hasProperty = AudioObjectHasProperty( deviceID, &address );

        address.mElement = channels[ 0 ];
        // returns true, channel 0 has a VolumeScalar property
        hasProperty = AudioObjectHasProperty( deviceID, &address );

        address.mElement = channels[ 1 ];
        // returns true, channel 1 has a VolumeScalar property
        hasProperty = AudioObjectHasProperty( deviceID, &address );
    }

    // try to get the input volume
    if ( ! err ) {
        address.mSelector = kAudioDevicePropertyVolumeScalar;
        address.mScope = kAudioDevicePropertyScopeInput;

        size = sizeof(volume);
        address.mElement = kAudioObjectPropertyElementMaster;
        // returns an error which we expect since it reported not having the property
        err = AudioObjectGetPropertyData( deviceID, &address, 0, nil, &size, &volume );

        size = sizeof(volume);
        address.mElement = channels[ 0 ];
        // returns noErr, but says the volume is always zero (weird)
        err = AudioObjectGetPropertyData( deviceID, &address, 0, nil, &size, &volume );

        size = sizeof(volume);
        address.mElement = channels[ 1 ];
        // returns noErr, but returns the correct volume!
        err = AudioObjectGetPropertyData( deviceID, &address, 0, nil, &size, &volume );
    }

    // try to set the input volume
    if ( ! err ) {
        address.mSelector = kAudioDevicePropertyVolumeScalar;
        address.mScope = kAudioDevicePropertyScopeInput;

        size = sizeof(volume);

        if ( toVolume < 0.0 ) volume = 0.0;
        else if ( toVolume > 1.0 ) volume = 1.0;
        else volume = toVolume;

        address.mElement = kAudioObjectPropertyElementMaster;
        // returns an error which we expect since it reported not having the property
        err = AudioObjectSetPropertyData( deviceID, &address, 0, nil, size, &volume );

        address.mElement = channels[ 0 ];
        // returns noErr, but doesn't affect my input gain
        err = AudioObjectSetPropertyData( deviceID, &address, 0, nil, size, &volume );

        address.mElement = channels[ 1 ];
        // success! correctly sets the input device volume.
        err = AudioObjectSetPropertyData( deviceID, &address, 0, nil, size, &volume );
    }

    return err;
}

「[私]はこれをどのように理解しましたか?」という質問に答えて編集します。

私は過去5年ほどの間、Appleのオーディオコードを使用することに多くの時間を費やし、解決策を探す場所と方法に関して、直感/プロセスを開発しました。私のビジネスパートナーと私は、第1世代のiPhoneと他のいくつかのデバイス用にオリジナルのiHeartRadioアプリを共同執筆しました。そのプロジェクトでの私の責任のひとつは、オーディオ部分、特にiOS用のAACShoutcastストリームデコーダー/プレーヤーの作成でした。当時、ドキュメントやオープンソースの例はなかったので、試行錯誤を繰り返し、たくさんのことを学びました。

とにかく、私があなたの質問を読んで賞金を見たとき、私はこれがただのぶら下がっている果物であると思いました(すなわち、あなたはRTFMを持っていませんでした;-)。ボリュームプロパティを設定するために数行のコードを記述しましたが、それが機能しなかったとき、私は本当に興味を持ちました。

プロセス的には、これが役立つかもしれません。

それが簡単な答えではないことを知った後、私は問題を解決する方法について考え始めました。私はサウンドシステム環境設定で入力ゲインを設定できることを知っていたので、otoolでそれを分解して、Appleが古いまたは新しいAudio Toolboxルーチンを使用しているかどうかを確認することから始めました(新しい):

使用してみてください:

otool -tV /System/Library/PreferencePanes/Sound.prefPane/Contents/MacOS/Sound | bbedit

次に、検索しAudioて、呼び出されるメソッドを確認します(bbeditがない場合は、すべてのMac開発者がIMOを実行し、ファイルにダンプして、他のテキストエディターで開きます)。

私は古い、廃止されたAudio Toolboxルーチン(この業界では廃止されるまで3年)に最も精通しているので、AppleのTechnotesをいくつか調べました。彼らはデフォルトの入力デバイスを取得し、最新のCoreAudioメソッドを使用してその音量を設定する方法を示すものを持っていますが、間違いなく彼らのコードが正しく機能しないことを確認しました(少なくとも私のMBPでは)。

その時点に到達したら、私は実証済みの方法に頼りました。たとえば、使用法を探して、関係している可能性が高いキーワード(たとえば、など)を探し始めAudioObjectSetPropertyDataますkAudioDevicePropertyVolumeScalar

CoreAudioと一般的なAppleToolboxの使用について私が見つけた興味深い点の1つは、人々がさまざまなこと(大量のペーストビンやGoogleCodeプロジェクトなど)を試すオープンソースコードがたくさんあることです。このコードの束を掘り下げても構わないと思っているなら、通常、答えを完全に見つけるか、いくつかの非常に良いアイデアを得るでしょう。

私の検索で私が見つけた最も関連性のあるものは、デフォルトの入力デバイスを取得し、新しいツールボックスルーチンを使用してマスター入力ゲインを設定する方法を示すAppleテクニカルノートでした(ハードウェアでは機能しませんでしたが)、いくつかのコードを見つけましたこれは、出力デバイスのチャネルごとにゲインを設定することを示しています。入力デバイスはマルチチャネルにすることができるので、これが次に試すべき論理的なことだと思いました。

少なくとも今のところ、あなたが尋ねたことを行う方法を示すAppleからの正しいドキュメントがないので、あなたの質問は本当に良いです。両方のチャンネルが音量を設定したと報告しているが、明らかに一方だけが設定しているので、それも間抜けです(入力マイクはモノラルソースなので、これは驚くべきことではありませんが、ノーオペレーションチャンネルとそれに関するドキュメントが少しないことを検討していますAppleのバグの)。

これは、Appleの最先端テクノロジーを扱い始めるときにかなり一貫して起こります。あなたは彼らのツールボックスで驚くべきことをすることができます、そしてそれは私が水から取り組んだ他のすべてのOSを吹き飛ばします、しかしあなたが適度に洗練された何かをしようとしているなら特にあなたが彼らのドキュメントに先んじるのにそれほど時間はかかりません。

たとえば、カーネルドライバを作成することにした場合、IOKitのドキュメントはひどく不十分であることがわかります。最終的には、オンラインになって、他の人のプロジェクトまたはOS Xソース、あるいはその両方のソースコードを掘り下げる必要があります。すぐに、ソースが本当に答えに最適な場所であると結論付けます(StackOverflowであっても)かなり素晴らしいです)。

ポイントとあなたのプロジェクトの幸運に感謝します:)

于 2012-06-17T07:17:56.923 に答える