AVAudioPCMBuffer построен программно, не воспроизводится в стерео

Я пытаюсь программно заполнить AVAudioPCMBuffer в Swift, чтобы построить метроном. Это первое настоящее приложение, которое я пытаюсь создать, так что это также мое первое звуковое приложение. Прямо сейчас я экспериментирую с разными фреймворками и методами точного зацикливания метронома.

Я пытаюсь создать AVAudioPCMBuffer с длиной меры / полосы, чтобы я мог использовать параметр .Loops метода scheduleBuffer AVAudioPlayerNode. Я начинаю с загрузки своего файла (2 канала, 44100 Гц, Float32, non-inter, * .wav и * .m4a имеют одну и ту же проблему) в буфер, а затем копирую этот буфер кадр за кадром, разделенный пустыми кадрами, в barBuffer. В следующем цикле показано, как я этого добиваюсь.

Если я планирую воспроизведение исходного буфера, он будет воспроизводиться в стерео, но когда я планирую barBuffer, я получаю только левый канал. Как я уже сказал, я новичок в программировании и не имею опыта программирования звука, так что это может быть мое незнание 32-битных каналов с плавающей запятой или этого типа данных UnsafePointer<UnsafeMutablePointer<float>>. Когда я быстро смотрю на свойство floatChannelData, из описания кажется, что это должно копировать два канала.

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. 

edit: Я удалил вопиющую ошибку i += 1, спасибо hotpaw2. Правый канал все еще отсутствует при воспроизведении barBuffer.


person JGHof    schedule 20.02.2016    source источник


Ответы (2)


К небезопасным указателям в swift довольно странно привыкать.

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]
    }
}

Надеюсь это поможет!

person hola    schedule 24.02.2016
comment
Вы знаете, как работает метод readIntoBuffer? file.length возвращает 3008 (образцы, кадры?) Когда я начинаю смотреть на каналы указателя, все становится странно. Канал 0 содержит данные из buffer.floatChannelData [0] [0] - [0] [6015]. Канал 1 показывает данные из buffer.floatChannelData [1] [0] - [0] [3007]. На этом этапе числа выстраиваются в линию, я просто не знаю, что они представляют или почему на канале 0 их вдвое больше. buffer.floatChannelData [2], однако, кажется совершенно несовместимым. иногда возвращает огромные числа в электронной нотации, а иногда - ошибки неправильного доступа. Спасибо за Ваш ответ! - person JGHof; 09.03.2016
comment
@JGHof Читает аудиофайл в заданный буфер. Что ты хочешь знать? - person hola; 11.03.2016
comment
Значения тарабарщины связаны с доступом к памяти, которая была выделена, но не может быть инициализирована. Плохой доступ связан с доступом к памяти, которая не была выделена. Вот почему это небезопасно. Важно следить за длиной и количеством каналов, чтобы не получить доступ к чужой или выделенной памяти. - person hola; 11.03.2016
comment
Я не понимаю, как именно AVAudioBuffer переводит файл в буфер. Мне нужны только каналы [0] и [1], или в [2] есть данные, которые мне нужно скопировать? Вы знаете, почему в [1] вдвое меньше данных по сравнению с [0]? есть ли способ получить количество каналов программно, или мне нужно знать, как мой файл переводится в буфер? Спасибо за любую помощь, которую вы можете предоставить. - person JGHof; 11.03.2016
comment
Вот paste, показывающий, как читать аудиофайл в буфер. Да, вам нужны все каналы. Доступ только к каналам и выборкам, которые находятся в допустимом диапазоне, определяемом форматом файла и заданной длиной выборки. Это связано с тем, как распределяется память и как указатели указывают на память. Здесь выходит за рамки, но это легко узнать, погуглите по поводу указателей. Счетчик каналов извлекается из буфера или свойства формата файла аудиофайла. Для аудиофайла: processingFormat.channelCount или fileFormat.channelCount. Для буфера: format.channelCount. - person hola; 11.03.2016

Это похоже на недоразумение Swift «for» циклов. Цикл «for» Swift автоматически увеличивает индекс массива «i». Но вы снова увеличиваете его в теле цикла, что означает, что вы в конечном итоге пропускаете все остальные семплы (правый канал) в вашем начальном буфере.

person hotpaw2    schedule 20.02.2016
comment
На самом деле это не устранило проблему с отключением правого канала. Сэмпл звучит намного лучше без пропуска всех остальных сэмплов, но он по-прежнему находится только в левом канале. - person JGHof; 21.02.2016