3

我正在尝试在 Swift 中以编程方式填充 AVAudioPCMBuffer 以构建节拍器。这是我正在尝试构建的第一个真正的应用程序,所以它也是我的第一个音频应用程序。现在我正在尝试不同的框架和方法来准确地循环节拍器。

我正在尝试构建一个具有度量/条长度的 AVAudioPCMBuffer,以便我可以使用 AVAudioPlayerNode 的 scheduleBuffer 方法的 .Loops 选项。我首先将我的文件(2 ch,44100 Hz,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. 

编辑:i += 1感谢hotpaw2,我删除了明显的错误。播放 barBuffer 时,仍然缺少正确的通道。

4

2 回答 2

3

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

希望这可以帮助!

于 2016-02-24T11:50:14.663 回答
1

这看起来像是对 Swift "for" 循环的误解。Swift "for" 循环自动增加 "i" 数组索引。但是您在循环体中再次增加它,这意味着您最终会跳过初始缓冲区中的所有其他样本(右通道)。

于 2016-02-20T19:36:48.673 回答