AVAudioPCMBuffer построен программно, без воспроизведения в стерео
Я пытаюсь заполнить AVAudioPCMBuffer программно в Swift, чтобы построить метроном. Это первое настоящее приложение, которое я пытаюсь создать, так же как и мое первое аудио приложение. Прямо сейчас я экспериментирую с различными структурами и методами точного зацикливания метронома.
Я пытаюсь построить AVAudioPCMBuffer с длиной меры / бара, чтобы я мог использовать опцию.Loops метода scheduleBuffer в AVAudioPlayerNode. Я начинаю с загрузки моего файла (2 канала, 44100 Гц, Float32, non-inter, *.wav и *.m4a, оба имеют одинаковую проблему) в буфер, затем копирую этот буфер кадр за кадром, разделенный пустыми кадрами, в barBuffer. Цикл ниже, как я это делаю.
Если я запланирую воспроизведение исходного буфера, он будет воспроизводиться в стереофоническом режиме, но когда я планирую barBuffer, я получаю только левый канал. Как я уже сказал, я новичок в программировании и не имею опыта программирования аудио, так что это может быть моим недостатком знаний о 32-битных плавающих каналах или об этом типе данных. UnsafePointer<UnsafeMutablePointer<float>>
, Когда я смотрю на свойство floatChannelData в swift, описание звучит так, как будто это должно быть копирование двух каналов.
var j = 0
for i in 0..<Int(capacity) {
barBuffer.floatChannelData.memory[j] = buffer.floatChannelData.memory[i]
j += 1
}
j += Int(silenceLengthInSamples)
// loop runs 4 times for 4 beats per bar.
редактировать: я удалил явную ошибку i += 1
Спасибо hotpaw2. Правый канал все еще отсутствует при воспроизведении barBuffer.
2 ответа
Небезопасные указатели в быстром довольно странно привыкнуть.
floatChannelData.memory[j]
Доступ только к первому каналу данных. Чтобы получить доступ к другим каналам, у вас есть пара вариантов:
Используя advancedBy
// Where current channel is at 0
// Get a channel pointer aka UnsafePointer<UnsafeMutablePointer<Float>>
let channelN = floatChannelData.advancedBy( channelNumber )
// Get channel data aka UnsafeMutablePointer<Float>
let channelNData = channelN.memory
// Get first two floats of channel channelNumber
let floatOne = channelNData.memory
let floatTwo = channelNData.advancedBy(1).memory
Использование нижнего индекса
// Get channel data aka UnsafeMutablePointer<Float>
let channelNData = floatChannelData[ channelNumber ]
// Get first two floats of channel channelNumber
let floatOne = channelNData[0]
let floatTwo = channelNData[1]
Использование нижнего индекса намного понятнее, и шаг продвижения, а затем ручной доступ к памяти неявен.
Для вашего цикла попробуйте получить доступ ко всем каналам буфера, выполнив что-то вроде этого:
for i in 0..<Int(capacity) {
for n in 0..<Int(buffer.format.channelCount) {
barBuffer.floatChannelData[n][j] = buffer.floatChannelData[n][i]
}
}
Надеюсь это поможет!
Это похоже на недоразумение петель "для" Swift. Цикл Swift "for" автоматически увеличивает индекс массива "i". Но вы снова увеличиваете его в теле цикла, что означает, что вы в конечном итоге пропускаете все остальные семплы (правый канал) в своем первоначальном буфере.