Skip to content

Commit 7a219c5

Browse files
authored
Merge pull request #82 from orchetect/dev
Dev merge
2 parents bf6ce74 + 998335c commit 7a219c5

File tree

6 files changed

+299
-23
lines changed

6 files changed

+299
-23
lines changed

Sources/MIDIKit/IO/Managed/InputConnection.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ extension MIDI.IO.InputConnection {
297297
// MARK: Add Endpoints
298298

299299
/// Add output endpoints to the connection.
300+
/// This respects the state of `preventAddingManagedOutputs`.
300301
public func add(
301302
outputs: [MIDI.IO.OutputEndpointIDCriteria]
302303
) {
@@ -312,6 +313,7 @@ extension MIDI.IO.InputConnection {
312313
}
313314

314315
/// Add output endpoints to the connection.
316+
/// This respects the state of `preventAddingManagedOutputs`.
315317
@_disfavoredOverload
316318
public func add(
317319
outputs: [MIDI.IO.OutputEndpoint]

Sources/MIDIKit/IO/Managed/OutputConnection.swift

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,30 +31,61 @@ extension MIDI.IO {
3131

3232
// class-specific
3333

34-
public private(set) var inputsCriteria: Set<MIDI.IO.InputEndpointIDCriteria>
34+
public private(set) var inputsCriteria: Set<MIDI.IO.InputEndpointIDCriteria> = []
35+
36+
private func setInputsCriteria(_ criteria: Set<MIDI.IO.InputEndpointIDCriteria>) {
37+
38+
if preventAddingManagedInputs,
39+
let midiManager = midiManager
40+
{
41+
let managedInputs: [MIDI.IO.InputEndpointIDCriteria] = midiManager.managedInputs
42+
.compactMap { $0.value.uniqueID }
43+
.map { .uniqueID($0) }
44+
45+
inputsCriteria = criteria
46+
.filter { !managedInputs.contains($0) }
47+
} else {
48+
inputsCriteria = criteria
49+
}
50+
51+
}
3552

3653
/// The Core MIDI input endpoint(s) reference(s).
3754
public private(set) var coreMIDIInputEndpointRefs: Set<MIDI.IO.CoreMIDIEndpointRef> = []
3855

56+
/// When new inputs appear in the system, automatically add them to the connection.
57+
public var automaticallyAddNewInputs: Bool
58+
59+
/// Prevent virtual inputs owned by the `Manager` (`.managedInputs`) from being added to the connection.
60+
public var preventAddingManagedInputs: Bool
61+
3962
// init
4063

4164
/// Internal init.
4265
/// This object is not meant to be instanced by the user. This object is automatically created and managed by the MIDI I/O `Manager` instance when calling `.addOutputConnection()`, and destroyed when calling `.remove(.outputConnection, ...)` or `.removeAll()`.
4366
///
4467
/// - Parameters:
4568
/// - toInputs: Input(s) to connect to.
69+
/// - automaticallyAddNewInputs: When new inputs appear in the system, automatically add them to the connection.
70+
/// - preventAddingManagedInputs: Prevent virtual inputs owned by the `Manager` from being added to the connection.
4671
/// - midiManager: Reference to I/O Manager object.
4772
/// - api: Core MIDI API version.
4873
internal init(
4974
toInputs: Set<MIDI.IO.InputEndpointIDCriteria>,
75+
automaticallyAddNewInputs: Bool,
76+
preventAddingManagedInputs: Bool,
5077
midiManager: MIDI.IO.Manager,
5178
api: MIDI.IO.APIVersion = .bestForPlatform()
5279
) {
5380

54-
self.inputsCriteria = toInputs
5581
self.midiManager = midiManager
82+
self.automaticallyAddNewInputs = automaticallyAddNewInputs
83+
self.preventAddingManagedInputs = preventAddingManagedInputs
5684
self.api = api.isValidOnCurrentPlatform ? api : .bestForPlatform()
5785

86+
// relies on midiManager and preventAddingManagedInputs
87+
setInputsCriteria(toInputs)
88+
5889
}
5990

6091
deinit {
@@ -171,11 +202,13 @@ extension MIDI.IO.OutputConnection {
171202
// MARK: Add Endpoints
172203

173204
/// Add input endpoints from the connection.
205+
/// This respects the state of `preventAddingManagedInputs`.
174206
public func add(
175207
inputs: [MIDI.IO.InputEndpointIDCriteria]
176208
) {
177209

178-
inputsCriteria.formUnion(inputs)
210+
let combined = inputsCriteria.union(inputs)
211+
setInputsCriteria(combined)
179212

180213
if let midiManager = midiManager {
181214
// this will re-generate coreMIDIInputEndpointRefs
@@ -185,6 +218,7 @@ extension MIDI.IO.OutputConnection {
185218
}
186219

187220
/// Add input endpoints from the connection.
221+
/// This respects the state of `preventAddingManagedInputs`.
188222
@_disfavoredOverload
189223
public func add(
190224
inputs: [MIDI.IO.InputEndpoint]
@@ -201,7 +235,8 @@ extension MIDI.IO.OutputConnection {
201235
inputs: [MIDI.IO.InputEndpointIDCriteria]
202236
) {
203237

204-
inputsCriteria.subtract(inputs)
238+
let removed = inputsCriteria.subtracting(inputs)
239+
setInputsCriteria(removed)
205240

206241
if let midiManager = midiManager {
207242
// this will re-generate coreMIDIInputEndpointRefs
@@ -223,12 +258,11 @@ extension MIDI.IO.OutputConnection {
223258
/// Remove all input endpoints from the connection.
224259
public func removeAllInputs() {
225260

226-
inputsCriteria = []
261+
let inputsToDisconnect = inputsCriteria
227262

228-
if let midiManager = midiManager {
229-
// this will re-generate coreMIDIInputEndpointRefs
230-
try? refreshConnection(in: midiManager)
231-
}
263+
setInputsCriteria([])
264+
265+
remove(inputs: Array(inputsToDisconnect))
232266

233267
}
234268

@@ -238,6 +272,16 @@ extension MIDI.IO.OutputConnection {
238272

239273
internal func notification(_ internalNotification: MIDI.IO.InternalNotification) {
240274

275+
if automaticallyAddNewInputs,
276+
let notif = MIDI.IO.SystemNotification(internalNotification, cache: nil),
277+
case .added(parent: _,
278+
child: let child) = notif,
279+
case .inputEndpoint(let newInput) = child
280+
{
281+
add(inputs: [newInput])
282+
return
283+
}
284+
241285
switch internalNotification {
242286
case .setupChanged, .added, .removed:
243287
if let midiManager = midiManager {

Sources/MIDIKit/IO/Manager/Manager addOutputConnection.swift

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,23 @@ extension MIDI.IO.Manager {
1515
/// - Parameters:
1616
/// - toInputs: Criteria for identifying a MIDI endpoint(s) in the system to connect to.
1717
/// - tag: Internal unique tag to reference the managed item in the `Manager`.
18+
/// - automaticallyAddNewInputs: When new inputs appear in the system, automatically add them to the connection.
19+
/// - preventAddingManagedInputs: Prevent virtual inputs owned by the `Manager` from being added to the connection.
1820
///
1921
/// - Throws: `MIDI.IO.MIDIError`
2022
public func addOutputConnection(
2123
toInputs: Set<MIDI.IO.InputEndpointIDCriteria>,
22-
tag: String
24+
tag: String,
25+
automaticallyAddNewInputs: Bool = false,
26+
preventAddingManagedInputs: Bool = false
2327
) throws {
2428

2529
try eventQueue.sync {
2630

2731
let newCS = MIDI.IO.OutputConnection(
2832
toInputs: toInputs,
33+
automaticallyAddNewInputs: automaticallyAddNewInputs,
34+
preventAddingManagedInputs: preventAddingManagedInputs,
2935
midiManager: self,
3036
api: preferredAPI
3137
)
@@ -48,16 +54,22 @@ extension MIDI.IO.Manager {
4854
/// - Parameters:
4955
/// - toInputs: Criteria for identifying a MIDI endpoint(s) in the system to connect to.
5056
/// - tag: Internal unique tag to reference the managed item in the `Manager`.
57+
/// - automaticallyAddNewInputs: When new inputs appear in the system, automatically add them to the connection.
58+
/// - preventAddingManagedInputs: Prevent virtual inputs owned by the `Manager` from being added to the connection.
5159
///
5260
/// - Throws: `MIDI.IO.MIDIError`
5361
public func addOutputConnection(
5462
toInputs: [MIDI.IO.InputEndpointIDCriteria],
55-
tag: String
63+
tag: String,
64+
automaticallyAddNewInputs: Bool = false,
65+
preventAddingManagedInputs: Bool = false
5666
) throws {
5767

5868
try addOutputConnection(
5969
toInputs: Set(toInputs),
60-
tag: tag
70+
tag: tag,
71+
automaticallyAddNewInputs: automaticallyAddNewInputs,
72+
preventAddingManagedInputs: preventAddingManagedInputs
6173
)
6274

6375
}
@@ -69,17 +81,23 @@ extension MIDI.IO.Manager {
6981
/// - Parameters:
7082
/// - toInputs: Criteria for identifying a MIDI endpoint(s) in the system to connect to.
7183
/// - tag: Internal unique tag to reference the managed item in the `Manager`.
84+
/// - automaticallyAddNewInputs: When new inputs appear in the system, automatically add them to the connection.
85+
/// - preventAddingManagedInputs: Prevent virtual inputs owned by the `Manager` from being added to the connection.
7286
///
7387
/// - Throws: `MIDI.IO.MIDIError`
7488
@_disfavoredOverload
7589
public func addOutputConnection(
7690
toInputs: [MIDI.IO.InputEndpoint],
77-
tag: String
91+
tag: String,
92+
automaticallyAddNewInputs: Bool = false,
93+
preventAddingManagedInputs: Bool = false
7894
) throws {
7995

8096
try addOutputConnection(
8197
toInputs: toInputs.map { .uniqueID($0.uniqueID) },
82-
tag: tag
98+
tag: tag,
99+
automaticallyAddNewInputs: automaticallyAddNewInputs,
100+
preventAddingManagedInputs: preventAddingManagedInputs
83101
)
84102

85103
}

Tests/MIDIKitTests/IO/Core MIDI/MIDIEventList/MIDIEventList Packets Tests.swift

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import CoreMIDI
1111

1212
final class MIDIEventListPackets_Tests: XCTestCase {
1313

14-
@available(macOS 11, iOS 14, macCatalyst 14, tvOS 14, watchOS 7, *)
1514
func testSinglePacketWithOneUMP() throws {
1615

16+
guard #available(macOS 11, iOS 14, macCatalyst 14, tvOS 14, watchOS 7, *)
17+
else { return }
18+
1719
let timeStamp: MIDITimeStamp = 0 // mach_absolute_time()
1820

1921
var eventList = try makeEventList(
@@ -37,9 +39,11 @@ final class MIDIEventListPackets_Tests: XCTestCase {
3739

3840
}
3941

40-
@available(macOS 11, iOS 14, macCatalyst 14, tvOS 14, watchOS 7, *)
4142
func testSinglePacketWithMultipleUMPs() throws {
4243

44+
guard #available(macOS 11, iOS 14, macCatalyst 14, tvOS 14, watchOS 7, *)
45+
else { return }
46+
4347
let timeStamp: MIDITimeStamp = 0 // mach_absolute_time()
4448

4549
var eventList = try makeEventList(
@@ -67,9 +71,11 @@ final class MIDIEventListPackets_Tests: XCTestCase {
6771

6872
}
6973

70-
@available(macOS 11, iOS 14, macCatalyst 14, tvOS 14, watchOS 7, *)
7174
func testMultiplePacketsWithSingleUMPs() throws {
7275

76+
guard #available(macOS 11, iOS 14, macCatalyst 14, tvOS 14, watchOS 7, *)
77+
else { return }
78+
7379
let timeStamp: MIDITimeStamp = 0 // mach_absolute_time()
7480

7581
var eventList = try makeEventList(
@@ -97,9 +103,11 @@ final class MIDIEventListPackets_Tests: XCTestCase {
97103

98104
}
99105

100-
@available(macOS 11, iOS 14, macCatalyst 14, tvOS 14, watchOS 7, *)
101106
func testMultiplePacketsWithMultipleUMPs() throws {
102107

108+
guard #available(macOS 11, iOS 14, macCatalyst 14, tvOS 14, watchOS 7, *)
109+
else { return }
110+
103111
let timeStamp: MIDITimeStamp = 0 // mach_absolute_time()
104112

105113
var eventList = try makeEventList(
@@ -158,4 +166,3 @@ final class MIDIEventListPackets_Tests: XCTestCase {
158166
}
159167

160168
#endif
161-

Tests/MIDIKitTests/IO/Inputs and Outputs/InputConnection Tests.swift

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ import CoreMIDI
1313

1414
final class InputsAndOutputs_InputConnection_Tests: XCTestCase {
1515

16+
override func setUp() {
17+
wait(sec: 0.2)
18+
}
19+
1620
@MIDI.Atomic var connEvents: [MIDI.Event] = []
1721

1822
/// Test initializing an InputConnection, adding/removing outputs, and receiving MIDI events.
@@ -136,7 +140,7 @@ final class InputsAndOutputs_InputConnection_Tests: XCTestCase {
136140

137141
connEvents = []
138142

139-
// add new connection, connecting to output1
143+
// add new connection
140144
let connTag = "testInputConnection"
141145
try manager.addInputConnection(
142146
toOutputs: [],
@@ -193,7 +197,7 @@ final class InputsAndOutputs_InputConnection_Tests: XCTestCase {
193197

194198
connEvents = []
195199

196-
// add new connection, connecting to output1
200+
// add new connection
197201
let connTag = "testInputConnection"
198202
try manager.addInputConnection(
199203
toOutputs: [],
@@ -264,7 +268,7 @@ final class InputsAndOutputs_InputConnection_Tests: XCTestCase {
264268

265269
wait(sec: 0.2)
266270

267-
// add new connection, connecting to output1
271+
// add new connection, attempting to connect to output1
268272
let connTag = "testInputConnection"
269273
try manager.addInputConnection(
270274
toOutputs: [output1.endpoint],
@@ -280,6 +284,7 @@ final class InputsAndOutputs_InputConnection_Tests: XCTestCase {
280284
let conn = try XCTUnwrap(manager.managedInputConnections[connTag])
281285
wait(sec: 0.5) // some time for connection to setup
282286

287+
// assert output1 was not added to the connection
283288
XCTAssertEqual(conn.outputsCriteria, [])
284289
XCTAssertEqual(conn.coreMIDIOutputEndpointRefs, [])
285290
XCTAssertEqual(conn.endpoints, [])
@@ -290,6 +295,14 @@ final class InputsAndOutputs_InputConnection_Tests: XCTestCase {
290295
XCTAssertEqual(connEvents, [])
291296
connEvents = []
292297

298+
// check that manually adding output1 is also not allowed
299+
conn.add(outputs: [output1.endpoint])
300+
301+
// assert output1 was not added to the connection
302+
XCTAssertEqual(conn.outputsCriteria, [])
303+
XCTAssertEqual(conn.coreMIDIOutputEndpointRefs, [])
304+
XCTAssertEqual(conn.endpoints, [])
305+
293306
}
294307

295308
}

0 commit comments

Comments
 (0)