Swift: 从 url 中检索音频文件标记列表?
Swift: Retrieve audio file marker list from url?
我只想获取音频文件中的标记列表。我认为这将是一个简单的常见任务,不会太困难。但是,我几乎找不到任何示例代码或文档,所以我最终得到了这个:
private func getMarkers(_ url: CFURL) -> AudioFileMarkerList {
var file: AudioFileID?
var size: UInt32 = 0
var markers = AudioFileMarkerList()
AudioFileOpenURL(url, .readPermission, kAudioFileWAVEType, &file)
AudioFileGetPropertyInfo(file!, kAudioFilePropertyMarkerList, &size, nil)
AudioFileGetProperty(file!, kAudioFilePropertyMarkerList, &size, &markers)
return markers
}
遗憾的是,这不起作用:error: memory read failed for 0x0
。
我就是想不通这个问题。我检查了 url 和大小(均有效),但始终无法检索标记。任何对此的帮助都会很棒!
编辑:
这种作品,但所有数据都是完全错误的,我无法理解单个音频文件如何具有多个 AudioFileMarkerLists 标记:
private func getMarkers(_ url: CFURL) -> [AudioFileMarkerList] {
var file: AudioFileID?
var size: UInt32 = 0
AudioFileOpenURL(url, .readPermission, kAudioFileWAVEType, &file)
AudioFileGetPropertyInfo(file!, kAudioFilePropertyMarkerList, &size, nil)
let length = NumBytesToNumAudioFileMarkers(Int(size))
var markers = [AudioFileMarkerList](repeating: AudioFileMarkerList(), count: length)
AudioFileGetProperty(file!, kAudioFilePropertyMarkerList, &size, &markers)
return markers
}
编辑 2: 根据我目前看到的大多数答案,这应该可行,但它 returns 是一个空数组:
private func getMarkers(_ url: CFURL) -> [AudioFileMarkerList] {
var file: AudioFileID?
var size: UInt32 = 0
AudioFileOpenURL(url, .readPermission, kAudioFileWAVEType, &file)
AudioFileGetPropertyInfo(file!, kAudioFilePropertyMarkerList, &size, nil)
let length = NumBytesToNumAudioFileMarkers(Int(size))
var markers = [AudioFileMarkerList]()
markers.reserveCapacity(length)
AudioFileGetProperty(file!, kAudioFilePropertyMarkerList, &size, &markers)
return markers
}
编辑 3:
我从 Ryan 的代码中删除了一堆错误检查和有用的东西,供任何想快速尝试找出问题的人使用:
private func getMarkers(_ url: CFURL) -> [AudioFileMarker]? {
var file: AudioFileID?
var size: UInt32 = 0
var markers: [AudioFileMarker] = []
AudioFileOpenURL(url, .readPermission, kAudioFileWAVEType, &file)
AudioFileGetPropertyInfo(file!, kAudioFilePropertyMarkerList, &size, nil)
let length = NumBytesToNumAudioFileMarkers(Int(size))
let data = UnsafeMutablePointer<AudioFileMarkerList>.allocate(capacity: length)
AudioFileGetProperty(file!, kAudioFilePropertyMarkerList, &size, data)
markers.append(data.pointee.mMarkers)
data.deallocate(capacity: length)
return markers
}
我只是希望 Apple 真的首先测试了 AudioFileMarkerList。
编辑 4:
感谢 Rhythmic Fistman 和 Ryan Francesconi 解决了!最终结果:
private func getMarkers(_ url: CFURL) -> [AudioFileMarker]? {
var file: AudioFileID?
var size: UInt32 = 0
var markerList: [AudioFileMarker] = []
AudioFileOpenURL(url, .readPermission, kAudioFileWAVEType, &file)
AudioFileGetPropertyInfo(file!, kAudioFilePropertyMarkerList, &size, nil)
let length = NumBytesToNumAudioFileMarkers(Int(size))
let data = UnsafeMutablePointer<AudioFileMarkerList>.allocate(capacity: length)
AudioFileGetProperty(file!, kAudioFilePropertyMarkerList, &size, data)
let markers = UnsafeBufferPointer<AudioFileMarker>(start: &data.pointee.mMarkers, count: length)
for marker in markers {
markerList.append(marker)
}
data.deallocate(capacity: length)
return markerList
}
编辑: 最简单的解决方案是使用 AudioKit 版本的 EZAudioFile.markers。请注意,这与原始 EZAudio 框架不同,因为我仅将此标记代码添加到 AudioKit 的版本中。
import AudioKit
...
if let file = EZAudioFile(url: url) {
if let markers = file.markers as? [EZAudioFileMarker] {
for m in markers {
Swift.print("NAME: \(m.name) FRAME: \(m.framePosition)")
}
}
}
如果您真的想在Swift中尝试,它看起来像下面这样。我不是这方面的专家,但据我所知,翻译 AudioFileMarkerList struct to Swift. This may be solvable, but it seems to me it's best to just use Objective C to accomplish these calls. Here is the almost finished function in Swift. I recommend using AudioKit to accomplish what you need as I have added the marker code to EZAudioFile there. Check: https://github.com/AudioKit/AudioKit/blob/master/AudioKit/Common/Internals/EZAudio/EZAudioFile.m
时存在一些问题
但这里要记录的是 Swift 代码正在进行中!请注意,目前它被硬编码为 WAVE 文件......也许其他人可以完成这个?
class func getAudioFileMarkers(_ url: URL) -> [AudioFileMarker]? {
Swift.print("getAudioFileMarkers() \(url)")
var err: OSStatus = noErr
var audioFileID: AudioFileID?
err = AudioFileOpenURL(url as CFURL,
.readPermission,
kAudioFileWAVEType,
&audioFileID)
if err != noErr {
Swift.print("AudioFileOpenURL FAILED, Error: \(err)")
return nil
}
guard audioFileID != nil else {
return nil
}
Swift.print("audioFileID: \(audioFileID)")
var outSize: UInt32 = 0
var writable: UInt32 = 0
err = AudioFileGetPropertyInfo(audioFileID!, kAudioFilePropertyMarkerList, &outSize, &writable)
if err != noErr {
Swift.print("AudioFileGetPropertyInfo kAudioFilePropertyMarkerList FAILED, Error: \(err)")
return nil
}
Swift.print("outSize: \(outSize), writable: \(writable)")
guard outSize != 0 else { return nil }
let length = NumBytesToNumAudioFileMarkers( Int(outSize) )
Swift.print("Found \(length) markers")
let theData = UnsafeMutablePointer<AudioFileMarkerList>.allocate(capacity: length)
if length == 0 {
return nil
}
// pull marker list
err = AudioFileGetProperty(audioFileID!, kAudioFilePropertyMarkerList, &outSize, theData)
if err != noErr {
Swift.print("AudioFileGetProperty kAudioFilePropertyMarkerList FAILED, Error: \(err)")
return nil
}
let markerList: AudioFileMarkerList = theData.pointee
Swift.print("markerList.mMarkers: \(markerList.mMarkers)")
// this is only showing up as a single AudioFileMarker, not an array of them.
// I DON'T KNOW WHY. It works in Obj-C. I'm obviously missing something, or there is a problem in translation
var out = [AudioFileMarker]()
let mirror = Mirror(reflecting: markerList.mMarkers)
for m in mirror.children {
Swift.print( "label: \(m.label) value: \(m.value)" )
}
// for now just append the first one.
// :(
out.append(markerList.mMarkers)
// done with this now
theData.deallocate(capacity: length)
return out
}
看起来您需要使用 UnsafeBufferPointer
来访问可变长度数组(例如 mMarkers
)。所以而不是
out.append(markerList.mMarkers)
只添加第一个元素,这样做
let markersBuffer = UnsafeBufferPointer<AudioFileMarker>(start: &data.pointee.mMarkers,
count: Int(data.pointee.mNumberMarkers))
for marker in markersBuffer {
markers.append(marker)
}
仿照this answer
我只想获取音频文件中的标记列表。我认为这将是一个简单的常见任务,不会太困难。但是,我几乎找不到任何示例代码或文档,所以我最终得到了这个:
private func getMarkers(_ url: CFURL) -> AudioFileMarkerList {
var file: AudioFileID?
var size: UInt32 = 0
var markers = AudioFileMarkerList()
AudioFileOpenURL(url, .readPermission, kAudioFileWAVEType, &file)
AudioFileGetPropertyInfo(file!, kAudioFilePropertyMarkerList, &size, nil)
AudioFileGetProperty(file!, kAudioFilePropertyMarkerList, &size, &markers)
return markers
}
遗憾的是,这不起作用:error: memory read failed for 0x0
。
我就是想不通这个问题。我检查了 url 和大小(均有效),但始终无法检索标记。任何对此的帮助都会很棒!
编辑: 这种作品,但所有数据都是完全错误的,我无法理解单个音频文件如何具有多个 AudioFileMarkerLists 标记:
private func getMarkers(_ url: CFURL) -> [AudioFileMarkerList] {
var file: AudioFileID?
var size: UInt32 = 0
AudioFileOpenURL(url, .readPermission, kAudioFileWAVEType, &file)
AudioFileGetPropertyInfo(file!, kAudioFilePropertyMarkerList, &size, nil)
let length = NumBytesToNumAudioFileMarkers(Int(size))
var markers = [AudioFileMarkerList](repeating: AudioFileMarkerList(), count: length)
AudioFileGetProperty(file!, kAudioFilePropertyMarkerList, &size, &markers)
return markers
}
编辑 2: 根据我目前看到的大多数答案,这应该可行,但它 returns 是一个空数组:
private func getMarkers(_ url: CFURL) -> [AudioFileMarkerList] {
var file: AudioFileID?
var size: UInt32 = 0
AudioFileOpenURL(url, .readPermission, kAudioFileWAVEType, &file)
AudioFileGetPropertyInfo(file!, kAudioFilePropertyMarkerList, &size, nil)
let length = NumBytesToNumAudioFileMarkers(Int(size))
var markers = [AudioFileMarkerList]()
markers.reserveCapacity(length)
AudioFileGetProperty(file!, kAudioFilePropertyMarkerList, &size, &markers)
return markers
}
编辑 3: 我从 Ryan 的代码中删除了一堆错误检查和有用的东西,供任何想快速尝试找出问题的人使用:
private func getMarkers(_ url: CFURL) -> [AudioFileMarker]? {
var file: AudioFileID?
var size: UInt32 = 0
var markers: [AudioFileMarker] = []
AudioFileOpenURL(url, .readPermission, kAudioFileWAVEType, &file)
AudioFileGetPropertyInfo(file!, kAudioFilePropertyMarkerList, &size, nil)
let length = NumBytesToNumAudioFileMarkers(Int(size))
let data = UnsafeMutablePointer<AudioFileMarkerList>.allocate(capacity: length)
AudioFileGetProperty(file!, kAudioFilePropertyMarkerList, &size, data)
markers.append(data.pointee.mMarkers)
data.deallocate(capacity: length)
return markers
}
我只是希望 Apple 真的首先测试了 AudioFileMarkerList。
编辑 4: 感谢 Rhythmic Fistman 和 Ryan Francesconi 解决了!最终结果:
private func getMarkers(_ url: CFURL) -> [AudioFileMarker]? {
var file: AudioFileID?
var size: UInt32 = 0
var markerList: [AudioFileMarker] = []
AudioFileOpenURL(url, .readPermission, kAudioFileWAVEType, &file)
AudioFileGetPropertyInfo(file!, kAudioFilePropertyMarkerList, &size, nil)
let length = NumBytesToNumAudioFileMarkers(Int(size))
let data = UnsafeMutablePointer<AudioFileMarkerList>.allocate(capacity: length)
AudioFileGetProperty(file!, kAudioFilePropertyMarkerList, &size, data)
let markers = UnsafeBufferPointer<AudioFileMarker>(start: &data.pointee.mMarkers, count: length)
for marker in markers {
markerList.append(marker)
}
data.deallocate(capacity: length)
return markerList
}
编辑: 最简单的解决方案是使用 AudioKit 版本的 EZAudioFile.markers。请注意,这与原始 EZAudio 框架不同,因为我仅将此标记代码添加到 AudioKit 的版本中。
import AudioKit
...
if let file = EZAudioFile(url: url) {
if let markers = file.markers as? [EZAudioFileMarker] {
for m in markers {
Swift.print("NAME: \(m.name) FRAME: \(m.framePosition)")
}
}
}
如果您真的想在Swift中尝试,它看起来像下面这样。我不是这方面的专家,但据我所知,翻译 AudioFileMarkerList struct to Swift. This may be solvable, but it seems to me it's best to just use Objective C to accomplish these calls. Here is the almost finished function in Swift. I recommend using AudioKit to accomplish what you need as I have added the marker code to EZAudioFile there. Check: https://github.com/AudioKit/AudioKit/blob/master/AudioKit/Common/Internals/EZAudio/EZAudioFile.m
时存在一些问题但这里要记录的是 Swift 代码正在进行中!请注意,目前它被硬编码为 WAVE 文件......也许其他人可以完成这个?
class func getAudioFileMarkers(_ url: URL) -> [AudioFileMarker]? {
Swift.print("getAudioFileMarkers() \(url)")
var err: OSStatus = noErr
var audioFileID: AudioFileID?
err = AudioFileOpenURL(url as CFURL,
.readPermission,
kAudioFileWAVEType,
&audioFileID)
if err != noErr {
Swift.print("AudioFileOpenURL FAILED, Error: \(err)")
return nil
}
guard audioFileID != nil else {
return nil
}
Swift.print("audioFileID: \(audioFileID)")
var outSize: UInt32 = 0
var writable: UInt32 = 0
err = AudioFileGetPropertyInfo(audioFileID!, kAudioFilePropertyMarkerList, &outSize, &writable)
if err != noErr {
Swift.print("AudioFileGetPropertyInfo kAudioFilePropertyMarkerList FAILED, Error: \(err)")
return nil
}
Swift.print("outSize: \(outSize), writable: \(writable)")
guard outSize != 0 else { return nil }
let length = NumBytesToNumAudioFileMarkers( Int(outSize) )
Swift.print("Found \(length) markers")
let theData = UnsafeMutablePointer<AudioFileMarkerList>.allocate(capacity: length)
if length == 0 {
return nil
}
// pull marker list
err = AudioFileGetProperty(audioFileID!, kAudioFilePropertyMarkerList, &outSize, theData)
if err != noErr {
Swift.print("AudioFileGetProperty kAudioFilePropertyMarkerList FAILED, Error: \(err)")
return nil
}
let markerList: AudioFileMarkerList = theData.pointee
Swift.print("markerList.mMarkers: \(markerList.mMarkers)")
// this is only showing up as a single AudioFileMarker, not an array of them.
// I DON'T KNOW WHY. It works in Obj-C. I'm obviously missing something, or there is a problem in translation
var out = [AudioFileMarker]()
let mirror = Mirror(reflecting: markerList.mMarkers)
for m in mirror.children {
Swift.print( "label: \(m.label) value: \(m.value)" )
}
// for now just append the first one.
// :(
out.append(markerList.mMarkers)
// done with this now
theData.deallocate(capacity: length)
return out
}
看起来您需要使用 UnsafeBufferPointer
来访问可变长度数组(例如 mMarkers
)。所以而不是
out.append(markerList.mMarkers)
只添加第一个元素,这样做
let markersBuffer = UnsafeBufferPointer<AudioFileMarker>(start: &data.pointee.mMarkers,
count: Int(data.pointee.mNumberMarkers))
for marker in markersBuffer {
markers.append(marker)
}
仿照this answer