繁体   English   中英

在 iOS 中,如何从数据创建音频文件(.wav、.mp3)文件?

[英]In iOS, How to create audio file(.wav, .mp3) file from data?

我正在从事硬件记录音频数据并发送到 iOS 应用程序的 BLE 项目。 我写了一个逻辑来从数据转换 mp3/wav 文件。

在这里,我从 Data 编写了 mp3 文件转换逻辑,如下所示:

func storeMusicFile(data: Data) {
     let fileName = "Record-1"
     guard mediaDirectoryURL != nil else {
           print("Error: Failed to fetch mediaDirectoryURL")
           return
     }

     let filePath = mediaDirectoryURL!.appendingPathComponent("/\(fileName).mp3")
     do {
        try data.write(to: filePath, options: .atomic)
     } catch {
        print("Failed while storing files.")
     }
}

但是在 AVAudioPlayer 中播放音频文件时,我收到“无法完成操作。(OSStatus 错误 1954115647。) ”错误。

那么,是否困惑音频文件转换逻辑错误或来自硬件的数据仍然需要解码?

@sagar-thummar 的先前回答为我节省了大量时间。 不幸的是,我不能对其进行投票或评论。 我需要做的一些更正是:

  • 将 mediaDirectoryURL 更改为 documentDirectoryURL
  • 创建 ARError 异常
  • 将采样率和每个样本的位数调整到我的设置

要创建音频文件 (.mp3/.wav),您必须动态计算头文件数据,并且需要将来自硬件的实际传输音频数据附加到该头文件中。

参考: WAVE PCM 声音文件格式

在这里,下面我添加了 Swift 4 代码片段以供参考

//MARK: Logic for Creating Audio file

class ARFileManager {

      static let shared = ARFileManager()
      let fileManager = FileManager.default

      var documentDirectoryURL: URL? {
          return fileManager.urls(for: .documentDirectory, in: .userDomainMask).first
      }

      func createWavFile(using rawData: Data) throws -> URL {
           //Prepare Wav file header
           let waveHeaderFormate = createWaveHeader(data: rawData) as Data

           //Prepare Final Wav File Data
           let waveFileData = waveHeaderFormate + rawData

           //Store Wav file in document directory.
           return try storeMusicFile(data: waveFileData)
       }

       private func createWaveHeader(data: Data) -> NSData {

            let sampleRate:Int32 = 2000
            let chunkSize:Int32 = 36 + Int32(data.count)
            let subChunkSize:Int32 = 16
            let format:Int16 = 1
            let channels:Int16 = 1
            let bitsPerSample:Int16 = 8
            let byteRate:Int32 = sampleRate * Int32(channels * bitsPerSample / 8)
            let blockAlign: Int16 = channels * bitsPerSample / 8
            let dataSize:Int32 = Int32(data.count)

            let header = NSMutableData()

            header.append([UInt8]("RIFF".utf8), length: 4)
            header.append(intToByteArray(chunkSize), length: 4)

            //WAVE
            header.append([UInt8]("WAVE".utf8), length: 4)

            //FMT
            header.append([UInt8]("fmt ".utf8), length: 4)

            header.append(intToByteArray(subChunkSize), length: 4)
            header.append(shortToByteArray(format), length: 2)
            header.append(shortToByteArray(channels), length: 2)
            header.append(intToByteArray(sampleRate), length: 4)
            header.append(intToByteArray(byteRate), length: 4)
            header.append(shortToByteArray(blockAlign), length: 2)
            header.append(shortToByteArray(bitsPerSample), length: 2)

            header.append([UInt8]("data".utf8), length: 4)
            header.append(intToByteArray(dataSize), length: 4)

            return header
       }

      private func intToByteArray(_ i: Int32) -> [UInt8] {
            return [
              //little endian
              UInt8(truncatingIfNeeded: (i      ) & 0xff),
              UInt8(truncatingIfNeeded: (i >>  8) & 0xff),
              UInt8(truncatingIfNeeded: (i >> 16) & 0xff),
              UInt8(truncatingIfNeeded: (i >> 24) & 0xff)
             ]
       }

       private func shortToByteArray(_ i: Int16) -> [UInt8] {
              return [
                  //little endian
                  UInt8(truncatingIfNeeded: (i      ) & 0xff),
                  UInt8(truncatingIfNeeded: (i >>  8) & 0xff)
              ]
        }

       func storeMusicFile(data: Data) throws -> URL {

             let fileName = "Record \(Date().dateFileName)"

             guard mediaDirectoryURL != nil else {
                debugPrint("Error: Failed to fetch mediaDirectoryURL")
                throw ARError(localizedDescription:             AlertMessage.medioDirectoryPathNotAvaiable)
              }

             let filePath = mediaDirectoryURL!.appendingPathComponent("\(fileName).wav")
              debugPrint("File Path: \(filePath.path)")
              try data.write(to: filePath)

             return filePath //Save file's path respected to document directory.
        }
 }

暂无
暂无

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

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