簡體   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