Swift 2到swift 3转换Midi输入

时间:2016-07-08 03:09:43

标签: xcode swift midi swift-playground swift3

我希望有人可以帮助我使用Xcode 8和swift 3 我有一个操场文件Xcode 7 swift 2,涉及Midi的Midi回调输入一切正常,7

我尝试转换为8并且它带来了关于内存的错误和一些名称更改,主要是我认为非严重的我还使用PlaygroundSupport重新定义了无限循环 但是我无法解决的错误涉及

的MyMIDIReadProc
MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);

错误说 无法转换类型'的值(pktList:UnsafePointer,readProcRefCon:UnsafeMutablePointer,srcConnRefCon:UnsafeMutablePointer) - > Void'到预期的参数类型'MIDIReadProc'(又名'@convention(c)(UnsafePointer,Optional>,Optional>) - >()')

我的理解是它需要插入一些描述的@convention(c)包装器。我想我是在正确的轨道,因为你可以包装一个功能,但我知道放在哪里已经用完了。我再次希望有人可以提出建议

感谢阅读 对于任何不好的语言道歉,因为我是自学的

这是原始的Xcode 7代码

            import Cocoa
            import CoreMIDI
            import XCPlayground

            func getDisplayName(obj: MIDIObjectRef) -> String
            {
                var param: Unmanaged<CFString>?
                var name: String = "Error";

                let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, &param)
                if err == OSStatus(noErr)
                {
                    name =  param!.takeRetainedValue() as String
                }

                return name;
            }

            func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
                readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
            {
                let packetList:MIDIPacketList = pktList.memory;
                let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(COpaquePointer(srcConnRefCon)).memory;
                print("MIDI Received From Source: \(getDisplayName(srcRef))");

                var packet:MIDIPacket = packetList.packet;
                for _ in 1...packetList.numPackets
                {
                    let bytes = Mirror(reflecting: packet.data).children;
                    var dumpStr = "";
                    // bytes mirror contains all the zero values in the ridiulous packet data tuple
                    // so use the packet length to iterate.
                    var i = packet.length;
                    for (_, attr) in bytes.enumerate()
                    {
                         dumpStr += String(format:"$%02X ", attr.value as! UInt8);
                        --i;
                        if (i <= 0)
                        {
                           break;
                        }
                    }

                    print(dumpStr)
                    packet = MIDIPacketNext(&packet).memory;
                }
            }

            var midiClient: MIDIClientRef = 0;
            var inPort:MIDIPortRef = 0;
            var src:MIDIEndpointRef = MIDIGetSource(0);

            MIDIClientCreate("MidiTestClient", nil, nil, &midiClient);
            MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);

            MIDIPortConnectSource(inPort, src, &src);

            // Keep playground running
            XCPlaygroundPage.currentPage.needsIndefiniteExecution = true;

这是转换的Xcode 8代码

            var str = "Hello, playground"
            import Cocoa
            import CoreMIDI
            import XCPlayground
            import PlaygroundSupport


             func getDisplayName(obj: MIDIObjectRef) -> String
             {
             var param: Unmanaged<CFString>?
             var name: String = "Error";

             let err: OSStatus = MIDIObjectGetStringProperty(obj, kMIDIPropertyDisplayName, &param)
             if err == OSStatus(noErr)
             {
             name =  param!.takeRetainedValue() as String
             }

             return name;
             }


            func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
                                readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
             {


             let packetList:MIDIPacketList = pktList.pointee;

             let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(OpaquePointer(srcConnRefCon)).pointee;
             print("MIDI Received From Source: \(getDisplayName(obj: srcRef))");

             var packet:MIDIPacket = packetList.packet;
             for _ in 1...packetList.numPackets
             {
             let bytes = Mirror(reflecting: packet.data).children;
             var dumpStr = "";

             var i = packet.length;
             for (_, attr) in bytes.enumerated()
             {
             dumpStr += String(format:"$%02X ", attr.value as! UInt8);
             i -= 1;
             if (i <= 0)
             {
             break;
             }

             }

             print(dumpStr)
             packet = MIDIPacketNext(&packet).pointee;
             }
             }

            var midiClient: MIDIClientRef = 0;
             var inPort:MIDIPortRef = 0;
             var src:MIDIEndpointRef = MIDIGetSource(0);

             MIDIClientCreate("MidiTestClient", nil, nil, &midiClient);

             MIDIInputPortCreate(midiClient, "MidiTest_InPort", MyMIDIReadProc, nil, &inPort);

            MIDIPortConnectSource(inPort, src, &src);


             PlaygroundPage.current.needsIndefiniteExecution = true

3 个答案:

答案 0 :(得分:2)

Swift 3中的指针类型发生了巨大变化。许多基于C的API的签名都会相应更改。

手动完成这些更改会很痛苦。你可以通过一些修改让Swift为你工作。

尝试更改功能标题:

func MyMIDIReadProc(pktList: UnsafePointer<MIDIPacketList>,
                                readProcRefCon: UnsafeMutablePointer<Void>, srcConnRefCon: UnsafeMutablePointer<Void>) -> Void
             {

到封闭声明:

let MyMIDIReadProc: MIDIReadProc = {pktList, readProcRefCon, srcConnRefCon in

Swift以这种风格完美地推断出参数类型。

您可能需要修复指针类型转换:

    let srcRef:MIDIEndpointRef = UnsafeMutablePointer<MIDIEndpointRef>(OpaquePointer(srcConnRefCon)).pointee;

这样的事情:

    //I'm not sure using `!` is safe here...
    let srcRef: MIDIEndpointRef = UnsafeMutablePointer(srcConnRefCon!).pointee

(顺便说一句,Xcode 7代码中的等效部分有点多余。您无需在那里使用中间COpaquePointer。)

在Swift 3中,指针不能为nil,可空指针用Optionals表示。您可能需要许多其他修复程序才能在Swift 3中使用基于C的API。

答案 1 :(得分:1)

OOPer指向(咳咳)你正确的方向。这是一篇关于使用Swift 3 Core MIDI和使用github repo的博客文章。

答案 2 :(得分:0)

假设您正在使用CoreMIDI 1.3或更高版本,那么使用MIDIInputPortCreateWithBlock代替MIDIInputPortCreate可能会有更多运气。

此方法将Swift块作为参数,而不是需要@convention(c)函数引用,使其更适合在属于Swift类的方法中使用,例如:

public func midiReadBlock(ptr: UnsafePointer<MIDIPacketList>, _: UnsafeMutableRawPointer?) -> Void {
    let list: MIDIPacketList = ptr.pointee
    ...
}

您可能还会发现这两个扩展程序很有用。

这一个(源自here)允许您使用MIDIPacketList直接在for pkt in list上进行迭代:

extension MIDIPacketList: Sequence {

    public func makeIterator() -> AnyIterator<MIDIPacket> {
        var iterator: MIDIPacket?
        var nextIndex: UInt32 = 0

        return AnyIterator {
            nextIndex += 1
            if nextIndex > self.numPackets { return nil }
            if iterator != nil {
                iterator = withUnsafePointer(to: &iterator!) { MIDIPacketNext($0).pointee }
            } else {
                iterator = self.packet;
            }
            return iterator
        }
    }
}

这个方法向MIDIPacket添加一个方法,将内容提取为[UInt8],而不必使用真正破坏的元组语法:

extension MIDIPacket {
    public var asArray: [UInt8] {
        let mirror = Mirror(reflecting: self.data)
        let length = Int(self.length)

        var result = [UInt8]()
        result.reserveCapacity(length)

        for (n, child) in mirror.children.enumerated() {
            if n == length {
                break
            }
            result.append(child.value as! UInt8)
        }
        return result
    }
}