【问题标题】:In iOS, How to create audio file(.wav, .mp3) file from data?在 iOS 中,如何从数据中创建音频文件(.wav、.mp3)文件?
【发布时间】: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) 播放器播放

标签: ios swift bluetooth-lowenergy avfoundation avaudioplayer


【解决方案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。不完整的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-31
    • 1970-01-01
    • 2022-08-13
    • 2017-07-06
    • 1970-01-01
    • 2015-08-01
    相关资源
    最近更新 更多