Skip to content

Commit

Permalink
Merge pull request #82 from orchetect/dev
Browse files Browse the repository at this point in the history
Dev merge
  • Loading branch information
orchetect authored Apr 12, 2022
2 parents bf6ce74 + 998335c commit 7a219c5
Show file tree
Hide file tree
Showing 6 changed files with 299 additions and 23 deletions.
2 changes: 2 additions & 0 deletions Sources/MIDIKit/IO/Managed/InputConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ extension MIDI.IO.InputConnection {
// MARK: Add Endpoints

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

/// Add output endpoints to the connection.
/// This respects the state of `preventAddingManagedOutputs`.
@_disfavoredOverload
public func add(
outputs: [MIDI.IO.OutputEndpoint]
Expand Down
62 changes: 53 additions & 9 deletions Sources/MIDIKit/IO/Managed/OutputConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,30 +31,61 @@ extension MIDI.IO {

// class-specific

public private(set) var inputsCriteria: Set<MIDI.IO.InputEndpointIDCriteria>
public private(set) var inputsCriteria: Set<MIDI.IO.InputEndpointIDCriteria> = []

private func setInputsCriteria(_ criteria: Set<MIDI.IO.InputEndpointIDCriteria>) {

if preventAddingManagedInputs,
let midiManager = midiManager
{
let managedInputs: [MIDI.IO.InputEndpointIDCriteria] = midiManager.managedInputs
.compactMap { $0.value.uniqueID }
.map { .uniqueID($0) }

inputsCriteria = criteria
.filter { !managedInputs.contains($0) }
} else {
inputsCriteria = criteria
}

}

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

/// When new inputs appear in the system, automatically add them to the connection.
public var automaticallyAddNewInputs: Bool

/// Prevent virtual inputs owned by the `Manager` (`.managedInputs`) from being added to the connection.
public var preventAddingManagedInputs: Bool

// init

/// Internal init.
/// 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()`.
///
/// - Parameters:
/// - toInputs: Input(s) to connect to.
/// - automaticallyAddNewInputs: When new inputs appear in the system, automatically add them to the connection.
/// - preventAddingManagedInputs: Prevent virtual inputs owned by the `Manager` from being added to the connection.
/// - midiManager: Reference to I/O Manager object.
/// - api: Core MIDI API version.
internal init(
toInputs: Set<MIDI.IO.InputEndpointIDCriteria>,
automaticallyAddNewInputs: Bool,
preventAddingManagedInputs: Bool,
midiManager: MIDI.IO.Manager,
api: MIDI.IO.APIVersion = .bestForPlatform()
) {

self.inputsCriteria = toInputs
self.midiManager = midiManager
self.automaticallyAddNewInputs = automaticallyAddNewInputs
self.preventAddingManagedInputs = preventAddingManagedInputs
self.api = api.isValidOnCurrentPlatform ? api : .bestForPlatform()

// relies on midiManager and preventAddingManagedInputs
setInputsCriteria(toInputs)

}

deinit {
Expand Down Expand Up @@ -171,11 +202,13 @@ extension MIDI.IO.OutputConnection {
// MARK: Add Endpoints

/// Add input endpoints from the connection.
/// This respects the state of `preventAddingManagedInputs`.
public func add(
inputs: [MIDI.IO.InputEndpointIDCriteria]
) {

inputsCriteria.formUnion(inputs)
let combined = inputsCriteria.union(inputs)
setInputsCriteria(combined)

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

/// Add input endpoints from the connection.
/// This respects the state of `preventAddingManagedInputs`.
@_disfavoredOverload
public func add(
inputs: [MIDI.IO.InputEndpoint]
Expand All @@ -201,7 +235,8 @@ extension MIDI.IO.OutputConnection {
inputs: [MIDI.IO.InputEndpointIDCriteria]
) {

inputsCriteria.subtract(inputs)
let removed = inputsCriteria.subtracting(inputs)
setInputsCriteria(removed)

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

inputsCriteria = []
let inputsToDisconnect = inputsCriteria

if let midiManager = midiManager {
// this will re-generate coreMIDIInputEndpointRefs
try? refreshConnection(in: midiManager)
}
setInputsCriteria([])

remove(inputs: Array(inputsToDisconnect))

}

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

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

if automaticallyAddNewInputs,
let notif = MIDI.IO.SystemNotification(internalNotification, cache: nil),
case .added(parent: _,
child: let child) = notif,
case .inputEndpoint(let newInput) = child
{
add(inputs: [newInput])
return
}

switch internalNotification {
case .setupChanged, .added, .removed:
if let midiManager = midiManager {
Expand Down
28 changes: 23 additions & 5 deletions Sources/MIDIKit/IO/Manager/Manager addOutputConnection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,23 @@ extension MIDI.IO.Manager {
/// - Parameters:
/// - toInputs: Criteria for identifying a MIDI endpoint(s) in the system to connect to.
/// - tag: Internal unique tag to reference the managed item in the `Manager`.
/// - automaticallyAddNewInputs: When new inputs appear in the system, automatically add them to the connection.
/// - preventAddingManagedInputs: Prevent virtual inputs owned by the `Manager` from being added to the connection.
///
/// - Throws: `MIDI.IO.MIDIError`
public func addOutputConnection(
toInputs: Set<MIDI.IO.InputEndpointIDCriteria>,
tag: String
tag: String,
automaticallyAddNewInputs: Bool = false,
preventAddingManagedInputs: Bool = false
) throws {

try eventQueue.sync {

let newCS = MIDI.IO.OutputConnection(
toInputs: toInputs,
automaticallyAddNewInputs: automaticallyAddNewInputs,
preventAddingManagedInputs: preventAddingManagedInputs,
midiManager: self,
api: preferredAPI
)
Expand All @@ -48,16 +54,22 @@ extension MIDI.IO.Manager {
/// - Parameters:
/// - toInputs: Criteria for identifying a MIDI endpoint(s) in the system to connect to.
/// - tag: Internal unique tag to reference the managed item in the `Manager`.
/// - automaticallyAddNewInputs: When new inputs appear in the system, automatically add them to the connection.
/// - preventAddingManagedInputs: Prevent virtual inputs owned by the `Manager` from being added to the connection.
///
/// - Throws: `MIDI.IO.MIDIError`
public func addOutputConnection(
toInputs: [MIDI.IO.InputEndpointIDCriteria],
tag: String
tag: String,
automaticallyAddNewInputs: Bool = false,
preventAddingManagedInputs: Bool = false
) throws {

try addOutputConnection(
toInputs: Set(toInputs),
tag: tag
tag: tag,
automaticallyAddNewInputs: automaticallyAddNewInputs,
preventAddingManagedInputs: preventAddingManagedInputs
)

}
Expand All @@ -69,17 +81,23 @@ extension MIDI.IO.Manager {
/// - Parameters:
/// - toInputs: Criteria for identifying a MIDI endpoint(s) in the system to connect to.
/// - tag: Internal unique tag to reference the managed item in the `Manager`.
/// - automaticallyAddNewInputs: When new inputs appear in the system, automatically add them to the connection.
/// - preventAddingManagedInputs: Prevent virtual inputs owned by the `Manager` from being added to the connection.
///
/// - Throws: `MIDI.IO.MIDIError`
@_disfavoredOverload
public func addOutputConnection(
toInputs: [MIDI.IO.InputEndpoint],
tag: String
tag: String,
automaticallyAddNewInputs: Bool = false,
preventAddingManagedInputs: Bool = false
) throws {

try addOutputConnection(
toInputs: toInputs.map { .uniqueID($0.uniqueID) },
tag: tag
tag: tag,
automaticallyAddNewInputs: automaticallyAddNewInputs,
preventAddingManagedInputs: preventAddingManagedInputs
)

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ import CoreMIDI

final class MIDIEventListPackets_Tests: XCTestCase {

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

guard #available(macOS 11, iOS 14, macCatalyst 14, tvOS 14, watchOS 7, *)
else { return }

let timeStamp: MIDITimeStamp = 0 // mach_absolute_time()

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

}

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

guard #available(macOS 11, iOS 14, macCatalyst 14, tvOS 14, watchOS 7, *)
else { return }

let timeStamp: MIDITimeStamp = 0 // mach_absolute_time()

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

}

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

guard #available(macOS 11, iOS 14, macCatalyst 14, tvOS 14, watchOS 7, *)
else { return }

let timeStamp: MIDITimeStamp = 0 // mach_absolute_time()

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

}

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

guard #available(macOS 11, iOS 14, macCatalyst 14, tvOS 14, watchOS 7, *)
else { return }

let timeStamp: MIDITimeStamp = 0 // mach_absolute_time()

var eventList = try makeEventList(
Expand Down Expand Up @@ -158,4 +166,3 @@ final class MIDIEventListPackets_Tests: XCTestCase {
}

#endif

Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ import CoreMIDI

final class InputsAndOutputs_InputConnection_Tests: XCTestCase {

override func setUp() {
wait(sec: 0.2)
}

@MIDI.Atomic var connEvents: [MIDI.Event] = []

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

connEvents = []

// add new connection, connecting to output1
// add new connection
let connTag = "testInputConnection"
try manager.addInputConnection(
toOutputs: [],
Expand Down Expand Up @@ -193,7 +197,7 @@ final class InputsAndOutputs_InputConnection_Tests: XCTestCase {

connEvents = []

// add new connection, connecting to output1
// add new connection
let connTag = "testInputConnection"
try manager.addInputConnection(
toOutputs: [],
Expand Down Expand Up @@ -264,7 +268,7 @@ final class InputsAndOutputs_InputConnection_Tests: XCTestCase {

wait(sec: 0.2)

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

// assert output1 was not added to the connection
XCTAssertEqual(conn.outputsCriteria, [])
XCTAssertEqual(conn.coreMIDIOutputEndpointRefs, [])
XCTAssertEqual(conn.endpoints, [])
Expand All @@ -290,6 +295,14 @@ final class InputsAndOutputs_InputConnection_Tests: XCTestCase {
XCTAssertEqual(connEvents, [])
connEvents = []

// check that manually adding output1 is also not allowed
conn.add(outputs: [output1.endpoint])

// assert output1 was not added to the connection
XCTAssertEqual(conn.outputsCriteria, [])
XCTAssertEqual(conn.coreMIDIOutputEndpointRefs, [])
XCTAssertEqual(conn.endpoints, [])

}

}
Expand Down
Loading

0 comments on commit 7a219c5

Please sign in to comment.