Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 如何将Int16音频样本数据转换为浮点音频样本数组_Swift_Audio_Nsarray_Avfoundation_Nsdata - Fatal编程技术网

Swift 如何将Int16音频样本数据转换为浮点音频样本数组

Swift 如何将Int16音频样本数据转换为浮点音频样本数组,swift,audio,nsarray,avfoundation,nsdata,Swift,Audio,Nsarray,Avfoundation,Nsdata,我目前正在处理音频样本。 我从Avassetrader获得它们,并有一个CMSampleBuffer,类似这样: guard let sampleBuffer = readerOutput.copyNextSampleBuffer() else { guard reader.status == .completed else { return nil } // Completed // samples is an array of Int16 let samples = sampleData.w

我目前正在处理音频样本。 我从Avassetrader获得它们,并有一个
CMSampleBuffer
,类似这样:

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)
}
guard let sampleBuffer=readerOutput.copyNextSampleBuffer()else{
guard reader.status==.completed else{return nil}
//完成
//samples是一个Int16数组
让samples=sampleData.withUnsafeBytes{
数组(非安全缓冲指针)(
开始:$0,计数:sampleData.count/MemoryLayout.size)
}
//我找到的唯一转换[Int16]->[Float]的方法。。。
return samples.map{Float($0)/Float(Int16.max)}
}
guard let blockBuffer=CMSampleBufferGetDataBuffer(sampleBuffer)else{
归零
}
let length=CMBlockBufferGetDataLength(块缓冲区)
让sampleBytes=UnsafeMutablePointer.allocate(容量:长度)
CMBlockBufferCopyDataBytes(块缓冲区,0,长度,采样字节)
追加(sampleBytes,计数:长度)
}

正如您所看到的,我找到的唯一转换[Int16]->[Float]的方法是
samples.map{Float($0)/Float(Int16.max)
,但通过这样做,我的处理时间在增加。是否存在将Int16指针转换为Float指针的其他方法?

用于:Xcode 8.3.3•Swift 3.1

extension Collection where Iterator.Element == Int16 {
    var floatArray: [Float] {
        return flatMap{ Float($0) }
    }
}
用法:

let int16Array: [Int16] = [1, 2, 3 ,4]    
let floatArray = int16Array.floatArray    
“投射”或“重新绑定”指针只会改变内存的使用方式 已解释。要从整数计算浮点值, 新值具有不同的内存表示形式(以及不同的 尺寸)

因此,您必须以某种方式迭代所有输入值 然后计算新的值。您可以做的是省略
数组
创建:

let samples = sampleData.withUnsafeBytes {
    UnsafeBufferPointer<Int16>(start: $0, count: sampleData.count / MemoryLayout<Int16>.size)
}
return samples.map { Float($0) / Float(Int16.max) }

在您的情况下,另一个选项可能是使用
CMBlockBufferGetDataPointer()
而不是
CMBlockBufferCopyDataBytes()

到分配的内存中。

如果使用进行转换,您可以做得更好:

import Accelerate

// Set up random [Int]
var randomInt = [Int16]()

randomInt.reserveCapacity(10000)
for _ in 0..<randomInt.capacity {
  let value = Int16(Int32(arc4random_uniform(UInt32(UInt16.max))) - Int32(UInt16.max / 2))
  randomInt.append(value)
}

// Time elapsed helper: https://stackoverflow.com/a/25022722/887210
func printTimeElapsedWhenRunningCode(title:String, operation:()->()) {
  let startTime = CFAbsoluteTimeGetCurrent()
  operation()
  let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
  print("Time elapsed for \(title): \(timeElapsed) s.")
}

// Testing

printTimeElapsedWhenRunningCode(title: "vDSP") {
  var randomFloat = [Float](repeating: 0, count: randomInt.capacity)
  vDSP_vflt16(randomInt, 1, &randomFloat, 1, vDSP_Length(randomInt.capacity))
}

printTimeElapsedWhenRunningCode(title: "map") {
  randomInt.map { Float($0) }
}

// Results
//
// Time elapsed for vDSP   : 0.000429034233093262 s.
// Time elapsed for flatMap: 0.00233501195907593 s.
导入加速
//设置随机[Int]
var randomInt=[Int16]()
随机点保留容量(10000)
对于0中的uu…()){
让startTime=CFAbsoluteTimeGetCurrent()
操作()
让时间流逝=CFAbsoluteTimeGetCurrent()-startTime
打印(“已用时间\(标题):\(已用时间)s.)
}
//测试
运行代码时的打印时间延迟(标题:“vDSP”){
var randomFloat=[Float](重复:0,计数:randomInt.capacity)
vDSP_vflt16(随机整数,1和随机浮点,1,vDSP_长度(随机整数容量))
}
运行代码时的打印时间延迟(标题:“地图”){
randomInt.map{Float($0)}
}
//结果
//
//vDSP经过的时间:0.000429034233093262秒。
//flatMap经过的时间:0.00233501195907593秒。
它的速度提高了大约5倍


(编辑:添加了Martin R建议的一些更改)

@Martin R和@ColGraff给出了非常好的答案,感谢大家和快速回复。 然而,我发现了一种更简单的方法,无需任何计算。
avassetraderaudiomixoutput
需要一个音频设置字典。在里面,我们可以设置键
AVLinearPCMIsFloatKey:true
。这样我就可以像这样读取数据

let samples = sampleData.withUnsafeBytes {
    UnsafeBufferPointer<Float>(start: $0, 
                               count: sampleData.count / MemoryLayout<Float>.size)
}
let samples=sampleData.withUnsafeBytes{
UnsafeBufferPointer(开始:$0,
计数:sampleData.count/MemoryLayout.size)
}

如果您打算将整数-32767…32767转换为-1.0…1.0,那么就是这样做的。但是您不需要创建数组,您可以映射UnsafeBufferPointer。如何“强制转换指针”?1)Int16是2个字节,浮点是4个字节。2)从整数计算浮点值。@MartinR事实上,我希望迭代通过执行
Int16value/Int16.max
来计算浮点。在Swift中不是说“这是一个Int16的指针,你能给我计算出的浮点指针吗?”?当我使用UnsafemtableRawPointer(UInt8的指针)时,我能够做一些类似的事情:
var floatValues=bytes.bindMemory(to:Float.self,capacity:bytesTotal)
Casting(或Swift行话中的“重新绑定”)只会改变内存的解释方式,而不会改变内存本身。抱歉,也许我解释得不好,但我想将Int16音频样本转换为浮点音频样本,而不必像在floatArray方法中那样重新迭代整个样本。似乎我们有相同的想法:)–一些备注:您的代码崩溃,因为randomFloat是在设置randomInt.capacity之前创建的,这使它成为一个空数组。您只需将
&randomInt.map
传递给vDSP_vflt16()。vDSP测量应包括randomInt数组创建。没有理由使用flatMap,只需
randomInt.map{Float($0)}
@MartinR Ahh是的,我将
randomFloat
的初始化移到更早的时间来整理代码,但忽略了测试。我会更正它并重新测试。谢谢!有趣的是,
对于0中的I..@MartinR,它更接近了。我仍然看到了一些改进,在使用vDSP vs for loop时,可能有50%到75%的时间。关于f vDSP、缓存以及此聊天中对测试的影响:您的第一个代码块有问题,它无法将
UnsafeBufferPointer.init
start
参数从
UnsafeRawBufferPointer
转换为
UnsafePointer?
@ColGraff:My
sampleData
具有
数据类型>.我从问题中的
sampleData.withUnsafeBytes()
猜到了。明白了,这是有道理的。
import Accelerate

// Set up random [Int]
var randomInt = [Int16]()

randomInt.reserveCapacity(10000)
for _ in 0..<randomInt.capacity {
  let value = Int16(Int32(arc4random_uniform(UInt32(UInt16.max))) - Int32(UInt16.max / 2))
  randomInt.append(value)
}

// Time elapsed helper: https://stackoverflow.com/a/25022722/887210
func printTimeElapsedWhenRunningCode(title:String, operation:()->()) {
  let startTime = CFAbsoluteTimeGetCurrent()
  operation()
  let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
  print("Time elapsed for \(title): \(timeElapsed) s.")
}

// Testing

printTimeElapsedWhenRunningCode(title: "vDSP") {
  var randomFloat = [Float](repeating: 0, count: randomInt.capacity)
  vDSP_vflt16(randomInt, 1, &randomFloat, 1, vDSP_Length(randomInt.capacity))
}

printTimeElapsedWhenRunningCode(title: "map") {
  randomInt.map { Float($0) }
}

// Results
//
// Time elapsed for vDSP   : 0.000429034233093262 s.
// Time elapsed for flatMap: 0.00233501195907593 s.
let samples = sampleData.withUnsafeBytes {
    UnsafeBufferPointer<Float>(start: $0, 
                               count: sampleData.count / MemoryLayout<Float>.size)
}