Я пытаюсь воспроизвести аудиобуфер стерео из памяти (не из файла) в моем приложении iOS, но мое приложение вылетает, когда я пытаюсь прикрепить AVAudioPlayerNode 'playerNode' к AVAudioEngine 'audioEngine'. Код ошибки, который я получаю, выглядит следующим образом:
Thread 1: Exception: "required condition is false: _outputFormat.channelCount == buffer.format.channelCount"
Я не знаю, связано ли это с тем, как я объявил AVAudioEngine, AVAudioPlayerNode, если что-то не так с создаваемым мной буфером, или я неправильно прикрепляю узлы (или что-то еще!). У меня такое чувство, что это как-то связано с тем, как я создаю новый буфер. Я пытаюсь создать стереобуфер из двух отдельных массивов «моно», и, возможно, его формат неверен.
Я объявил audioEngine: AVAudioEngine! и playerNode: AVAudioPlayerNode! глобально:
var audioEngine: AVAudioEngine!
var playerNode: AVAudioPlayerNode!
Затем я загружаю аудиофайл моно-источник, который будет обрабатывать мое приложение (данные из этого файла не будут воспроизводиться, они будут загружены в массив, обработаны и затем em> загружается в новый буфер):
// Read audio file
let audioFileFormat = audioFile.processingFormat
let frameCount = UInt32(audioFile.length)
let audioBuffer = AVAudioPCMBuffer(pcmFormat: audioFileFormat, frameCapacity: frameCount)!
// Read audio data into buffer
do {
try audioFile.read(into: audioBuffer)
} catch let error {
print(error.localizedDescription)
}
// Convert buffer to array of floats
let input: [Float] = Array(UnsafeBufferPointer(start: audioBuffer.floatChannelData![0], count: Int(audioBuffer.frameLength)))
Затем массив отправляется в функцию свертки дважды, которая каждый раз возвращает новый массив. Это связано с тем, что исходный моно-файл должен стать стереофоническим звуковым буфером:
maxSignalLength = input.count + 256
let leftAudioArray: [Float] = convolve(inputAudio: input, impulse: normalisedLeftImpulse)
let rightAudioArray: [Float] = convolve(inputAudio: input, impulse: normalisedRightImpulse)
Переменная maxSignalLength в настоящее время представляет собой длину входного сигнала + длину импульсного отклика (normalisedImpulseResponse), с которым выполняется свертка, которая на данный момент равна 256. В какой-то момент это станет подходящей переменной.
Затем я объявляю и загружаю новый буфер и его формат, у меня такое ощущение, что ошибка где-то здесь, так как это будет буфер, который воспроизводится:
let bufferFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: hrtfSampleRate, channels: 2, interleaved: false)!
let outputBuffer = AVAudioPCMBuffer(pcmFormat: bufferFormat, frameCapacity: AVAudioFrameCount(maxSignalLength))!
Обратите внимание, что я не создаю буфер с чередованием, я загружаю стереофонические аудиоданные в буфер следующим образом (что, на мой взгляд, также может быть неправильным):
for ch in 0 ..< 2 {
for i in 0 ..< maxSignalLength {
var val: Float!
if ch == 0 { // Left
val = leftAudioArray[i]
// Limit
if val > 1 {
val = 1
}
if val < -1 {
val = -1
}
} else if ch == 1 { // Right
val = rightAudioArray[i]
// Limit
if val < 1 {
val = 1
}
if val < -1 {
val = -1
}
}
outputBuffer.floatChannelData![ch][i] = val
}
}
Аудио также ограничено значениями от -1 до 1.
Затем я, наконец, прихожу (пытаюсь) загрузить буфер в аудиоузел, присоединяю аудиоузел к аудио движку, запускаю аудио движок и затем воспроизводю узел.
let frameCapacity = AVAudioFramePosition(outputBuffer.frameCapacity)
let frameLength = outputBuffer.frameLength
playerNode.scheduleBuffer(outputBuffer, at: nil, options: AVAudioPlayerNodeBufferOptions.interrupts, completionHandler: nil)
playerNode.prepare(withFrameCount: frameLength)
let time = AVAudioTime(sampleTime: frameCapacity, atRate: hrtfSampleRate)
audioEngine.attach(playerNode)
audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: outputBuffer.format)
audioEngine.prepare()
do {
try audioEngine.start()
} catch let error {
print(error.localizedDescription)
}
playerNode.play(at: time)
Ошибка, которую я получаю во время выполнения:
AVAEInternal.h:76 required condition is false: [AVAudioPlayerNode.mm:712:ScheduleBuffer: (_outputFormat.channelCount == buffer.format.channelCount)]
Строка, в которой возникает эта ошибка, не отображается. Я застрял на этом некоторое время и пробовал много разных вещей, но, похоже, нет очень четкой информации о воспроизведении звука из памяти, а не из файлов с помощью AVAudioEngine из того, что я мог найти. Любая помощь будет принята с благодарностью.
Спасибо!
Редактировать # 1: Лучшее название
Изменить № 2: ОБНОВЛЕНИЕ - я выяснил, почему получаю ошибку. Похоже, это было вызвано настройкой playerNode перед его подключением к audioEngine. Смена порядка остановила сбой программы и выдачу ошибки:
let frameCapacity = AVAudioFramePosition(outputBuffer.frameCapacity)
let frameLength = outputBuffer.frameLength
audioEngine.attach(playerNode)
audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: outputBuffer.format)
audioEngine.prepare()
playerNode.scheduleBuffer(outputBuffer, at: nil, options: AVAudioPlayerNodeBufferOptions.interrupts, completionHandler: nil)
playerNode.prepare(withFrameCount: frameLength)
let time = AVAudioTime(sampleTime: frameCapacity, atRate: hrtfSampleRate)
do {
try audioEngine.start()
} catch let error {
print(error.localizedDescription)
}
playerNode.play(at: time)
Однако у меня нет звука. После создания массива с плавающей запятой в outputBuffer с помощью того же метода, который использовался для входного сигнала, и просмотра его содержимого с точкой останова он кажется пустым, поэтому я также должен неправильно сохранять данные в outputBuffer.