2016-07-08 4 views
0

J'espère que quelqu'un pourra m'aider à utiliser Xcode 8 et swift 3 J'ai un fichier de terrain de jeu Xcode 7 swift 2 qui implique un rappel Midi pour Midi Input tout fonctionne amende dans 7Swift 2 conversion swift 3 Midi Entrée

J'ai essayé une conversion à 8 et il a soulevé des erreurs concernant la mémoire et quelques changements de nom principalement de ce que je crois être non sérieux j'ai également redéfini la boucle infinie en utilisant PlaygroundSupport Cependant l'erreur que je ne peux pas surmonter implique MyMIDIReadProc à

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

L'erreur dit Impossible de convertir la valeur de type '(pktList: UnsafePointer, readProcRefCon: UnsafeMutablePointer, srcConnRefCon: UnsafeMutablePointer) -> Void' au type d'argument attendu 'MIDIReadProc' (alias '@convention (c) (UnsafePointer, Facultatif>, Facultatif>) ->() ')

Ma compréhension est qu'il a besoin d'un wrapper @convention (c) de quelque description inséré. Je pense que je suis sur la bonne voie parce que vous pouvez envelopper une fonction, mais ma connaissance de l'endroit où le mettre est épuisée. Encore une fois j'espérais quelqu'un pourrait être en mesure de conseiller

Merci d'avoir lu excuses pour toute mauvaise langue que je suis autodidacte

Voici le Xcode d'origine 7 Code

  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; 

Et ici est le code Xcode 8 converti

  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 

Répondre

1

types de pointeur sont radicalement modifiés dans Swift 3. de nombreuses signatures d'API basées sur C sont modifiées en conséquence .

Suivre ces changements manuellement serait douloureux. Vous pouvez faire travailler Swift pour vous, avec une petite modification.

Essayez de changer l'en-tête de la fonction:

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

à une déclaration de clôture:

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

Swift infère types d'arguments parfaitement dans ce style.

Vous devrez peut-être corriger la conversion de type pointeur:

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

à quelque chose comme ceci:

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

(Soit dit en passant, la partie équivalente dans votre code Xcode 7 est un peu redondant . Vous n'avez pas besoin d'utiliser COpaquePointer intermédiaire là.)


Swift 3, pointeurs ne peut pas être nul, et les pointeurs nullables sont représentés avec Optionals. Il se peut que vous ayez besoin de beaucoup d'autres correctifs pour utiliser les API C dans Swift 3.

0

OOPer vous dirige (ahem) dans la bonne direction. Voici un article de blog sur l'utilisation de Swift 3 Core MIDI avec un repo de github de travail.

0

En supposant que vous travaillez avec CoreMIDI 1.3 ou version ultérieure, vous pouvez avoir plus de chance en utilisant MIDIInputPortCreateWithBlock au lieu de MIDIInputPortCreate.

Cette méthode prend un bloc Swift comme paramètre au lieu d'exiger une référence de fonction @convention(c), le rendant plus susceptible d'être utilisé dans les méthodes appartenant aux classes Swift, par exemple:

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

Vous pouvez également trouver ces deux extensions utile.

Celui-ci (dérivé de here) vous permet d'itérer directement sur une MIDIPacketList utilisant 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 
     } 
    } 
} 

et celui-ci ajoute une méthode à un MIDIPacket pour extraire le contenu en tant que [UInt8] au lieu d'avoir à utiliser la syntaxe de tuple vraiment cassée:

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