Skip to content

Instantly share code, notes, and snippets.

@tion-low
Created August 6, 2019 09:15
Show Gist options
  • Save tion-low/47e9fc4082717078dff4d6259b6ffbc9 to your computer and use it in GitHub Desktop.
Save tion-low/47e9fc4082717078dff4d6259b6ffbc9 to your computer and use it in GitHub Desktop.
import UIKit
import AVFoundation
public func createSampleBufferBy<T>(pcm: [T], timeStamp: AudioTimeStamp, bd: AudioStreamBasicDescription) -> CMSampleBuffer? {
var basicDescription = bd
var formatDescription: CMAudioFormatDescription?
_ = CMAudioFormatDescriptionCreate(allocator: kCFAllocatorDefault,
asbd: &basicDescription,
layoutSize: 0,
layout: nil,
magicCookieSize: 0,
magicCookie: nil,
extensions: nil,
formatDescriptionOut: &formatDescription)
var blockBuffer: CMBlockBuffer?
_ = CMBlockBufferCreateWithMemoryBlock(allocator: kCFAllocatorDefault,
memoryBlock: UnsafeMutableRawPointer(mutating: pcm),
blockLength: pcm.count * MemoryLayout<T>.stride,
blockAllocator: kCFAllocatorNull,
customBlockSource: nil,
offsetToData: 0,
dataLength: pcm.count * MemoryLayout<T>.stride,
flags: 0,
blockBufferOut: &blockBuffer)
var sampleBuffer: CMSampleBuffer?
let t = CMTime(value: CMTimeValue(Int(AVAudioTime.seconds(forHostTime: mach_absolute_time()) * 1000000000)),
timescale: 1000000000,
flags: .init(rawValue: 3),
epoch: 0)
_ = CMAudioSampleBufferCreateWithPacketDescriptions(allocator: kCFAllocatorDefault,
dataBuffer: blockBuffer,
dataReady: true,
makeDataReadyCallback: nil,
refcon: nil,
formatDescription: formatDescription!,
sampleCount: pcm.count,
presentationTimeStamp: t,
packetDescriptions: nil,
sampleBufferOut: &sampleBuffer)
return sampleBuffer
}
extension AudioBufferList {
public mutating func convert() -> [AudioBuffer] {
let buf: UnsafeBufferPointer<AudioBuffer> = UnsafeBufferPointer<AudioBuffer>(start: &(self.mBuffers), count: Int(self.mNumberBuffers))
return Array(buf)
}
}
extension AudioBuffer {
public func convert() -> [Float] {
if let mdata = self.mData {
let ump = mdata.bindMemory(to: Float.self, capacity: Int(mDataByteSize))
let usp = UnsafeBufferPointer(start: ump, count: Int(mDataByteSize) / MemoryLayout<Float>.size)
return [Float](usp)
} else {
return []
}
}
}
let basicDescription = AudioStreamBasicDescription(mSampleRate: 48000,
mFormatID: kAudioFormatLinearPCM,
mFormatFlags: kLinearPCMFormatFlagIsFloat,
mBytesPerPacket: 4,
mFramesPerPacket: 1,
mBytesPerFrame: 4,
mChannelsPerFrame: 1,
mBitsPerChannel: 32,
mReserved: 0)
let pcm = { () -> [Float] in
var samples: [Float] = []
for n in 0..<1024 {
samples.append(sinf(Float(2.0 * Double.pi) * 440 * Float(n) / 44100))
}
return samples
}()
let sampleBuffer = createSampleBufferBy(pcm: pcm, timeStamp: AudioTimeStamp(mSampleTime: 0, mHostTime: 0, mRateScalar: 0, mWordClockTime: 0, mSMPTETime: .init(), mFlags: .init(rawValue: 0), mReserved: 0), bd: basicDescription)
var audioBufferList = AudioBufferList(mNumberBuffers: 1, mBuffers: AudioBuffer(mNumberChannels: 0, mDataByteSize: 0, mData: nil))
var blockBuffer: CMBlockBuffer?
_ = CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer!,
bufferListSizeNeededOut: nil,
bufferListOut: &audioBufferList,
bufferListSize: MemoryLayout<AudioBufferList>.stride,
blockBufferAllocator: nil,
blockBufferMemoryAllocator: nil,
flags: kCMSampleBufferFlag_AudioBufferList_Assure16ByteAlignment,
blockBufferOut: &blockBuffer)
print(blockBuffer)
print(audioBufferList)
print(pcm)
print("\n")
print(audioBufferList.convert()[0].convert())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment