带 AuGraph 的变速单元 [iOS Swift]

Posted

技术标签:

【中文标题】带 AuGraph 的变速单元 [iOS Swift]【英文标题】:Varispeed Unit with AuGraph [iOS Swift] 【发布时间】:2020-03-05 16:53:59 【问题描述】:

我们正在尝试使用 AUGraph 将变速单元与输出单元连接起来。 这是我们当前的代码:

var graph: AUGraph?
    var varispeedNode: AUNode = 0
    var varispeedUnit: AudioUnit?
    var outputNode: AUNode = 0
    var outputUnit: AudioUnit?

    init(_ client: UDPClient, _ tcpClient: TCPClient, _ opusHelper: OpusHelper, _ tvTemp: UILabel) 
        super.init()
        let success = initCircularBuffer(&circularBuffer, 4096)
        if success 
            print("Circular buffer init was successful")
         else 
            print("Circular buffer init not successful")
        

        self.tvTemp = tvTemp
        self.opusHelper = opusHelper
        monotonicTimer = MonotonicTimer()

        udpClient = client
        self.tcpClient = tcpClient

        status = NewAUGraph(&graph)

        if status != noErr 
            print("NEW AUGrpah ERROR: \(status!)")
        

        var varispeedDesc = AudioComponentDescription(
            componentType: OSType(kAudioUnitType_FormatConverter),
            componentSubType: OSType(kAudioUnitSubType_Varispeed),
            componentManufacturer: OSType(kAudioUnitManufacturer_Apple),
            componentFlags: 0,
            componentFlagsMask: 0
        )

        status = AUGraphAddNode(self.graph!, &varispeedDesc, &varispeedNode)

        if status != noErr 
            print("Varispeed desc ERRROR: \(status!)")
        

        var outputDesc = AudioComponentDescription(
            componentType: OSType(kAudioUnitType_Output),
            componentSubType: OSType(kAudioUnitSubType_VoiceProcessingIO),
            componentManufacturer: OSType(kAudioUnitManufacturer_Apple),
            componentFlags: 0,
            componentFlagsMask: 0
        )

        status = AUGraphAddNode(self.graph!, &outputDesc, &outputNode)

        if status != noErr 
            print("Output Desc ERROR \(status!)")
        

        status = AUGraphOpen(graph!)

        if status != noErr 
            print("AUGraph open ERROR: \(status!)")
        

        status = AUGraphNodeInfo(self.graph!, self.varispeedNode, nil, &varispeedUnit)

        if status != noErr 
            print("Varispeed Unit Unable to get INFO: \(status!)")
        

        status = AUGraphNodeInfo(self.graph!, self.outputNode, nil, &outputUnit)

        if status != noErr 
            print("Output Unit Unable to get INFO: \(status!)")
        


        let inputComponent = AudioComponentFindNext(nil, &outputDesc)

        status = AudioComponentInstanceNew(inputComponent!, &outputUnit)
        if status != noErr 
            print("Audio component instance new error \(status!)")
        

        var flag: UInt32 = 1



        var ioFormat = CAStreamBasicDescription(
            sampleRate: 48000.0,
            numChannels: 1,
            pcmf: .int16,
            isInterleaved: false
        )


        status = AudioUnitSetProperty(
            outputUnit!,
            AudioUnitPropertyID(kAudioUnitProperty_StreamFormat),
            AudioUnitScope(kAudioUnitScope_Input),
            0,
            &ioFormat!,
            MemoryLayoutStride.SizeOf32(ioFormat)
        )
        if status != noErr 
            print("Unable to set stream format input to output \(status!)")
        


        // Set the MaximumFramesPerSlice property. This property is used to describe to an audio unit the maximum number
        // of samples it will be asked to produce on any single given call to AudioUnitRender
        var maxFramesPerSlice: UInt32 = 4096
        status = AudioUnitSetProperty(
            varispeedUnit!,
            AudioUnitPropertyID(kAudioUnitProperty_MaximumFramesPerSlice),
            AudioUnitScope(kAudioUnitScope_Global),
            0,
            &maxFramesPerSlice,
            MemoryLayoutStride.SizeOf32(UInt32.self)
        )
        if status != noErr 
            print("Unable to set max frames per slice 1 \(status!)")
        

        var playbackCallback = AURenderCallbackStruct(
            inputProc: AudioController_PlaybackCallback,
            inputProcRefCon: UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
        )

        status = AudioUnitSetProperty(
            outputUnit!,
            AudioUnitPropertyID(kAudioUnitProperty_SetRenderCallback),
            AudioUnitScope(kAudioUnitScope_Global),
            kOutputBus,
            &playbackCallback,
            MemoryLayout<AURenderCallbackStruct>.size.ui
        )
        if status != noErr 
            print("Failed to set recording render callback \(status!)")
        

        status = AUGraphConnectNodeInput(
            graph!,
            varispeedNode,
             AudioUnitElement(0),
            outputNode,
             AudioUnitElement(0)
        )

        if status != noErr 
            print("Failed to connect varispeed node to output node \(status!)")
        


        status = AudioUnitSetParameter(
            varispeedUnit!,
            AudioUnitParameterID(kVarispeedParam_PlaybackRate),
            AudioUnitScope(kAudioUnitScope_Global),
           0,
            AudioUnitParameterValue(0.2000000082426955),
            0
        )

        if status != noErr 
            print("Varispeed rate failed to set \(status!)")
        

        status = AudioOutputUnitStart(outputUnit!)
        if status != noErr 
            print("Failed to initialize output unit \(status!)")
        

        if graph != nil 
            var outIsInitialized = DarwinBoolean(false)

            status = AUGraphIsInitialized(graph!, &outIsInitialized)
            if status != noErr 
                print("AUGraph is initialized 1 ERROR \(status!)")
            

            if !outIsInitialized.boolValue 
                status = AUGraphInitialize(graph!)
                if status != noErr 
                    print("AUGraph is initialized 2 ERROR \(status!)")
                
             else 
                print("AUGraph is already init")
            

            var isRunning = DarwinBoolean(false)

            status = AUGraphIsRunning(graph!, &isRunning)
            if status != noErr 
                print("AUGraph is running \(status!)")
            

            if !isRunning.boolValue 
                status = AUGraphStart(graph!)
                if status != noErr 
                    print("AUGraph was not started \(status!)")
                
             else 
                print("AUGraph is running")
            
         else 
            print("Error processing graph NULL")
        

    

当我们设置速率时,我们可以听到声音,但输出不受 varispeed 属性的影响。我们正在通过 UDP 获取实时音频,并且正在尝试更改 ios 上的播放速度。

谁能指导我们正确连接变速单元输出单元

https://***.com/a/59061396/12020007

【问题讨论】:

【参考方案1】:

您可能希望输入回调位于图表的输入上,而不是中间。

您可能想尝试使用 kAudioUnitSubType_NewTimePitch 效果,而不是 Varispeed 效果音频单元。

您可能需要设置效果节点的输入和输出格式,并确保效果节点的输出格式与图表中下一个节点的输入格式匹配。

您可能还想查看效果节点的旁路属性是否启用,并进行适当设置。

【讨论】:

以上是关于带 AuGraph 的变速单元 [iOS Swift]的主要内容,如果未能解决你的问题,请参考以下文章

如何在 iOS 的 AUGraph 中添加两个 I/O 音频单元?

连接节点错误 kAudioUnitErr_PropertyNotWriteable 时 AudioToolbox AUGraph 失败

AUGraph 在 iOS 上被弃用了吗?如果是这样,啥时候?

AUGraph 回调延迟

ios 5.0 中的 ios AUGraph 音高偏移

通过 AUGraph 连接的 iOS 波形发生器