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

Posted

技术标签:

【中文标题】在 iOS 中,如何从数据中创建音频文件(.wav、.mp3)文件?【英文标题】:In iOS, How to create audio file(.wav, .mp3) file from data? 【发布时间】:2018-03-21 06:41:31 【问题描述】:

我正在开发 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。)”错误。

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

【问题讨论】:

你如何阅读 MP3 文件?或者得到它的路径? 只是一个建议,下载您的应用程序的容器并提取您保存的 MP3 文件,然后尝试使用您的 MAC(PC) 播放器播放 【参考方案1】:

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

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

【讨论】:

【参考方案2】:

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

参考:WAVE PCM soundfile format

这里,下面我添加了 Swift 4 代码 sn-p 供参考

//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.
        
 

【讨论】:

没有成员 - dateFileName、ARError、mediaDirectoryURL。不完整的答案。

以上是关于在 iOS 中,如何从数据中创建音频文件(.wav、.mp3)文件?的主要内容,如果未能解决你的问题,请参考以下文章

在 python 中创建 32 位浮点 wav 文件?

在 C# (WP7) 中创建音频文件

在python中创建无限WAV文件

如何收听我在 Python 中创建的音频?

PhoneGap - 如何在 iOS 文档文件夹中创建新文件

如何将您在 python 中创建的 .wav 文件保存到指定目录?