Varispeed Unit with AuGraph [iOS Swift]

。_饼干妹妹 提交于 2021-01-29 14:48:30

问题


We are trying to connect varispeed unit with output unit using AUGraph. This is our current code:

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")
        }

    }

We can hear the voice but the output is not affected by the varispeed property when we set the rate on it. We are getting real time audio through UDP and we are trying to change the playout speed on iOS.

Can anyone guide us to connect Varispeed unit and output Unit properly.

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


回答1:


You probably want the input callback to be on the input to your graph, not the middle.

You may want to try the kAudioUnitSubType_NewTimePitch effect, instead of the Varispeed effect audio unit.

You may need to set the format of the input and output of your effect node and make sure the output format of your effect node matches that of the input to the next node in your graph.

You might also want to check to see whether the bypass property of your effect node is enabled or not, and set it appropriately.



来源:https://stackoverflow.com/questions/60550421/varispeed-unit-with-augraph-ios-swift

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!