在 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)文件?的主要内容,如果未能解决你的问题,请参考以下文章