2016-07-08 8 views
0

Я надеюсь, что кто-то сможет помочь мне использовать Xcode 8 и swift 3 У меня есть игровой файл Xcode 7 swift 2, который включает в себя Midi callback для Midi Input, все работает fine in 7Swift 2 to swift 3 conversion Midi Input

Я попробовал преобразование в 8, и это привело к ошибкам в отношении памяти и нескольких изменений имени в основном из того, что, по моему мнению, несерьезно, я также переопределил бесконечный цикл, используя PlaygroundSupport Однако ошибка, с которой я не могу справиться включает в себя MyMIDIReadProc на

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

ошибка говорит Невозможно преобразовать значение типа '(pktList: UnsafePointer, readProcRefCon: UnsafeMutablePointer, srcConnRefCon: UnsafeMutablePointer) -> Void' для ожидаемого типа аргумента 'MIDIReadProc' (aka '@convention (c) (UnsafePointer, Необязательный>, Необязательный>) ->() ')

Мое понимание состоит в том, что ему необходимо установить оболочку @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 

ответ

1

типов указателей резко изменены в Swift подпись 3. Многие с-Based Apis' изменяется соответствующим образом ,

После этих изменений вручную было бы больно. Вы можете заставить 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, а указатели с нулевым значением представлены с помощью опций. Возможно, вам понадобится много других исправлений для работы с API-интерфейсами C в Swift 3.

0

OOPer указывает (ах) вы в правильном направлении. Вот сообщение в блоге об использовании Swift 3 Core MIDI наряду с рабочим репозиторией github.

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