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". Но вы снова увеличиваете его в теле цикла, что означает, что вы в конечном итоге пропускаете все остальные семплы (правый канал) в своем первоначальном буфере.

Другие вопросы по тегам