AVAudioPlayerNode多声道音频控制

时间:2017-05-28 00:13:04

标签: swift mono core-audio surround avaudiopcmbuffer

我已成功使用AVAudioPlayerNode播放立体声和单声道文件。我想使用具有3个以上通道(环绕文件)的文件,并能够以非线性方式路由音频。例如,我可以将文件通道0分配给输出通道2,将文件通道4分配给输出通道1.

音频接口的输出数量将是未知的(2-40),这就是为什么我需要能够允许用户在他们认为合适时路由音频的原因。而WWDC 2015 507中用户更改Audio Midi Setup中的路由的解决方案并不是一个可行的解决方案。

我能想到的只有一种可能性(而且我对其他人开放):每个频道创建一个播放器,并且每个频道只加载一个频道'值得缓冲similar to this post。但即使是海报的录取,也存在问题。

所以我正在寻找一种方法将文件的每个频道复制到AudioBuffer中,如:

let file = try AVAudioFile(forReading: audioURL)
let fullBuffer = AVAudioPCMBuffer(pcmFormat: file.processingFormat, 
                                  frameCapacity: AVAudioFrameCount(file.length))

try file.read(into: fullBuffer)

// channel 0
let buffer0 = AVAudioPCMBuffer(pcmFormat: file.processingFormat,
                               frameCapacity: AVAudioFrameCount(file.length))

// this doesn't work, unable to get fullBuffer channel and copy
// error on subscripting mBuffers
buffer0.audioBufferList.pointee.mBuffers.mData = fullBuffer.audioBufferList.pointee.mBuffers[0].mData

// repeat above buffer code for each channel from the fullBuffer

1 个答案:

答案 0 :(得分:0)

我能够弄清楚,所以这里的代码是为了让它发挥作用。注意:下面的代码分隔立体声(2声道)文件。这可以很容易地扩展到处理未知数量的频道。

let file = try AVAudioFile(forReading: audioURL)

let formatL = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: file.processingFormat.sampleRate, channels: 1, interleaved: false)
let formatR = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: file.processingFormat.sampleRate, channels: 1, interleaved: 

let fullBuffer = AVAudioPCMBuffer(pcmFormat: file.processingFormat, frameCapacity: AVAudioFrameCount(file.length))
let bufferLeft = AVAudioPCMBuffer(pcmFormat: formatL, frameCapacity: AVAudioFrameCount(file.length))
let bufferRight = AVAudioPCMBuffer(pcmFormat: formatR, frameCapacity: AVAudioFrameCount(file.length))

try file.read(into: fullBuffer)
bufferLeft.frameLength = fullBuffer.frameLength
bufferRight.frameLength = fullBuffer.frameLength

for i in 0..<Int(file.length) {
    bufferLeft.floatChannelData![0][i] = fullBuffer.floatChannelData![0][i]
    bufferRight.floatChannelData![0][i] = fullBuffer.floatChannelData![1][i]
}