2014-10-21 7 views
5

Patrzę na niektóre przykłady midi wyjścia za pomocą rdzenia midi.Używanie MIDIPacketList w swift

Konkretnie this question

i this

Mam kod, który działa w oparciu o te w objc i teraz chcę spróbować przetłumaczyć, że do szybkich.

linia ja przynajmniej zrozumieć jest to jedno: MIDIPacketList* pktList = (MIDIPacketList*) pktBuffer;

czytałem to jako uznająca pktlist wskaźnik typu MIDIPacketList i przypisując mu wartość pktBuffer, oddanych do typu MIDIPacketList

jestem nowy do C i objC, a to nie ma dla mnie sensu.

MIDIPacketList jest struct zdefiniowane here:

w jaki sposób ma to sensu rzucać ByteArray do typu struct MIDIPacketList i jaka jest ta stara się osiągnąć? Domyślam się, że próbuje zdefiniować rozmiar listy pakietów, ale dlaczego musimy to zrobić tutaj i jak to się dzieje? dlaczego nie wystarczy zrobić z MIDIPacketListAdd, jak dzieje się kilka linii później?

Oto moja próba wykonania klasy midi w szybkim tempie - czy ktoś może zobaczyć, co się dzieje? ten kod nie powoduje żadnych błędów w Xcode, dopóki nie zostanie uruchomiony. Mam działającą wersję tego w objC, ale nie mogę uzyskać rozmiaru listy pakietów zdefiniowanej w swift. (Przynajmniej myślę, że to 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 

Odpowiedz

5

znalazłem odpowiedź at this question

tablica bajtów w wersji objc jest paskudny Hack przeznaczyć trochę pamięci do packetList

Oto mój zrewidowane kod, który teraz działa.

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

    var packet = UnsafeMutablePointer<MIDIPacket>.alloc(1) 
    var packetList = UnsafeMutablePointer<MIDIPacketList>.alloc(1) 
    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") 
    } 
    packet.destroy() 
    //packet.dealloc(1) 
    packetList.destroy() 
    packetList.dealloc(1) 
} 

Jednak uwaga dealoksu wydaje się niepotrzebna, nie jestem do końca pewien, dlaczego. Czy MIDIReceived zajmuje się tym?

Jeśli ktoś ma lepsze rozwiązanie - może bez użycia wskaźników, proszę to opublikować!

+0

doc dla zniszczyć () func mówi: "Zniszcz obiekt, na który wskazuje wskaźnik". Więc nie potrzebujesz dealloc, ponieważ niszczyciel to robi. Ponadto, nie sądzisz: var pakiet = UnsafeMutablePointer .alloc (sizeof (MIDIPacket)) byłby lepszy? –

+1

@GeneDeLisa Myślę, że parametr dla metody alloc jest liczbą obiektów, a nie bajtem. Nie wiem, w jaki sposób mógłby znać rozmiar pakietu. O ile mogę powiedzieć, przydziela więcej pamięci, niż myśli, że będziesz potrzebować, a nie dokładnie poprawną kwotę. Tak więc jest to odpowiednik bytearray w przykładzie objC. Jestem początkującym, więc mogłem źle zrozumieć. – Thomas

+0

Nie wiedziałem o zniszczeniu obejmującym dealloc. Widziałem przykłady, w których oba zostały wyraźnie nazwane tak, jak ja tutaj. – Thomas

0

Użyłem również powyższej procedury do wysyłania poleceń midi z mojej aplikacji do wewnętrznych syntezatorów działających w tle, takich jak iMini, Z3TA +, Sunrizer, itp., Ale nie mogłem pozbyć się wycieków pamięci. Ta wersja nie ma niebezpiecznych wskaźników i allocentów. Działa bez przerażających wycieków pamięci. Przetestowano:

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 
} 

testowana.

+1

Trochę dobrych wiadomości: Obecnie (Xcode 7.3) krotka danych jest już zdefiniowana jako 256 0s, więc nie trzeba jej inicjować. Zgadzam się również z niewłaściwym użyciem krotek w całym C API. Na liście Swift Evolution znajdują się propozycje rozwiązań alternatywnych. –

0

Tak właśnie skończyłem. Użyłem przykładu bufora bajtów znalezionego w różnych przykładach C/ObjC w Internecie, ale odkryłem, że musiałem przydzielić nieco więcej miejsca dla samej struktury MIDIPacketList.

MidiEvent to tylko tablica UInt8. Dla zwykłych zdarzeń MIDI ma długość 3 bajty: (status, dane, dane).

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

Więc jeśli właśnie wysyłasz jedną notatkę midi, wyglądałoby to tak. Ten przykład wysłać wiadomość NoteOn na Bliski C na kanał 1 z prędkością 100. Należy użyć funkcji pomocniczych do tych MidiEvents jednak, zamiast ciężko ich kodowania;)

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