简体   繁体   English

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

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

I am working on BLE project where hardware records the audio data & sending to the iOS application.我正在从事硬件记录音频数据并发送到 iOS 应用程序的 BLE 项目。 I writting a logic to convert mp3/wav file from data.我写了一个逻辑来从数据转换 mp3/wav 文件。

Here, I written mp3 file conversion logic from Data like below:在这里,我从 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.")
     }
}

But while playing an audio file in AVAudioPlayer, I am getting " The operation couldn't be completed. (OSStatus error 1954115647.) " error.但是在 AVAudioPlayer 中播放音频文件时,我收到“无法完成操作。(OSStatus 错误 1954115647。) ”错误。

So, Confused whether audio file conversion logic is wrong or data from hardware is still needs to decode?那么,是否困惑音频文件转换逻辑错误或来自硬件的数据仍然需要解码?

The previous answer from @sagar-thummar saved me a ton of time. @sagar-thummar 的先前回答为我节省了大量时间。 Unfortunately I am not allowed to vote or comment on it.不幸的是,我不能对其进行投票或评论。 A few corrections I need to do was:我需要做的一些更正是:

  • change mediaDirectoryURL to documentDirectoryURL将 mediaDirectoryURL 更改为 documentDirectoryURL
  • create ARError exception创建 ARError 异常
  • adjust the sample rate AND bits per sample to my settings将采样率和每个样本的位数调整到我的设置

To create a audio file(.mp3/.wav), you have to dynamically calculate header file data & need to append that header with actual transfer audio data from the hardware.要创建音频文件 (.mp3/.wav),您必须动态计算头文件数据,并且需要将来自硬件的实际传输音频数据附加到该头文件中。

Reference: WAVE PCM soundfile format参考: WAVE PCM 声音文件格式

Here, below I added Swift 4 code snippet for reference在这里,下面我添加了 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