I'm trying to create a MIDI Thru connection that filters out specific control messages. I'm coding in Swift on macOS 11 and a Swift beginner.
The MIDIThruConnectionParams structure is variable length. The MIDIControlTransform type is defined but I am not clear how to add them. Is there a recommended / best / safest way?
There is this comment after the structure definition:
// remainder of structure is variable-length:
// MIDIControlTransform controls[];
// MIDIValueMap maps[];
The MIDIThruConnectionParams structure is variable length. The MIDIControlTransform type is defined but I am not clear how to add them. Is there a recommended / best / safest way?
There is this comment after the structure definition:
// remainder of structure is variable-length:
// MIDIControlTransform controls[];
// MIDIValueMap maps[];
I'm not good at MIDI, so just read Apple's documentations and very few articles on the web.
(This was the only useful one I found.)
One thing sure is that using MIDIThruConnectionParams is very difficult even for experienced Swift programmers.
You may need something like the following:
(You may need to fix many parts and add more codes...)
Find some third party frameworks that are more Swifty (sorry I do not know if any).
Or learn how to interact with C-based APIs including pointers and C-structs with variable-length member for months, possibly for years.
(This was the only useful one I found.)
One thing sure is that using MIDIThruConnectionParams is very difficult even for experienced Swift programmers.
You may need something like the following:
Code Block import CoreMIDI /// Fixed size C-array UInt8[128] typealias MIDIValueMapValueType = (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) extension MIDIValueMap { init(_ array: [UInt8]) { assert(array.count == 128, "array needs to contain 128 elements") let value = array.withUnsafeBytes {bytes in bytes.load(as: MIDIValueMapValueType.self) } self.init(value: value) } } extension UnsafeMutablePointer where Pointee == MIDIThruConnectionParams { var controls: UnsafeMutablePointer<MIDIControlTransform> { return ( UnsafeMutableRawPointer(self) + MemoryLayout<MIDIThruConnectionParams>.stride ).assumingMemoryBound(to: MIDIControlTransform.self) } var maps: UnsafeMutablePointer<MIDIValueMap> { return ( UnsafeMutableRawPointer(self) + MemoryLayout<MIDIThruConnectionParams>.stride + MemoryLayout<MIDIControlTransform>.stride * Int(self.pointee.numControlTransforms) ).assumingMemoryBound(to: MIDIValueMap.self) } } func createMIDIThruConnectionParams( source: MIDIEndpointRef? = nil, destination: MIDIEndpointRef? = nil, controlTransforms: [MIDIControlTransform] = [], maps: [MIDIValueMap] = [] ) -> Data { let size = MemoryLayout<MIDIThruConnectionParams>.stride + MemoryLayout<MIDIControlTransform>.stride * controlTransforms.count + MemoryLayout<MIDIValueMap>.stride * maps.count var midiThruConnectionParams = Data(count: size) midiThruConnectionParams.withUnsafeMutableBytes {bufPtr in let paramsPtr = bufPtr.baseAddress!.assumingMemoryBound(to: MIDIThruConnectionParams.self) MIDIThruConnectionParamsInitialize(paramsPtr) // if let source = source { let thruSource = MIDIThruConnectionEndpoint(endpointRef: source, uniqueID: MIDIUniqueID(1)) paramsPtr.pointee.numSources = 1 paramsPtr.pointee.sources.0 = thruSource } if let dest = destination { let thruDest = MIDIThruConnectionEndpoint(endpointRef: dest, uniqueID: MIDIUniqueID(2)) paramsPtr.pointee.numDestinations = 1 paramsPtr.pointee.destinations.0 = thruDest } // paramsPtr.pointee.numControlTransforms = UInt16(controlTransforms.count) paramsPtr.pointee.numMaps = UInt16(maps.count) memcpy(paramsPtr.controls, controlTransforms, MemoryLayout<MIDIControlTransform>.stride * controlTransforms.count) memcpy(paramsPtr.maps, maps, MemoryLayout<MIDIValueMap>.stride * maps.count) //Do other initializations //paramsPtr.pointee.... = ... //... } return midiThruConnectionParams } let connectionParams = createMIDIThruConnectionParams( controlTransforms: [ MIDIControlTransform(/*...*/), //... ] ) var connectionRef = MIDIThruConnectionRef() let status = MIDIThruConnectionCreate(nil, connectionParams as CFData, &connectionRef)
(You may need to fix many parts and add more codes...)
If you really are a Swift beginner, I would recommend not to use these structs directly in your Swift code.a Swift beginner.
Find some third party frameworks that are more Swifty (sorry I do not know if any).
Or learn how to interact with C-based APIs including pointers and C-structs with variable-length member for months, possibly for years.