【发布时间】:2021-09-17 18:18:09
【问题描述】:
我想在 ios 中使用 AUGraph 使用 Audiounit 播放立体声,但我面临的问题是“当我想以 48000 采样率在立体声模式下播放时,我的声音播放速度很快”。但它适用于单声道声音(单声道)。
这是我的代码。
import Combine
import AudioUnit
import Foundation
import AudioToolbox
import AVFoundation
@objc protocol AudioUnitDataChannelPlayoutDelegate
{
func performInput(
_ ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
inTimeStamp: UnsafePointer<AudioTimeStamp>,
inBufNumber: UInt32,
inNumberFrames: UInt32,
ioData: UnsafeMutablePointer<AudioBufferList> ) -> OSStatus
}
private let AudioController_InputCallback: AURenderCallback =
{
(
inRefCon,
ioActionFlags,
inTimeStamp,
inBufNumber,
inNumberFrames,
ioData
)-> OSStatus in
let delegate = unsafeBitCast(inRefCon, to: AudioUnitDataChannelPlayoutDelegate.self)
let result = delegate.performInput(ioActionFlags,
inTimeStamp: inTimeStamp,
inBufNumber: inBufNumber,
inNumberFrames: inNumberFrames,
ioData: ioData!)
return noErr
}
class AudioUnitDataChannelPlayout
{
private static var instance: AudioUnitDataChannelPlayout?
public class var sharedInstance: AudioUnitDataChannelPlayout
{
if instance == nil
{
instance = AudioUnitDataChannelPlayout()
}
return instance!
}
static let audioBuffer = CircularBuffer(size: 25003904)
let kInputBus: UInt32 = 1
let kOutputBus: UInt32 = 0
var status: OSStatus?
var flag: UInt32 = 1
var ioFormat = CAStreamBasicDescription(
sampleRate: Double(48000.0),
numChannels: 2,
pcmf: .int16,
isInterleaved: true )
var timePitchFormat = CAStreamBasicDescription(
sampleRate: Double(48000.0),
numChannels: 1, // if chnges to 2 nothing happens
pcmf: .float32,
isInterleaved: false ) // if change to true then error occurs
var graph: AUGraph?
var firstConverterNode: AUNode = 0
var timePitchNode: AUNode = 0
var secondConverterNode: AUNode = 0
var outputNode: AUNode = 0
var firstConverterUnit: AudioUnit?
var timePitchUnit: AudioUnit?
var secondConverterUnit: AudioUnit?
var outputUnit: AudioUnit?
init()
{
configureAudioSession()
setupRecordingUnit()
playAudio()
}
private func setupRecordingUnit()
{
check(error: NewAUGraph(&graph), description: "Failed to create AUGraph")
var output_desc = AudioComponentDescription(
componentType: OSType(kAudioUnitType_Output),
componentSubType: OSType(kAudioUnitSubType_VoiceProcessingIO),
componentManufacturer: OSType(kAudioUnitManufacturer_Apple),
componentFlags: 0,
componentFlagsMask: 0 )
var converter_desc = AudioComponentDescription(
componentType: OSType(kAudioUnitType_FormatConverter),
componentSubType: OSType(kAudioUnitSubType_AUConverter),
componentManufacturer: OSType(kAudioUnitManufacturer_Apple),
componentFlags: 0,
componentFlagsMask: 0 )
var varispeed_desc = AudioComponentDescription(
componentType: OSType(kAudioUnitType_FormatConverter),
componentSubType: OSType(kAudioUnitSubType_NewTimePitch),
componentManufacturer: OSType(kAudioUnitManufacturer_Apple),
componentFlags: 0,
componentFlagsMask: 0 )
check(error: AUGraphAddNode(graph!, &output_desc, &outputNode), description: "Failed to Add Node Audio Node")
check(error: AUGraphAddNode(graph!, &converter_desc, &firstConverterNode), description: "Failed to Add converter node")
check(error: AUGraphAddNode(graph!, &varispeed_desc, &timePitchNode), description: "Failed to Add Node varispeed Node")
check(error: AUGraphAddNode(graph!, &converter_desc, &secondConverterNode), description: "Failed to Add converter node")
check(error: AUGraphOpen(graph!), description: "Failed to open AUGraph")
check(error: AUGraphNodeInfo(graph!, outputNode, nil, &outputUnit), description: "Failed to get Info of audioUnit")
check(error: AUGraphNodeInfo(graph!, firstConverterNode, nil, &firstConverterUnit), description: "Failed to get Info of converterUnit")
check(error: AUGraphNodeInfo(graph!, timePitchNode, nil, &timePitchUnit), description: "Failed to get Info of VarispeedUnit")
check(error: AUGraphNodeInfo(graph!, secondConverterNode, nil, &secondConverterUnit), description: "Failed to get Info of converterUnit")
check(error: AudioUnitSetProperty(outputUnit!,kAudioOutputUnitProperty_EnableIO,kAudioUnitScope_Output,kOutputBus,&flag,MemoryLayoutStride.SizeOf32(flag)),
description: "Failed to set enable IO for Playing.")
check(error: AudioUnitSetProperty(firstConverterUnit!, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &ioFormat, MemoryLayoutStride.SizeOf32(ioFormat)), description: "Failed to set property of firstConverter Unit")
check(error: AudioUnitSetProperty(firstConverterUnit!, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kOutputBus, &timePitchFormat, MemoryLayoutStride.SizeOf32(timePitchFormat)), description: "Failed to set property of firstConverter Unit 1")
check(error: AudioUnitSetProperty(timePitchUnit!, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &timePitchFormat, MemoryLayoutStride.SizeOf32(timePitchFormat)), description: "Failed to set property of varispeed unit")
check(error: AudioUnitSetProperty(timePitchUnit!, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kOutputBus, &timePitchFormat, MemoryLayoutStride.SizeOf32(timePitchFormat)), description: "Failed to set property of Varispeed Unit 1")
check(error: AudioUnitSetProperty(secondConverterUnit!, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &timePitchFormat, MemoryLayoutStride.SizeOf32(timePitchFormat)), description: "Failed to set property of firstConverter Unit")
check(error: AudioUnitSetProperty(secondConverterUnit!, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kOutputBus, &ioFormat, MemoryLayoutStride.SizeOf32(ioFormat)), description: "Failed to set property of firstConverter Unit 1")
check(error: AudioUnitSetProperty(outputUnit!, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &ioFormat, MemoryLayoutStride.SizeOf32(ioFormat)), description: "Failed to set property of Output Unit")
AUGraphConnectNodeInput(graph!, firstConverterNode, 0, timePitchNode, 0)
AUGraphConnectNodeInput(graph!, timePitchNode, 0, secondConverterNode, 0)
AUGraphConnectNodeInput(graph!, secondConverterNode, 0, outputNode, 0)
var recordingCallback = AURenderCallbackStruct(
inputProc: AudioController_InputCallback,
inputProcRefCon: UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()) )
check(error: AUGraphSetNodeInputCallback(graph!, firstConverterNode, 0, &recordingCallback), description: "Failed to set inPutCallback")
AUGraphInitialize(graph!)
}
func check(error: OSStatus, description: String)
{
if error != noErr
{
fatalError("\(description) : \(error)")
}
}
func startSpeakerUnit()
{
check(error: AUGraphStart(graph!), description: "Error Failed to start AUGraph")
print("initializing the speaker unit")
}
func stopSpeakerUnit()
{
check(error: AUGraphStop(graph!), description: "Error Failed to stop AUGraph")
AudioUnitDataChannelPlayout.instance = nil
}
private func playAudio()
{
AudioUnitSetParameter(self.timePitchUnit!, kNewTimePitchParam_Rate, kAudioUnitScope_Global,0, AudioUnitParameterValue(1.0), 0)
}
}
extension AudioUnitDataChannelPlayout: AudioUnitDataChannelPlayoutDelegate
{
func performInput(_ ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>, inTimeStamp: UnsafePointer<AudioTimeStamp>, inBufNumber: UInt32, inNumberFrames: UInt32, ioData: UnsafeMutablePointer<AudioBufferList>) -> OSStatus
{
let playbackPointer = ioData[0].mBuffers
print("SECOND POINTER: \(playbackPointer)")
let bytesToCopy = ioData[0].mBuffers.mDataByteSize
var bufferTail = AudioUnitDataChannelPlayout.audioBuffer.getTail()
print(AudioUnitDataChannelPlayout.audioBuffer.getAvailableBytes())
let bytesToWrite = min(bytesToCopy, AudioUnitDataChannelPlayout.audioBuffer.getAvailableBytes())
memcpy(playbackPointer.mData, bufferTail, Int(bytesToWrite))
print("playing...\(bytesToCopy)")
AudioUnitDataChannelPlayout.audioBuffer.consume(samples: bytesToWrite)
return noErr
}
}
在这堂课中,我只是在播放立体声的波形文件。在这方面的任何帮助将不胜感激。
【问题讨论】:
-
播放速度真的更快吗?还是音高变了?或两者?所有立体声源都会发生这种情况吗?请提供有关此问题的更多详细信息,以便我们猜测可能是什么原因。
-
是的,所有立体声源都会发生这种情况,而且播放速度也非常快,我不确定它的音高是否发生了变化。这是从augraph drive.google.com/drive/folders/…传递之前和之后的wave文件的链接最后但并非最不重要的是非常感谢您的关注。
-
我不知道您的代码,但在耳朵看来,这听起来像是应用了 2x 速度效果,但没有校正由此产生的音高变化。要么您在不知情的情况下在立体声链中产生了这种效果,要么您可能遇到输入和输出之间的值不匹配等问题。
-
我看到你的代码中有一个
timePitchNode。这可能是问题的根源(无论如何我都会开始调试,然后再做任何其他事情)。例如,完全停用此效果,看看您的导出是否仍然有问题。 -
对于第一部分,我浏览了所有代码并尝试发现是否应用了速度效果,但我没有得到它。我只是在播放器中提供原始 .wav 文件,我认为它的输入和输出是相同的。对于第二部分,timepitchNode 可以很好地处理单声道声音,但我会按照你说的那样尝试。
标签: ios swift audiounit playing augraph