如何使用 AVAudioBuffer 将样本数组写入 24 位音频文件?

How to write an array of samples into a 24 bits audio file with AVAudioBuffer?

我在 swift 中使用 AVAudioEngine 编写 24 位 wav 文件时遇到问题。 对于我的用法,我的输入是一个 Float 数组。 我有输入文件的音频格式(使用 AVAudioFile 检索)。

因此,我需要将我的输入 Float 数组转换为缓冲区可写的值。另外,我想找到合适的渠道来写入我的数据。 我的代码使用 16 位和 32 位文件,但我不知道如何处理 24 位文件... 在这里:

  //Static func to write audiofile
  fileprivate func writeAudioFile(to outputURL : URL,
                                  withFormat format : AVAudioFormat,
                                  fromSamples music : [Float] )
  {
    var outputFormatSettings = format.settings
    guard let bufferFormat = AVAudioFormat(settings: outputFormatSettings) else{
      return
    }

    var audioFile : AVAudioFile?
    do{
      audioFile = try AVAudioFile(forWriting: outputURL,
                                  settings: outputFormatSettings,
                                  commonFormat: format.commonFormat,
                                  interleaved: true)
    } catch let error as NSError {
      print("error:", error.localizedDescription)
    }

    let frameCount = music.count / Int(format.channelCount)
    let outputBuffer = AVAudioPCMBuffer(pcmFormat: bufferFormat,
                                        frameCapacity: AVAudioFrameCount(frameCount))
    //We write the data in the right channel
    guard let bitDepth = (outputFormatSettings["AVLinearPCMBitDepthKey"] as? Int) else {
      return
    }
    switch bitDepth {
    case 16:
      for i in 0..<music.count {
        var floatValue = music[i]
        if(floatValue > 1){
          floatValue = 1
        }
        if(floatValue < -1){
          floatValue = -1
        }
        let value = floatValue * Float(Int16.max)
        outputBuffer?.int16ChannelData!.pointee[i] =  Int16(value)
      }
case 24:
  //Here I am not sure of what I do ... Could'nt find the right channel !
  for i in 0..<music.count {
    outputBuffer?.floatChannelData!.pointee[i] =  music[i]
  }
    case 32:
      for i in 0..<music.count {
        outputBuffer?.floatChannelData!.pointee[i] = music[i]
      }
    default:
      return
    }
    outputBuffer?.frameLength = AVAudioFrameCount( frameCount )

    do{
      try audioFile?.write(from: outputBuffer!)

    } catch let error as NSError {
      print("error:", error.localizedDescription)
      return
    }
  }

如果有人知道如何处理此问题,请提前致谢!

在 C 中表示 24 位 int 并不有趣,所以在 Swift 中我敢肯定它是彻头彻尾的痛苦,而且 API 中的 none 无论如何都支持它。最好的办法是转换为更便于处理的格式。

AVAudioFile has two formats and an internal converter to convert between them. Its fileFormat represents the format of the file on disk, while its processingformat表示读取lpcm数据时的格式,写入时接受的lpcm数据格式。

典型的工作流程是选择一种标准的处理格式,使用这种格式进行所有处理,并让 AVAudioFile 与文件格式相互转换以读取和写入磁盘。所有音频单元 API 都接受非交错格式,因此我倾向于对所有处理格式使用非交错。

下面是一个复制音频文件前半部分的示例。它没有解决您现有的代码,而是说明了一种更常见的方法:

func halfCopy(src: URL, dst: URL) throws {

    let srcFile = try AVAudioFile(forReading: src) //This opens the file for reading using the standard format (deinterleaved floating point).
    let dstFile = try AVAudioFile(forWriting: dst,
                                  settings: srcFile.fileFormat.settings,
                                  commonFormat: srcFile.processingFormat.commonFormat,
                                  interleaved: srcFile.processingFormat.isInterleaved) //AVAudioFile(forReading: src) always returns a non-interleaved processing format, this will be false

    let frameCount = AVAudioFrameCount(srcFile.length) / 2  // Copying first half of file

    guard let buffer = AVAudioPCMBuffer(pcmFormat: srcFile.processingFormat,
                                        frameCapacity: frameCount) else {
                                            fatalError("Derp")
    }

    try srcFile.read(into: buffer, frameCount: frameCount)
    try dstFile.write(from: buffer)

}