Swift:从URL检索audio文件标记列表?

我只想得到一个audio文件中的标记列表。 我认为这将是一个简单的通用任务,不会太困难。 但是,我几乎找不到任何示例代码或文档,所以我最终得到这样的结果:

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和大小(这两个都是有效的),但总是无法检索标记。 任何帮助,这将是太棒了!

编辑:这种工作,但所有的数据是完全错误的,我不明白如何一个audio文件可以有多个标记的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:根据目前为止我见过的大多数答案,这应该工作,但它返回一个空数组:

 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的代码有用的东西,任何人都想快速尝试,find问题:

 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 } 

我只希望苹果实际上首先testing了AudioFileMarkerList。

编辑4:解决感谢节奏Fistman和瑞安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 } 

看起来像你需要使用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) } 

模拟这个答案

编辑:最简单的解决scheme是使用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结构转换为Swift。 这可能是可以解决的,但是在我看来,最好使用Objective C来完成这些调用。 这里是Swift中几乎完成的函数。 我build议使用AudioKit来完成你所需要的,因为我已经在EZAudioFile中添加了标记码。 检查: https : //github.com/AudioKit/AudioKit/blob/master/AudioKit/Common/Internals/EZAudio/EZAudioFile.m

但是,这里logging的是正在进行的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 }