如何设置内置输入(OSX Core Audio / Audio Unit)的输入电平(增益)?

2024-01-09

我有一个 OSX 应用程序,它使用音频单元记录音频数据。音频单元的输入可以设置为任何可用的输入源,包括内置输入。问题是,我从内置输入获得的音频经常被削波,而在 Audacity(甚至 Quicktime)等程序中,我可以调低输入电平,但不会被削波。

当然,将样本帧乘以一小部分是行不通的,因为我得到的音量较低,但样本本身在输入时仍然被剪裁。

如何设置内置输入的输入电平或增益以避免削波问题?


这适用于我在 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;
}

编辑回答你的问题,“我是怎么解决这个问题的?”

在过去五年左右的时间里,我花了很多时间使用苹果的音频代码,并且在涉及到在哪里以及如何寻找解决方案时,我已经形成了一些直觉/流程。我和我的商业伙伴共同为第一代 iPhone 和其他一些设备编写了最初的 iHeartRadio 应用程序,我在该项目中的职责之一是音频部分,特别是为 iOS 编写 AAC Shoutcast 流解码器/播放器。当时没有任何文档或开源示例,因此涉及大量的反复试验,我学到了很多东西。

无论如何,当我读到你的问题并看到赏金时,我认为这只是唾手可得的成果(即你没有 RTFM ;-)。我写了几行代码来设置音量属性,当这不起作用时,我真的很感兴趣。

从流程角度来看,您可能会发现这很有用:

一旦我知道这不是一个简单的答案,我就开始思考how来解决问题。我知道声音系统首选项可以让你设置输入增益,所以我开始用 otool 对其进行反汇编,看看 Apple 是否使用旧的或新的音频工具箱例程(碰巧是新的):

尝试使用:

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

然后搜索Audio查看调用了哪些方法(如果您没有 bbedit(我认为每个 Mac 开发人员都应该使用 bbedit),请将其转储到文件中并在其他文本编辑器中打开)。

我最熟悉的是较旧的、已弃用的 Audio Toolbox 例程(在这个行业已经过时了三年),所以我查看了 Apple 的一些技术说明。他们有一个演示如何获取默认输入设备并使用最新的 CoreAudio 方法设置其音量,但正如您无疑看到的那样,他们的代码无法正常工作(至少在我的 MBP 上)。

一旦我到达这一点,我就回到了经过验证的方法:开始谷歌搜索可能涉及的关键字(例如AudioObjectSetPropertyData, kAudioDevicePropertyVolumeScalar等)寻找示例用法。

关于 CoreAudio 和使用 Apple Toolbox,我发现的一件有趣的事情是,有一个lot大量的开源代码可供人们尝试各种事物(大量的 Pastebin 和 GoogleCode 项目等)。如果您愿意深入研究一堆这样的代码,您通常会直接找到答案或得到一些非常好的想法。

在我的搜索中,我发现最相关的内容是 Apple 技术说明,展示了如何获取默认输入设备并使用新的工具箱例程设置主输入增益(即使它在我的硬件上不起作用),并且我找到了一些代码显示了在输出设备上按通道设置增益。由于输入设备可以是多通道的,我认为这是下一个要尝试的合乎逻辑的事情。

你的问题非常好,因为至少现在苹果还没有正确的文档来说明如何按照你的要求进行操作。这也很愚蠢,因为两个通道都报告它们设置了音量,但显然只有其中一个通道设置了音量(输入麦克风是单声道源,所以这并不奇怪,但我认为有一个无操作通道,并且没有关于它的文档) Apple 上的一个错误)。

当你开始接触苹果的尖端技术时,这种情况经常发生。你可以用他们的工具箱做一些令人惊奇的事情,它让我曾经开发过的所有其他操作系统都大吃一惊,但不需要太长时间就能超越他们的文档,特别是如果你试图做任何适度复杂的事情。

例如,如果您决定编写内核驱动程序,您会发现 IOKit 上的文档严重不足。最终,你必须上网并挖掘源代码,无论是其他人的项目还是 OS X 源代码,或者两者兼而有之,很快你就会得出结论,就像我所知道的那样,源代码确实是获得答案的最佳位置(尽管 StackOverflow非常棒)。

感谢您的积分,祝您的项目顺利:)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何设置内置输入(OSX Core Audio / Audio Unit)的输入电平(增益)? 的相关文章

随机推荐

  • Django/Python - 每秒更新数据库

    我正在努力用 Django 和 Python 创建一个基于浏览器的游戏 并且我正在尝试为我遇到的问题之一找到解决方案 本质上 每一秒都需要更新多个用户变量 例如 有一个货币变量应该每秒增加一定数量 随着你的升级和所有这些爵士乐而逐渐变大 我
  • 在 Kotlin 中编写 React Native Android 模块?

    React Native 文档提供了吐司模块 https facebook github io react native docs native modules android html用java编写的例子 同样的例子在 Kotlin 中是
  • JSON和Unity,在游戏上显示图像[重复]

    这个问题在这里已经有答案了 我有一个测验游戏应用程序 并且我有游戏上的图像 我想显示图像 文本显示得很好 但图像却不是 这是我的 JSON C 代码 点击这里图片 https i stack imgur com AEaFB png 调用我的
  • 为什么 Rails 不断发回 Set-Cookie 标头?

    我遇到了弹性负载均衡器和清漆缓存的问题 涉及 cookie 和会话在 Rails 和客户端之间混淆 问题的一部分是 rails 几乎在每个请求上都添加了一个带有会话 ID 的 Set Cookie 标头 如果客户端已经发送session i
  • 谜题:在四个反射墙内,激光束可以通过多少种方式击中目标

    你在一个长方形的房间里遇到敌人 你只有一把激光武器 房间里没有任何障碍物 墙壁可以完全反射激光束 然而 激光只能传播一定的距离 然后就变得毫无用处 如果它撞到角落 它会沿着它来的方向反射回来 这就是谜题的进行方式 您将获得自己所在位置和目标
  • 对汇编中的指针和值感到困惑

    我正在使用 MASM 汇编器 让我们看一下这段简短的代码 来自我读过的一本书 data var1 BYTE 10h code main proc mov esi OFFSET byteVal mov al esi AL 10h 我不太明白
  • 如何计算多个纬度和经度之间的距离?

    I want to calculate total distance between each points both contains lat and long these points are stored in local datab
  • 如何创建 jQuery 价格滑块

    我一直在尝试寻找教程 但没有成功 我并不是要求任何人为我做这项工作 而是更多地看看是否有人知道任何有用的东西 所以基本上我需要我的滑块具有最小值为零和动态设置的最大值 获取动态值不是问题 0 o 200 所以中间的 o 将是可点击的滑动元素
  • 使用 jQuery 从 URL 加载动态 div 内容

    我有一个 jQuery 搜索脚本 它使用选项卡让用户定义他们想要使用的搜索类型 当用户搜索时 会创建一个类似于 的 URLtype query 当您重新加载页面时 结果丢失的原因是它们不在文档源中 它们后来被添加到 DOM 中 我认为你有两
  • 如何在c#中仅在耳机的左声道和仅在耳机的右声道播放声音?

    我需要仅在耳机的左声道上播放声音 wav 文件 而另一个文件仅在耳机的右声道上播放 我是c 新手 请帮我解决这个问题 我认为仅 WPF 无法做到这一点 但您可能想查看一下NAudio http naudio codeplex com
  • Blazor.net UI 不渲染任何内容

    我正在开发 Blaor Net 应用程序 参考了互联网上的许多帖子 我面临的问题是 我想将代码从 UI 移动到单独的文件 以保持 razor 文件干净 可读和可理解 为此 我将 UI 端 C 代码保存到一个从 BaseComponent 继
  • 使用 OpenCV 洪水填充

    我只是想使用洪水填充 但它失败了 而且我从未使用过它 所以我认为我做错了什么 Mat flooded new Mat Point flood new Point 1 1 floodedmat Mat zeros myMat2 size Cv
  • 将正则表达式应用于子字符串而不使用字符串切片

    我想在较大的字符串中搜索正则表达式匹配从某个位置开始 and 不使用字符串切片 我的背景是我想迭代地搜索字符串以查找各种正则表达式的匹配项 Python 中的一个自然解决方案是跟踪字符串中的当前位置并使用例如 re match regex
  • jquery:检测滚动位置

    我希望在滚动时看到页脚时收到警报 window on mousewheel function if window scrollTop window height gt footer position top alert footer vis
  • T-SQL 是否有用于连接字符串的聚合函数? [复制]

    这个问题在这里已经有答案了 可能的重复 SQL Server 2000中的内爆类型函数 https stackoverflow com questions 534724 implode type function in sql server
  • 将 Whatsapp Markdown 转换为 HTML 标签

    我需要将 Whatsapp markdown 转换为 HTML 标签 Eg Bold to b Bold b Italic to i Italic i 我想使用正则表达式来捕获字符串中的单词 这是链接 包含测试用例 以及我的最佳尝试 htt
  • 为什么loadedmetadata 不能持续触发

    有谁知道为什么loadedmetadata在chrome上不能持续触发 如果您在检查控制台时打开此页面并保持刷新 您将看到只有三分之一会触发 http output jsbin com petefipepa http output jsbi
  • Base64 反序列化期间的空引用异常 (C#)

    我使用以下方法来序列化和反序列化 NET 对象 public static string SerializeToBase64 object data var stream new MemoryStream var formatter new
  • 在lua中使用cURL

    我正在尝试在一个小 lua 脚本中使用curl 库 我知道有一个 k 选项可以禁用curl默认执行的认证验证 但我一直无法找到如何通过代码来做到这一点 到目前为止 这是我所拥有的 local cURL require cURL header
  • 如何设置内置输入(OSX Core Audio / Audio Unit)的输入电平(增益)?

    我有一个 OSX 应用程序 它使用音频单元记录音频数据 音频单元的输入可以设置为任何可用的输入源 包括内置输入 问题是 我从内置输入获得的音频经常被削波 而在 Audacity 甚至 Quicktime 等程序中 我可以调低输入电平 但不会