简体   繁体   English

AVAudioRecorder 生成奇怪的 Wav 文件(标题错误)

[英]AVAudioRecorder generates strange Wav file(wrong header)

How can I get the only the PCM data from AVAudioRecorder file?如何从 AVAudioRecorder 文件中获取唯一的 PCM 数据? these are the settings I use to record the file:这些是我用来记录文件的设置:

        let settings : [String : Any] = [
            AVFormatIDKey: Int(kAudioFormatLinearPCM),
            AVSampleRateKey: Int(stethoscopeSampleRateDefault),
            AVNumberOfChannelsKey: 1,
            AVEncoderAudioQualityKey: AVAudioQuality.medium.rawValue,
        ]

the outcome of this is strange wav file with strange header.这样做的结果是带有奇怪标题的奇怪 wav 文件。 How can I extract only the PCM data out of it?如何仅从中提取 PCM 数据?

The actual sound data in a wav file is in the "data" subchunk of that file - this format description might help you visualize the structure you'll have to navigate. wav 文件中的实际声音数据位于该文件的“数据”子块中 -这种格式描述可能会帮助您可视化您必须导航的结构。 But maybe what's tripping you up is that Apple includes an extra subchunk called "fllr" which precedes the sound data, so you have to seek past that too.但也许让您感到困惑的是,Apple 在声音数据之前包含了一个名为“fllr”的额外子块,因此您也必须寻找过去。 Fortunately every subchunk is given an id and size, so finding the data subchunk is still relatively straightforward.幸运的是,每个子块都有一个 id 和大小,因此找到数据子块仍然相对简单。

  1. Open the file using FileHandle使用FileHandle打开文件
  2. Seek to byte 12, which gets you past the header and puts you at the beginning of the first subchunk (should be fmt).寻找第 12 字节,它使您通过标题并将您置于第一个子块的开头(应该是 fmt)。
  3. Read 4 bytes and convert to a string, then read 4 more bytes and convert to an integer.读取 4 个字节并转换为字符串,然后再读取 4 个字节并转换为整数。 The string is the subchunk name, and the integer is the size of that subchunk.字符串是子块名称,整数是该子块的大小。 If the string is not "data" then seek forward "size" number of bytes and repeat step 3.如果字符串不是“数据”,则向前查找“大小”字节数并重复步骤 3。
  4. Read the rest of the file - this is your PCM data.阅读文件的其余部分 - 这是您的 PCM 数据。

With Jamie's guidance I managed to solve this.在杰米的指导下,我设法解决了这个问题。 Here is my code:这是我的代码:

    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
    }

Here's the definition for RiffFile and SubChunk structs:这是 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM