Yoh*_*hst 5 macos ios coremidi swift
我正在努力用swift初始化MusicPlayer.h中的MIDIMetaEvent结构头文件定义结构如下:
struct MIDIMetaEvent {
var metaEventType: UInt8
var unused1: UInt8
var unused2: UInt8
var unused3: UInt8
var dataLength: UInt32
var data: (UInt8)
}
Run Code Online (Sandbox Code Playgroud)
在"数据"成员之前,这似乎相当简单.这是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) )
Run Code Online (Sandbox Code Playgroud)
但编译器对此并不满意,并抱怨"UnsafeBufferPointer无法转换为UInt8".如果我只是将数据设置为单个值但将dataLength设置为大于1的值,则生成的MIDIEventData显示事件中的第一个值是"数据"中的第一个值,后跟符合"dataLength"字节的乱码数据字节.很明显,"数据"被视为某种连续记忆.
那么如何将'data'元素设置为数组中的UInt8元素?
AudioToolbox框架定义MIDIMetaEvent为
typedef struct MIDIMetaEvent
{
UInt8 metaEventType;
UInt8 unused1;
UInt8 unused2;
UInt8 unused3;
UInt32 dataLength;
UInt8 data[1];
} MIDIMetaEvent;
Run Code Online (Sandbox Code Playgroud)
其中data[1]实际用作"可变长度数组".在(Objective-)C中,可以只分配一个指向实际所需大小的内存块的指针:
MIDIMetaEvent *mep = malloc(sizeof(MIDIMetaEvent) + data.count);
Run Code Online (Sandbox Code Playgroud)
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)
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以创建一个实例
let me = MyMetaEvent(type: 0x7F, data: myData)
Run Code Online (Sandbox Code Playgroud)
并传递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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
使用自定义数据创建实例:
let me = MyMetaEvent(type: 0x7F, data: ...)
Run Code Online (Sandbox Code Playgroud)
传递给UnsafePointer<MIDIMetaEvent>参数的函数:
me.withMIDIMetaEventPtr { metaEventPtr in
let status = MusicTrackNewMetaEvent(track, 0, metaEventPtr)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
739 次 |
| 最近记录: |