【问题标题】:Core Audio sound metering on multiple file players多个文件播放器上的 Core Audio 声音计量
【发布时间】:2017-12-28 14:29:29
【问题描述】:

我有一个 AUGraph 设置,其中有几个 File Player 音频单元馈入 MultiChannelMixer 单元,然后馈入 Remote I/O 输出。这个设置工作得很好。

现在我一直在努力添加回调,以便我可以计算各个文件播放器的声音级别。

private let meteringCallback: AURenderCallback = { (
    inRefCon,
    ioActionFlags,
    inTimeStamp,
    inBusNumber,
    frameCount,
    ioData ) -> OSStatus in

    var status = noErr

    var track: AUTrack = unsafeBitCast(inRefCon, to: AUTrack.self)

    status = AudioUnitRender(track.fileAU!,
                             ioActionFlags,
                             inTimeStamp,
                             inBusNumber,
                             frameCount,
                             ioData!);

    var samples = [Float]()
    let ptr = ioData!.pointee.mBuffers.mData?.assumingMemoryBound(to: Float.self)
    samples.append(contentsOf: UnsafeBufferPointer(start: ptr, count: Int(frameCount)))

    // ... fancy algorithm calculating DB value ...
}

AUTrack simple 保存有关该特定轨道的信息。将整个类实例传递给回调(通常在示例中这样做)在这里没有意义,因为有多个文件播放器。

现在我需要在某个地方设置这个回调,这样我就可以从每个输入混音器的文件播放器中捕获值。然而,当我尝试这样做时,我不断收到 -10877(无效元素)错误。

我尝试用这个设置计量回调。

// Set metering callback
var meteringCallbackStruct = AURenderCallbackStruct(inputProc: meteringCallback,
                                                    inputProcRefCon: &self.tracks[1])
status = AudioUnitSetProperty(self.tracks[1].fileAU!,
                          kAudioUnitProperty_SetRenderCallback,
                          kAudioUnitScope_Output,
                          0,
                          &meteringCallbackStruct,
                     UInt32(MemoryLayout<AURenderCallbackStruct>.size))

我不太确定如何解决这个问题。

除非我以某种方式将它们传回混音器单元,否则这个回调不会“吃掉”样本吗?

【问题讨论】:

    标签: swift swift3 callback core-audio audiounit


    【解决方案1】:

    您不应该在 Swift 中进行回调。渲染线程处理只能在 C/C++ 中完成。

    您可以使用render notify

    AudioUnitAddRenderNotify(mixer, my_C_callback, nil) //my_C_callback should not reference Swift objects, or be a Swift callback.
    

    它使用与渲染回调相同的函数签名。它被称为渲染前和渲染后,您想要处理渲染后。您可以从 ioActionFlags 获取此信息。

    int isPostRender = ioActionFlags & kAudioUnitRenderAction_PostRender;
    

    但是,由于您使用的是多通道混音器,因此内置了输入电平监控,因此您不需要回调。

    你先这样启用它。

    //AudioUnit mixer; kAudioUnitSubType_MultiChannelMixer 
    
    //Call Before AudioUnitInitialize()
    UInt32 meteringMode = 1;
    AudioUnitSetProperty(mixer, kAudioUnitProperty_MeteringMode, kAudioUnitScope_Input, 0, &meteringMode, sizeof(meteringMode));
    

    然后在处理过程中您可以通过读取参数来获得级别。

    int channel = 0;
    
    AudioUnitParameterValue averageDecibles;
    AudioUnitGetParameter(mixer, kMultiChannelMixerParam_PreAveragePower, kAudioUnitScope_Input, channel, &averageDecibles);
    
    AudioUnitParameterValue peakHoldDecibles;
    AudioUnitGetParameter(mixer, kMultiChannelMixerParam_PrePeakHoldLevel, kAudioUnitScope_Input, channel, &peakHoldDecibles);
    

    斯威夫特:

    var meteringMode: UInt32 = 1;
    let propSize = UInt32(MemoryLayout<UInt32>.size)
    AudioUnitSetProperty(mixer, kAudioUnitProperty_MeteringMode, kAudioUnitScope_Input, 0, &meteringMode, propSize);
    
    var averageDecibles: AudioUnitParameterValue = 0
    AudioUnitGetParameter(mixer, kMultiChannelMixerParam_PreAveragePower, kAudioUnitScope_Input, channel, &averageDecibles);
    
    var peakHoldDecibles: AudioUnitParameterValue = 0
    AudioUnitGetParameter(mixer, kMultiChannelMixerParam_PrePeakHoldLevel, kAudioUnitScope_Input, channel, &peakHoldDecibles);
    

    【讨论】:

    • 非常感谢。这对我很有帮助,我正在编写自己的混音器。我不敢相信我错过了头文件中的这些参数。 :D
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-21
    • 1970-01-01
    • 1970-01-01
    • 2011-04-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多