2014-10-21 9 views
5

Ich schaue mir einige der Beispiele von Midi-Ausgabe mit Core Midi.Verwenden von MIDIPacketList in swift

Speziell this question

und this

Ich habe Code, der auf diese in ObjC basierend arbeitet und ich möchte nun versuchen, das zu rasche zu übersetzen.

die Linie, die ich am wenigsten verstehe, ist diese: MIDIPacketList* pktList = (MIDIPacketList*) pktBuffer;

lese ich dies als einen Zeiger pktlist vom Typ MIDIPacketList erklärt und ihnen den Wert von pktBuffer, warf den Typen MIDIPacketList

Ich bin neu zuweisen zu C und objC und das ergibt für mich keinen Sinn.

MIDIPacketList ist eine Struktur here definiert:

in welcher Art und Weise macht es Sinn, eine bytearray auf die Struktur Typ MIDIPacketList und zu werfen, was diese zu erreichen versucht? Ich denke, es versucht, die Größe der Paketliste zu definieren, aber warum müssen wir das hier tun, und wie macht es das überhaupt? Warum reicht es nicht, es mit MIDIPacketListAdd zu tun, wie es ein paar Zeilen später passiert?

Hier ist mein Versuch einer Midi-Ausgangsklasse in swift - kann jemand sehen, was schief geht? Dieser Code gibt keine Fehler in Xcode, bis es ausgeführt wird. Ich habe eine funktionierende Version von diesem in objC, aber ich kann die Größe der Paketliste nicht erreichen, die in swift definiert wird. (Zumindest glaube ich das ist das Problem)

import Foundation 
import CoreMIDI 

class MidiOutClass { 

var midiClient = MIDIClientRef() 
var midiSource = MIDIEndpointRef() 


func openOutput() { 
    MIDIClientCreate("MIDI client", nil, nil, &midiClient) 
    MIDISourceCreate(midiClient, "MIDI Source",&midiSource) 
    println("midi out opened")//should only do this if successful 
} 

func noteOn(channel: Int, note: Int, velocity:Int) { 
    midisend((0x90+channel), note: note, value: velocity) 
} 

func polyAfter(channel: Int, note: Int, value:Int) { 
    midisend((0xA0+channel), note: note, value: value) 
} 

func noteOff(channel: Int, note: Int) { 
    midisend((0x90+channel), note: note, value: 0) 
} 

func midisend(status:Int, note: Int, value:Int) { 

    var packet: UnsafeMutablePointer<MIDIPacket> = nil 
    //var buffer = [Byte](count:1024, repeatedValue: 0) 
//this is the array I'm trying to use in a similar way to the obj C. 

    var packetList: UnsafeMutablePointer<MIDIPacketList> = nil 
    let midiDataToSend:[Byte] = [Byte(status), Byte(note), Byte(value)]; 
    packet = MIDIPacketListInit(packetList); 
    packet = MIDIPacketListAdd(packetList, 1024, packet, 0, 3, midiDataToSend); 

    if (packet == nil) { 
     println("failed to send the midi.") 
    } else { 
     MIDIReceived(midiSource, packetList) 
     println("sent some stuff") 
    } 
} 

}//end MidiOutClass 

Antwort

5

ich eine Antwort gefunden at this question

das Byte-Array in der ObjC Version ist ein gemeiner Hack eine Erinnerung an die Packet

hier ist meine überarbeitete zuzuteilen Code, der jetzt funktioniert.

Allerdings scheint die auskommentierte dealloc unnötig zu sein, ich bin mir nicht ganz sicher warum noch. Behandelt MIDIReceived es?

Wenn jemand eine bessere Lösung hat - vielleicht ohne Zeiger zu verwenden, bitte posten Sie es!

+0

Die doc für die destroy () func sagt "Zerstöre das Objekt, auf das der Zeiger zeigt." Du brauchst das Dealloc also nicht, da das das tut. Denkst du auch nicht: var packet = UnsafeMutablePointer .alloc (sizeof (MIDIPacket)) wäre besser? –

+1

@GeneDeLisa Ich denke, der Parameter für die Alloc-Methode ist die Anzahl der Objekte und nicht die Byte-Größe. Nicht sicher, wie es die Größe des Pakets überhaupt wissen würde. Soweit ich das beurteilen kann, weist es mehr Speicher zu, als er denkt, dass er benötigt wird, und nicht eine genau richtige Menge. Dies entspricht dem Bytearray im ObjC-Beispiel. Ich bin ein Anfänger, also könnte ich es falsch verstanden haben. – Thomas

+0

Ich wusste nicht über zerstören mit Dealloc. Ich habe Beispiele gesehen, in denen beide ausdrücklich genannt wurden, wie ich es hier getan habe. – Thomas

0

Ich habe auch die obige Routine zum Senden von MIDI-Befehlen von meiner App zu internen Synths im Hintergrund wie iMini, Z3TA +, SunRizer, etc. verwendet, aber ich konnte Speicherlecks nicht loswerden. Diese Version enthält keine unsicheren Zeiger und Allocs. Es funktioniert ohne die gefürchteten Speicherlecks.

static var z: UInt8 = 0 // initalize tuple with 256 x this UInt8 value: 

// Silly: why not an array instead of this.. a tuple is needed.. length must be exact 256.. 
// Don't know no other way to create a tuple with 256 elements... 
    var midiDataTuple = (z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z, z) 

// use the above tuple in MIDIPacket 



func midiSend(status: Int, val1: Int, val2 :Int) 
{ 
    var midipacket = MIDIPacket() 

    midipacket.timeStamp = 0 
    midipacket.length = 3 
    midipacket.data  = midiDataTuple //<-= 

    midipacket.data.0 = UInt8(status) 
    midipacket.data.1 = UInt8(val1 ) 
    midipacket.data.2 = UInt8(val2 ) 

    var midipacketlist = MIDIPacketList(numPackets: 1, packet: midipacket) 

    MIDIReceived(midiSource, &midipacketlist) 
} 




////////////////////////////////////////////////////////////// 
func noteOn(soundNr: Int, note: Int, velocity:Int) 
{ 
    let chan = midiChannelForSoundNr[soundNr] 
    midiSend((0x90 + chan), val1: note, val2: velocity) 
    notesPlaying[chan][note] = true 
} 

getestet.

+1

Eine kleine gute Nachricht: Derzeit (Xcode 7.3) ist das Datentupel bereits als 256 0s definiert, Sie müssen es also nicht initialisieren. Und ich stimme dem Missbrauch von Tupeln in allen C-APIs zu. Es gibt Vorschläge in der Swift Evolution Liste für Alternativen. –

0

So bin ich gelandet. Ich habe das Beispiel des Byte-Puffers verwendet, wie es in verschiedenen C/ObjC-Beispielen online zu finden ist, aber ich musste feststellen, dass ich etwas mehr Platz für die MIDIPacketList-Struktur selbst reservieren musste.

Ein MidiEvent ist nur ein UInt8-Array. Für gewöhnliche MIDI-Events hat es eine Länge von 3 Bytes: (Status, Data, Data).

/// A UInt8 array, usually 3 bytes long 
public typealias MidiEvent = [UInt8] 

extension MIDIPacketList { 
    init(midiEvents: [MidiEvent]) { 

     let timestamp = MIDITimeStamp(0) // do it now 
     let totalBytesInAllEvents = midiEvents.reduce(0) { total, event in 
      return total + event.count 
     } 

     // Without this, we'd run out of space for the last few MidiEvents 
     let listSize = sizeof(MIDIPacketList) + totalBytesInAllEvents 

     // CoreMIDI supports up to 65536 bytes, but in practical tests it seems 
     // certain devices accept much less than that at a time. Unless you're 
     // turning on/off ALL notes at once, 256 bytes should be plenty. 
     assert(totalBytesInAllEvents < 256, 
      "The packet list was too long! Split your data into multiple lists.") 

     // Allocate space for a certain number of bytes 
     let byteBuffer = UnsafeMutablePointer<UInt8>.alloc(listSize) 
     // Use that space for our MIDIPacketList 
     let packets = UnsafeMutablePointer<MIDIPacketList>(byteBuffer) 
     var packet = MIDIPacketListInit(packets) 

     midiEvents.forEach { event in 
      packet = MIDIPacketListAdd(packets, listSize, packet, timestamp, event.count, event) 
     } 

     self = packets.memory // copy the MIDIPacketList data into self 
     byteBuffer.dealloc(listSize) // release the manually managed memory 
    } 
} 

Wenn Sie also nur eine Midi-Note senden, sieht es ungefähr so ​​aus. Dieses Beispiel würde allerdings eine NoteOn Nachricht in den Nahen C auf Kanal 1 mit einer Geschwindigkeit von 100. Sie sollten Helferfunktionen verwenden, um diese MidiEvents zu machen senden, anstatt sie zu hart Codierung;)

var packets = MIDIPacketList(midiEvents: [[0x90, 60, 100]]) 
MIDISend(clientOutputPort, destination, &packetList) 
Verwandte Themen