如何将Int16音频样本的数据转换为浮动音频样本的数组 [英] How to convert Data of Int16 audio samples to array of float audio samples
问题描述
我目前正在处理音频样本.
我从AVAssetReader获得它们,并有一个CMSampleBuffer
像这样:
I'm currently working with audio samples.
I get them from AVAssetReader and have a CMSampleBuffer
with something like this:
guard let sampleBuffer = readerOutput.copyNextSampleBuffer() else {
guard reader.status == .completed else { return nil }
// Completed
// samples is an array of Int16
let samples = sampleData.withUnsafeBytes {
Array(UnsafeBufferPointer<Int16>(
start: $0, count: sampleData.count / MemoryLayout<Int16>.size))
}
// The only way I found to convert [Int16] -> [Float]...
return samples.map { Float($0) / Float(Int16.max)}
}
guard let blockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) else {
return nil
}
let length = CMBlockBufferGetDataLength(blockBuffer)
let sampleBytes = UnsafeMutablePointer<UInt8>.allocate(capacity: length)
CMBlockBufferCopyDataBytes(blockBuffer, 0, length, sampleBytes)
sampleData.append(sampleBytes, count: length)
}
如您所见,我发现唯一可以转换[Int16]-> [Float]的是samples.map { Float($0) / Float(Int16.max)
,但是这样做会增加我的处理时间.是否存在将Int16的指针强制转换为Float的指针的另一种方法?
As you can see the only I found to convert [Int16] -> [Float] issamples.map { Float($0) / Float(Int16.max)
but by doing this my processing time is increasing. Does it exist an other way to cast a pointer of Int16 to a pointer of Float?
推荐答案
投射"或重新绑定"指针只会更改内存的方式 解释.您想从整数计算浮点值, 新值具有不同的内存表示形式(也有不同的 大小).
"Casting" or "rebinding" a pointer only changes the way how memory is interpreted. You want to compute floating point values from integers, the new values have a different memory representation (and also a different size).
因此,您以某种方式必须对所有输入值进行迭代
并计算新值.您可以做的是忽略Array
创建:
Therefore you somehow have to iterate over all input values
and compute the new values. What you can do is to omit the Array
creation:
let samples = sampleData.withUnsafeBytes {
UnsafeBufferPointer<Int16>(start: $0, count: sampleData.count / MemoryLayout<Int16>.size)
}
return samples.map { Float($0) / Float(Int16.max) }
另一种选择是使用 加速框架:
Another option would be to use the vDSP functions from the Accelerate framework:
import Accelerate
// ...
let numSamples = sampleData.count / MemoryLayout<Int16>.size
var factor = Float(Int16.max)
var floats: [Float] = Array(repeating: 0.0, count: numSamples)
// Int16 array to Float array:
sampleData.withUnsafeBytes {
vDSP_vflt16($0, 1, &floats, 1, vDSP_Length(numSamples))
}
// Scaling:
vDSP_vsdiv(&floats, 1, &factor, &floats, 1, vDSP_Length(numSamples))
我不知道这是否更快,您必须检查一下. (更新:速度更快,如ColGraff在他的回答中所示.)
I don't know if that is faster, you'll have to check. (Update: It is faster, as ColGraff demonstrated in his answer.)
显式循环也比使用map
快得多:
An explicit loop is also much faster than using map
:
let factor = Float(Int16.max)
let samples = sampleData.withUnsafeBytes {
UnsafeBufferPointer<Int16>(start: $0, count: sampleData.count / MemoryLayout<Int16>.size)
}
var floats: [Float] = Array(repeating: 0.0, count: samples.count)
for i in 0..<samples.count {
floats[i] = Float(samples[i]) / factor
}
return floats
根据您的情况,另一种选择是使用CMBlockBufferGetDataPointer()
而不是CMBlockBufferCopyDataBytes()
到分配的内存中.
An additional option in your case might be to use CMBlockBufferGetDataPointer()
instead of CMBlockBufferCopyDataBytes()
into allocated memory.
这篇关于如何将Int16音频样本的数据转换为浮动音频样本的数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!