AVAudioPCMBuffer 以编程方式构建,不以立体声播放
AVAudioPCMBuffer built programmatically, not playing back in stereo
我正在尝试在 Swift 中以编程方式填充 AVAudioPCMBuffer 以构建节拍器。这是我尝试构建的第一个真正的应用程序,所以它也是我的第一个音频应用程序。现在我正在尝试使用不同的框架和方法来让节拍器准确循环。
我正在尝试构建一个长度为 measure/bar 的 AVAudioPCMBuffer,以便我可以使用 AVAudioPlayerNode 的 scheduleBuffer 方法的 .Loops 选项。我首先将我的文件(2 ch、44100 Hz、Float32、non-inter、*.wav 和 *.m4a 都有相同的问题)加载到缓冲区中,然后将该缓冲区逐帧复制到 barBuffer 中,帧由空帧分隔。下面的循环是我如何完成这个。
如果我安排原始缓冲区播放,它将以立体声播放,但是当我安排barBuffer 时,我只得到左声道。正如我所说,我是编程初学者,没有音频编程经验,所以这可能是我对 32 位浮点通道或这种数据类型 UnsafePointer<UnsafeMutablePointer<float>>
缺乏了解。当我查看 swift 中的 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.
编辑:感谢 hotpaw2,我删除了明显的错误 i += 1
。但是,当播放 barBuffer 时,右声道仍然丢失。
这看起来像是对 Swift "for" 循环的误解。 Swift "for" 循环自动递增 "i" 数组索引。但是您在循环体中再次递增它,这意味着您最终会跳过初始缓冲区中的所有其他样本(右通道)。
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]
}
}
希望对您有所帮助!
我正在尝试在 Swift 中以编程方式填充 AVAudioPCMBuffer 以构建节拍器。这是我尝试构建的第一个真正的应用程序,所以它也是我的第一个音频应用程序。现在我正在尝试使用不同的框架和方法来让节拍器准确循环。
我正在尝试构建一个长度为 measure/bar 的 AVAudioPCMBuffer,以便我可以使用 AVAudioPlayerNode 的 scheduleBuffer 方法的 .Loops 选项。我首先将我的文件(2 ch、44100 Hz、Float32、non-inter、*.wav 和 *.m4a 都有相同的问题)加载到缓冲区中,然后将该缓冲区逐帧复制到 barBuffer 中,帧由空帧分隔。下面的循环是我如何完成这个。
如果我安排原始缓冲区播放,它将以立体声播放,但是当我安排barBuffer 时,我只得到左声道。正如我所说,我是编程初学者,没有音频编程经验,所以这可能是我对 32 位浮点通道或这种数据类型 UnsafePointer<UnsafeMutablePointer<float>>
缺乏了解。当我查看 swift 中的 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.
编辑:感谢 hotpaw2,我删除了明显的错误 i += 1
。但是,当播放 barBuffer 时,右声道仍然丢失。
这看起来像是对 Swift "for" 循环的误解。 Swift "for" 循环自动递增 "i" 数组索引。但是您在循环体中再次递增它,这意味着您最终会跳过初始缓冲区中的所有其他样本(右通道)。
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]
}
}
希望对您有所帮助!