问题描述
如何从AVAudioRecorder文件中获取唯一的PCM数据? 这些是我用来记录文件的设置:
let settings : [String : Any] = [
AVFormatIDKey: Int(kAudioFormatLinearPCM),AVSampleRateKey: Int(stethoscopeSampleRateDefault),AVNumberOfChannelsKey: 1,AVEncoderAudioQualityKey: AVAudioQuality.medium.rawValue,]
此结果是带有奇怪头的奇怪wav文件。 如何仅从其中提取PCM数据?
解决方法
wav文件中的实际声音数据在该文件的“数据”子块中-this format description可以帮助您可视化要导航的结构。但也许令您感到困扰的是,Apple在声音数据之前还包含一个名为“ fllr”的额外子块,因此您也必须超越它。幸运的是,每个子块都有一个id和大小,因此查找数据子块仍然相对简单。
- 使用
FileHandle
打开文件
- 搜索第12个字节,它使您越过标题并将您放在第一个子块的开头(应为fmt)。
- 读取4个字节并转换为字符串,然后再读取4个字节并转换为整数。字符串是子块名称,整数是该子块的大小。如果字符串不是“数据”,则向前搜索“大小”字节数,然后重复步骤3。
- 读取文件的其余部分-这是您的PCM数据。
在杰米的指导下,我设法解决了这个问题。这是我的代码:
func extractSubchunks(data:Data) -> RiffFile?{
var data = data
var chunks = [SubChunk]()
let position = data.subdata(in: 8..<12)
let filelength = Int(data.subdata(in: 4..<8).uint32)
let wave = String(bytes: position,encoding: .utf8) ?? "NoName"
guard wave == "WAVE" else {
print("File is \(wave) not WAVE")
return nil
}
data.removeSubrange(0..<12)
print("Found chunks")
while data.count != 0{
let position = data.subdata(in: 0..<4)
let length = Int(data.subdata(in: 4..<8).uint32)
guard let current = String(bytes: position,encoding: .utf8) else{
return nil
}
data.removeSubrange(0..<8)
let chunkData = data.subdata(in: 0..<length)
data.removeSubrange(0..<length)
let subchunk = SubChunk(name: current,size: length,data: chunkData)
chunks.append(subchunk)
print(subchunk.debugDescription)
}
let riff = RiffFile(size: filelength,subChunks: chunks)
return riff
}
这是RiffFile和SubChunk结构的定义:
struct RiffFile {
var size : Int
var subChunks : [SubChunk]
}
struct SubChunk {
var debugDescription: String {
return "name : \(name) size : \(size) dataAssignedsize : \(data.count)"
}
var name : String
var size : Int
var data : Data
}