如何将Int16音频样本的数据转换为浮动音频样本的数组 [英] How to convert Data of Int16 audio samples to array of float audio samples

查看:192
本文介绍了如何将Int16音频样本的数据转换为浮动音频样本的数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在处理音频样本. 我从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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆