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

问题描述 投票:2回答:1

我正在研究BLE项目,其中硬件记录音频数据并发送到iOS应用程序。我写了一个逻辑来转换数据中的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.)”错误。

那么,混淆音频文件转换逻辑是错误还是硬件数据仍然需要解码?

ios swift bluetooth-lowenergy avfoundation avaudioplayer
1个回答
1
投票

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

参考:WAVE PCM soundfile format

在这里,我在下面添加了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.
        }
 }
© www.soinside.com 2019 - 2024. All rights reserved.