我正在研究BLE项目,其中录音机硬件连续传输数据并发送到iOS应用程序。从iOS应用程序结束,我需要读取传输的数据。
硬件将HEX数据发送到iOS应用程序,我们需要创建.mp3 / .wav文件
有人有想法从二进制/十六进制输入数据创建音频文件吗?
注意:我必须使用原始数据(Hex)来创建音频文件。
谢谢
答案 0 :(得分:1)
从您的问题中不清楚数据是如何进入的,但我现在假设您定期将Data
线性PCM数据作为您想要追加的有符号整数。如果是其他格式,则必须更改设置。这些只是通用的东西;你几乎肯定要根据你的具体问题修改它。
(大部分代码基于Create a silent audio CMSampleBufferRef)
首先你需要一个作家:
let writer = try AVAssetWriter(outputURL: outputURL, fileType: .wav)
然后你需要知道你的数据是如何格式化的(这是静静地假设数据是帧大小的倍数;如果不是这样,你需要跟踪部分帧):
let numChannels = 1
let sampleRate = 44100
let bytesPerFrame = MemoryLayout<Int16>.size * numChannels
let frames = data.count / bytesPerFrame
let duration = Double(frames) / Double(sampleRate)
let blockSize = frames * bytesPerFrame
然后你需要知道当前帧是什么。这将随着时间的推移而更新。
var currentFrame: Int64 = 0
现在您需要对数据进行描述:
var asbd = AudioStreamBasicDescription(
mSampleRate: Float64(sampleRate),
mFormatID: kAudioFormatLinearPCM,
mFormatFlags: kLinearPCMFormatFlagIsSignedInteger,
mBytesPerPacket: UInt32(bytesPerFrame),
mFramesPerPacket: 1,
mBytesPerFrame: UInt32(bytesPerFrame),
mChannelsPerFrame: UInt32(numChannels),
mBitsPerChannel: UInt32(MemoryLayout<Int16>.size*8),
mReserved: 0
)
var formatDesc: CMAudioFormatDescription?
status = CMAudioFormatDescriptionCreate(kCFAllocatorDefault, &asbd, 0, nil, 0, nil, nil, &formatDesc)
assert(status == noErr)
创建输入适配器并将其添加到编写器
let settings:[String : Any] = [ AVFormatIDKey : kAudioFormatLinearPCM,
AVNumberOfChannelsKey : numChannels,
AVSampleRateKey : sampleRate ]
let input = AVAssetWriterInput(mediaType: .audio, outputSettings: settings, sourceFormatHint: formatDesc)
writer.add(input)
这就是所有的一次性设置,是时候开始写作了:
writer.startWriting()
writer.startSession(atSourceTime: kCMTimeZero)
如果您的所有数据大小相同,则可以创建可重复使用的缓冲区(或者每次都可以创建一个新缓冲区):
var block: CMBlockBuffer?
var status = CMBlockBufferCreateWithMemoryBlock(
kCFAllocatorDefault,
nil,
blockSize, // blockLength
nil, // blockAllocator
nil, // customBlockSource
0, // offsetToData
blockSize, // dataLength
0, // flags
&block
)
assert(status == kCMBlockBufferNoErr)
当数据进入时,将其复制到缓冲区中:
status = CMBlockBufferReplaceDataBytes(&inputData, block!, 0, blockSize)
assert(status == kCMBlockBufferNoErr)
现在从缓冲区创建一个样本缓冲区并将其附加到writer输入:
var sampleBuffer: CMSampleBuffer?
status = CMAudioSampleBufferCreateReadyWithPacketDescriptions(
kCFAllocatorDefault,
block, // dataBuffer
formatDesc!,
frames, // numSamples
CMTimeMake(currentFrame, Int32(sampleRate)), // sbufPTS
nil, // packetDescriptions
&sampleBuffer
)
assert(status == noErr)
input.append(sampleBuffer!)
当一切都完成后,完成作者并完成任务:
input.markAsFinished()
writer.finishWriting{}