AVAudioPlayerNode управление многоканальным звуком

Я успешно использовал AVAudioPlayerNode для воспроизведения стереофонических и монофонических файлов. Я хотел бы использовать файлы с 3+ каналами (объемные файлы) и иметь возможность направлять звук нелинейным способом. Например, я мог бы назначить файловый канал 0 для выходного канала 2, а файловый канал 4 - для выходного канала 1.

Количество выходов аудиоинтерфейса будет неизвестно (2-40), и поэтому мне нужно иметь возможность разрешить пользователю направлять аудио по своему усмотрению. И решение WWDC 2015 507 о том, чтобы пользователь изменил маршрутизацию в Audio Midi Setup, не является жизнеспособным решением.

Есть только одна возможность, о которой я могу подумать (и я открыт для других): создание одного проигрывателя на канал и загрузка каждого из буферов, состоящих только из одного канала, аналогично этому посту. Но даже при поступлении плакатов есть проблемы.

Поэтому я ищу способ скопировать каждый канал файла в 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 ответ

Я смог понять это, так что вот код, чтобы заставить его работать. Примечание: приведенный ниже код разделяет стереофонический (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]
}
Другие вопросы по тегам