我正在努力用swift初始化MusicPlayer.h中的MIDIMetaEvent结构头文件定义结构如下:
struct MIDIMetaEvent {
var metaEventType: UInt8
var unused1: UInt8
var unused2: UInt8
var unused3: UInt8
var dataLength: UInt32
var data: (UInt8)
}
直到那个数据'之前,这似乎相当简单。会员。这是1元素元组定义吗?我可以很容易地初始化所有其他结构元素但是徒劳地试图设置数据'除了单一价值之外的其他任何东西。在我的代码中,我使用了一个名为myData的UInt8数组,并试图像这样初始化结构:
var msg = MIDIMetaEvent(
metaEventType : UInt8(0x7F),
unused1 : UInt8(0),
unused2 : UInt8(0),
unused3 : UInt8(0),
dataLength : UInt32(myData.count),
data : UnsafeBufferPointer<UInt8>(start: UnsafePointer<UInt8>(myData), count:myData.count) )
但编译器对此并不满意并抱怨&#34; UnsafeBufferPointer无法转换为UInt8&#34;。如果我只是将数据设置为单个值但将dataLength设置为大于1的值,则生成的MIDIEventData会显示事件中的第一个值是我所处理的数据&#39;其次是根据&quot; dataLength&#39;的乱码数据字节。字节。这么清楚&#39;数据&#39;被视为某种连续的记忆。
那么如何设置数据&#39;元素到数组的UInt8元素?
答案 0 :(得分:6)
AudioToolbox框架将MIDIMetaEvent
定义为
typedef struct MIDIMetaEvent
{
UInt8 metaEventType;
UInt8 unused1;
UInt8 unused2;
UInt8 unused3;
UInt32 dataLength;
UInt8 data[1];
} MIDIMetaEvent;
其中data[1]
实际上用作“可变长度数组”。
在(Objective-)C中,可以只分配指向内存块的指针
实际需要的尺寸:
MIDIMetaEvent *mep = malloc(sizeof(MIDIMetaEvent) + data.count);
Swift对指针转换和固定大小数组的映射更加严格 Swift元组(处理起来很麻烦)。
以下实用程序类显示了如何解决此问题:
class MyMetaEvent {
private let size: Int
private let mem : UnsafeMutablePointer<UInt8>
let metaEventPtr : UnsafeMutablePointer<MIDIMetaEvent>
init(type: UInt8, data: [UInt8]) {
// Allocate memory of the required size:
size = sizeof(MIDIMetaEvent) + data.count
mem = UnsafeMutablePointer<UInt8>.alloc(size)
// Convert pointer:
metaEventPtr = UnsafeMutablePointer(mem)
// Fill data:
metaEventPtr.memory.metaEventType = type
metaEventPtr.memory.dataLength = UInt32(data.count)
memcpy(mem + 8, data, UInt(data.count))
}
deinit {
// Release the allocated memory:
mem.dealloc(size)
}
}
然后您可以使用
创建实例let me = MyMetaEvent(type: 0x7F, data: myData)
并将me.metaEventPtr
传递给Swift函数,并使用UnsafePointer<MIDIMetaEvent>
参数。
Swift 3/4的更新:
不再可能将指针转换为其他类型 它必须是“反弹”:
class MyMetaEvent {
private let size: Int
private let mem: UnsafeMutablePointer<UInt8>
init(type: UInt8, data: [UInt8]) {
// Allocate memory of the required size:
size = MemoryLayout<MIDIMetaEvent>.size + data.count
mem = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
mem.initialize(to: 0, count: size)
// Fill data:
mem.withMemoryRebound(to: MIDIMetaEvent.self, capacity: 1) { metaEventPtr in
metaEventPtr.pointee.metaEventType = type
metaEventPtr.pointee.dataLength = UInt32(data.count)
memcpy(&metaEventPtr.pointee.data, data, data.count)
}
}
deinit {
// Release the allocated memory:
mem.deallocate(capacity: size)
}
func withMIDIMetaEventPtr(body: (UnsafePointer<MIDIMetaEvent>) -> Void) {
mem.withMemoryRebound(to: MIDIMetaEvent.self, capacity: 1) { metaEventPtr in
body(metaEventPtr)
}
}
}
使用自定义数据创建实例:
let me = MyMetaEvent(type: 0x7F, data: ...)
传递给UnsafePointer<MIDIMetaEvent>
参数的函数:
me.withMIDIMetaEventPtr { metaEventPtr in
let status = MusicTrackNewMetaEvent(track, 0, metaEventPtr)
}
答案 1 :(得分:0)
我的$ 0.02
只是为了创建一个元事件而乱用指针是一件痛苦的事情,但我们仍然坚持下去。看起来这不会很快改变。
我试过这个并且它有效。我将MusicSequence写入文件,然后在Sibelius 7中打开它。它记录了我添加的文本,时间签名和关键签名事件。顺便说一句,你将时间签名事件添加到序列的速度轨道。 是的,ptr [1 ...没有明确分配。尚未遇到问题。有什么建议? (批评欢迎)
let text = "Piano"
let data = [UInt8](text.utf8)
var metaEvent = MIDIMetaEvent()
metaEvent.metaEventType = 3 // track or sequence name
metaEvent.dataLength = UInt32(data.count)
withUnsafeMutablePointer(&metaEvent.data, {
ptr in
for i in 0 ..< data.count {
ptr[i] = data[i]
}
})
let status = MusicTrackNewMetaEvent(track, 0, &metaEvent)