【问题标题】:AVAudioRecorder generates strange Wav file(wrong header)AVAudioRecorder 生成奇怪的 Wav 文件(错误的标题)
【发布时间】:2020-12-16 05:31:20
【问题描述】:

如何从 AVAudioRecorder 文件中获取唯一的 PCM 数据? 这些是我用来记录文件的设置:

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

结果是带有奇怪标题的奇怪 wav 文件。 如何只提取 PCM 数据?

【问题讨论】:

    标签: ios swift wav avaudiorecorder


    【解决方案1】:

    wav 文件中的实际声音数据位于该文件的“数据”子块中 - this format description 可能会帮助您可视化您必须导航的结构。但也许让你感到困惑的是,Apple 在声音数据之前包含了一个名为“fllr”的额外子块,所以你也必须超越它。幸运的是,每个子块都有一个 id 和大小,因此找到数据子块仍然相对简单。

    1. 使用FileHandle打开文件
    2. 查找第 12 个字节,这将使您越过标头并将您置于第一个子块的开头(应该是 fmt)。
    3. 读取 4 个字节并转换为字符串,然后再读取 4 个字节并转换为整数。字符串是子块名称,整数是子块的大小。如果字符串不是“数据”,则向前搜索“大小”字节数并重复步骤 3。
    4. 读取文件的其余部分 - 这是您的 PCM 数据。

    【讨论】:

      【解决方案2】:

      在 Jamie 的指导下,我设法解决了这个问题。这是我的代码:

          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
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多