带螺旋记录仪的变速装置[iOS Swift]

带螺旋记录仪的变速装置[iOS Swift],ios,swift,core-audio,audiounit,augraph,Ios,Swift,Core Audio,Audiounit,Augraph,我们正在尝试使用AUGraph连接变速装置和输出装置。 这是我们当前的代码: var graph: AUGraph? var varispeedNode: AUNode = 0 var varispeedUnit: AudioUnit? var outputNode: AUNode = 0 var outputUnit: AudioUnit? init(_ client: UDPClient, _ tcpClient: TCPClient, _ opus

我们正在尝试使用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")
        }

    }
var图:AUGraph?
var varispeedNode:AUNode=0
音频单元:音频单元?
变量outputNode:AUNode=0
var输出单位:音频单位?
init(u客户端:UDPClient,tcpClient:tcpClient,uopshelper:opusHelper,tvTemp:UILabel){
super.init()
让success=initCircularBuffer(&circularBuffer,4096)
如果成功{
打印(“循环缓冲区初始化成功”)
}否则{
打印(“循环缓冲区初始化不成功”)
}
self.tvTemp=tvTemp
self.opusHelper=opusHelper
单调时间=单调时间()
udpClient=客户端
self.tcpClient=tcpClient
状态=新建图形(&G)
如果状态!=noErr{
打印(“新的AUGrpah错误:\(状态!)”)
}
var varispeedDesc=音频组件说明(
组件类型:OSType(kAudioUnitType_FormatConverter),
组件子类型:OSType(kAudioUnitSubType_Varispeed),
组件制造商:OSType(kAudioUnitManufacturer_Apple),
组件标志:0,
componentFlagsMask:0
)
状态=AUGraphAddNode(self.graph!、&varispeedDesc、&varispeedNode)
如果状态!=noErr{
打印(“Varispeed描述错误:\(状态!)”)
}
var outputDesc=音频组件说明(
组件类型:OSType(kAudioUnitType_输出),
componentSubType:OSType(kAudioUnitSubType_VoiceProcessingIO),
组件制造商:OSType(kAudioUnitManufacturer_Apple),
组件标志:0,
componentFlagsMask:0
)
状态=AUGraphAddNode(self.graph!、&outputDesc、&outputNode)
如果状态!=noErr{
打印(“输出描述错误\(状态!)”)
}
状态=打开(图形!)
如果状态!=noErr{
打印(“图形打开错误:\(状态!)”)
}
状态=AUGraphNodeInfo(self.graph!、self.varispeedNode、nil和varispeedUnit)
如果状态!=noErr{
打印(“Varispeed装置无法获取信息:\(状态!)”)
}
状态=AUGraphNodeInfo(self.graph!、self.outputNode、nil和outputUnit)
如果状态!=noErr{
打印(“输出单元无法获取信息:\(状态!)”)
}
让inputComponent=AudioComponentFindNext(无,&outputDesc)
状态=AudioComponentInstanceNew(inputComponent!、&outputUnit)
如果状态!=noErr{
打印(“音频组件实例新错误\(状态!)”)
}
变量标志:UInt32=1
var ioFormat=CAStreamBasicDescription(
采样器:48000.0,
数字频道:1,
pcmf:.int16,
i交错:错误
)
状态=AudioUnitSetProperty(
输出单位!,
AudioUnitPropertyID(kAudioUnitProperty_StreamFormat),
音频单位示波器(kAudioUnitScope_输入),
0,
&ioFormat!,
MemoryLayoutStride.SizeOf32(ioFormat)
)
如果状态!=noErr{
打印(“无法将流格式输入设置为输出\(状态!)”)
}
//设置MaximumFramesPerSlice属性。此属性用于向音频单元描述最大数量
//在任何一次呼叫AudioUnitRender时,都会要求其制作样本的数量
var maxFramesPerSlice:UInt32=4096
状态=AudioUnitSetProperty(
速度单位!,
AudioUnitPropertyID(kAudioUnitProperty_MaximumFramesPerSlice),
AudioUnitScope(kAudioUnitScope_Global),
0,
&maxFramesPerSlice,
MemoryLayoutStride.SizeOf32(UInt32.self)
)
如果状态!=noErr{
打印(“无法设置每片1的最大帧数\(状态!)”)
}
var playbackCallback=AURenderCallbackStruct(
inputProc:AudioController\u回放回调,
inputProcRefCon:UnsafemeutableRawPointer(未托管.passUnrepained(self).toOpaque())
)
状态=AudioUnitSetProperty(
输出单位!,
AudioUnitPropertyID(kAudioUnitProperty_SetRenderCallback),
AudioUnitScope(kAudioUnitScope_Global),
库特普特布斯,
&回放回调,

MemoryLayout

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

您可能需要尝试kAudioUnitSubType_NewTimePitch效果,而不是Varispeed效果音频单元

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


您可能还需要检查效果节点的旁路属性是否已启用,并对其进行适当设置。

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

您可能需要尝试kAudioUnitSubType_NewTimePitch效果,而不是Varispeed效果音频单元

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

您可能还希望检查效果节点的“旁路”属性是否已启用,并对其进行适当设置