我有一系列要标准化的音频文件,因此它们都具有相似的感知响度。出于测试目的,我决定改编AVAudioPCMBuffer.normalize
AudioKit 中的方法以适应我的目的。见这里实现:https ://github.com/AudioKit/AudioKit/blob/main/Sources/AudioKit/Audio%20Files/AVAudioPCMBuffer%2BProcessing.swift
我将每个文件转换为AVAudioPCMBuffer
,然后reduce
在该缓冲区数组上执行 a 以获得所有缓冲区的最高峰。然后我创建了一个新版本的 normalize,称为normalize(with peakAmplitude: Float) -> AVAudioPCMBuffer
获取峰值幅度,计算 againFactor
然后遍历floatData
for eachchannel
并将floatData
乘以gainFactor
。然后我将我的新风格称为我normalize
从peak.amplitude
所有reduce
音频缓冲区的操作中获得的。
这有时会产生有用的结果。
这是有问题的实际代码:
extension AVAudioPCMBuffer {
public func normalize(with peakAmplitude: Float) -> AVAudioPCMBuffer {
guard let floatData = floatChannelData else { return self }
let gainFactor: Float = 1 / peakAmplitude
let length: AVAudioFrameCount = frameLength
let channelCount = Int(format.channelCount)
// i is the index in the buffer
for i in 0 ..< Int(length) {
// n is the channel
for n in 0 ..< channelCount {
let sample = floatData[n][i] * gainFactor
self.floatChannelData?[n][i] = sample
}
}
self.frameLength = length
return self
}
}
extension Array where Element == AVAudioPCMBuffer {
public func normalized() -> [AVAudioPCMBuffer] {
var minPeak = AVAudioPCMBuffer.Peak()
minPeak.amplitude = AVAudioPCMBuffer.Peak.min
let maxPeakForAllBuffers: AVAudioPCMBuffer.Peak = reduce(minPeak) { result, buffer in
guard
let currentBufferPeak = buffer.peak(),
currentBufferPeak.amplitude > result.amplitude
else {
return result
}
return currentBufferPeak
}
return map { $0.normalize(with: maxPeakForAllBuffers.amplitude) }
}
}
三个问题:
- 我的方法对多个文件是否合理?
- 这似乎是使用“峰值归一化”与 RMS 或 EBU R128 归一化。这就是为什么当我给它一批 3 个音频文件并且其中 2 个正确地变大时,即使
ffmpeg-normalize
在同一批文件上使 1 个文件明显更安静,其中 1 个也变大了? - 关于如何改变
floatData
跨倍数AVAudioAudioPCMBuffers
以使它们具有相似的感知响度的任何其他建议?