初始化MIDIMetaEvent结构 [英] Initializing MIDIMetaEvent structure

查看:157
本文介绍了初始化MIDIMetaEvent结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力用swift初始化在MusicPlayer.h中找到的MIDIMetaEvent结构.头文件定义的结构如下:

I am struggling to initialize the MIDIMetaEvent structure found in MusicPlayer.h with swift The header file defines the structure as follows:

struct MIDIMetaEvent {
  var metaEventType: UInt8
  var unused1: UInt8
  var unused2: UInt8
  var unused3: UInt8
  var dataLength: UInt32
  var data: (UInt8)
}

在该数据"成员之前,这似乎相当简单.那是1元素元组的定义吗?我可以轻松地初始化所有其他struct元素,但是徒劳地尝试将'data'设置为除单个值之外的任何其他内容.在我的代码中,我使用了一个名为myData的UInt8数组,并试图像这样初始化结构:

Which seems fairly straightforward up until that 'data' member. Is that a 1 element tuple definition? I can easily initialize all other struct elements but have tried in vain to set 'data' to anything else than a single value. In my code I used an UInt8 array called myData and attempted to init the structure like so:

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) )

但是编译器对此不满意,并抱怨"UnsafeBufferPointer无法转换为UInt8".如果我只是简单地将数据设置为单个值,但将dataLength设置为大于1的值,则生成的MIDIEventData将显示事件中的第一个值是我卡在数据"中的内容,然后是与"dataLength"字节一致的乱码数据字节.显然,数据"被视为某种连续的记忆.

But the compiler is not happy with this and complains about "UnsafeBufferPointer no convertible to UInt8". If I simply set data to a single value but set dataLength to a value more than 1, the resulting MIDIEventData shows that the first value in the event is what I stuck in 'data' followed by gibberish data bytes in accordance with 'dataLength' bytes. So clearly 'data' is seen as some sort of continuous memory.

那么如何从数组中将'data'元素设置为UInt8元素?

So how do I set that 'data' element to UInt8 elements from an array?

推荐答案

AudioToolbox框架将MIDIMetaEvent定义为

The AudioToolbox framework defines MIDIMetaEvent as

typedef struct MIDIMetaEvent
{
    UInt8       metaEventType;
    UInt8       unused1;
    UInt8       unused2;
    UInt8       unused3;
    UInt32      dataLength;
    UInt8       data[1];
} MIDIMetaEvent;

其中,data[1]实际上用作可变长度数组". 在(Objective-C)中,可以只分配一个指针到 实际需要的大小:

where data[1] is actually used as a "variable length array". In (Objective-)C one can just allocate a pointer to a memory block of the actually needed size:

MIDIMetaEvent *mep = malloc(sizeof(MIDIMetaEvent) + data.count);

使用指针强制转换时,Swift更加严格,并且固定大小的数组被映射到 Swift元组(处理起来可能很麻烦).

Swift is more strict with pointer casts and fixed size arrays are mapped to Swift tuples (which can be cumbersome to handle with).

以下实用程序类显示了如何解决此问题:

The following utility class shows how this could be solved:

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)
    }
}

然后您可以使用创建一个实例

Then you can create an instance with

let me = MyMetaEvent(type: 0x7F, data: myData)

并通过UnsafePointer<MIDIMetaEvent>me.metaEventPtr传递给Swift函数 论点.

and pass me.metaEventPtr to the Swift functions taking a UnsafePointer<MIDIMetaEvent> argument.

Swift 3/4的更新:

不再简单地将指针转换为其他类型, 它必须是反弹的":

Simply converting a pointer to a different type is no longer possible, it must be "rebound":

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)
        }
    }
}

使用自定义数据创建实例:

Create an instance with custom data:

let me = MyMetaEvent(type: 0x7F, data: ...)

传递给带有UnsafePointer<MIDIMetaEvent>参数的函数:

Pass to a function taking a UnsafePointer<MIDIMetaEvent> argument:

me.withMIDIMetaEventPtr { metaEventPtr in
    let status = MusicTrackNewMetaEvent(track, 0, metaEventPtr)
}

这篇关于初始化MIDIMetaEvent结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆