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

时间:2017-10-13 11:02:21

标签: swift avaudioengine

我在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
    }
  }

如果有人知道如何处理这个问题,请提前感谢!

1 个答案:

答案 0 :(得分:4)

在C中表示一个24位的int并不好玩,所以在Swift中我确定它非常痛苦,而且无论如何都没有API支持它。您最好的选择是转换为更方便的格式进行处理。

AVAudioFile有两种格式和一个内部转换器,可以在它们之间进行转换。其fileFormat表示磁盘上文件的格式,而processingformat表示读取时lpcm数据的格式,以及写入时将接受的lpcm数据的格式。

典型的工作流程是选择标准的processingFormat,使用这种格式进行所有处理,并让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)

}