Skip to content

Commit

Permalink
Issue #106: Added MIKMIDIConnectionManager for managing and persistin…
Browse files Browse the repository at this point in the history
…g connected devices.
  • Loading branch information
Andrew Madsen committed Nov 6, 2015
1 parent deabcea commit 8bc1638
Show file tree
Hide file tree
Showing 5 changed files with 554 additions and 0 deletions.
12 changes: 12 additions & 0 deletions Framework/MIKMIDI.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@
83FB360E1B42D58000F91DCD /* MIKMIDISequence+MIKMIDIPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 83FB360C1B42D58000F91DCD /* MIKMIDISequence+MIKMIDIPrivate.h */; };
9D07CAC71BEA70E200C4ABB0 /* MIKMIDICompilerCompatibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D07CAC61BEA70E200C4ABB0 /* MIKMIDICompilerCompatibility.h */; settings = {ATTRIBUTES = (Public, ); }; };
9D07CAC81BEA70E200C4ABB0 /* MIKMIDICompilerCompatibility.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D07CAC61BEA70E200C4ABB0 /* MIKMIDICompilerCompatibility.h */; settings = {ATTRIBUTES = (Public, ); }; };
9D07CB221BEC13E400C4ABB0 /* MIKMIDIConnectionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D07CB201BEC13E400C4ABB0 /* MIKMIDIConnectionManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
9D07CB231BEC13E400C4ABB0 /* MIKMIDIConnectionManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D07CB201BEC13E400C4ABB0 /* MIKMIDIConnectionManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
9D07CB241BEC13E400C4ABB0 /* MIKMIDIConnectionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D07CB211BEC13E400C4ABB0 /* MIKMIDIConnectionManager.m */; };
9D07CB251BEC13E400C4ABB0 /* MIKMIDIConnectionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D07CB211BEC13E400C4ABB0 /* MIKMIDIConnectionManager.m */; };
9D0895EE1B0D29F200A5872E /* MIKMIDIMappingItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D0895EC1B0D29F200A5872E /* MIKMIDIMappingItem.h */; settings = {ATTRIBUTES = (Public, ); }; };
9D0895EF1B0D29F200A5872E /* MIKMIDIMappingItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D0895EC1B0D29F200A5872E /* MIKMIDIMappingItem.h */; settings = {ATTRIBUTES = (Public, ); }; };
9D0895F01B0D29F200A5872E /* MIKMIDIMappingItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0895ED1B0D29F200A5872E /* MIKMIDIMappingItem.m */; };
Expand Down Expand Up @@ -351,6 +355,8 @@
83C850C81B7AA452001D71B0 /* MIKMIDIMappingManager_SubclassMethods.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MIKMIDIMappingManager_SubclassMethods.h; sourceTree = "<group>"; };
83FB360C1B42D58000F91DCD /* MIKMIDISequence+MIKMIDIPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "MIKMIDISequence+MIKMIDIPrivate.h"; sourceTree = "<group>"; };
9D07CAC61BEA70E200C4ABB0 /* MIKMIDICompilerCompatibility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIKMIDICompilerCompatibility.h; sourceTree = "<group>"; };
9D07CB201BEC13E400C4ABB0 /* MIKMIDIConnectionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIKMIDIConnectionManager.h; sourceTree = "<group>"; };
9D07CB211BEC13E400C4ABB0 /* MIKMIDIConnectionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIKMIDIConnectionManager.m; sourceTree = "<group>"; };
9D0895EC1B0D29F200A5872E /* MIKMIDIMappingItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIKMIDIMappingItem.h; sourceTree = "<group>"; };
9D0895ED1B0D29F200A5872E /* MIKMIDIMappingItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIKMIDIMappingItem.m; sourceTree = "<group>"; };
9D0895F21B0D2A4700A5872E /* MIKMIDIMappableResponder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIKMIDIMappableResponder.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -749,6 +755,8 @@
children = (
9D74EF3C17A713A100BEE89F /* MIKMIDIDeviceManager.h */,
9D74EF3D17A713A100BEE89F /* MIKMIDIDeviceManager.m */,
9D07CB201BEC13E400C4ABB0 /* MIKMIDIConnectionManager.h */,
9D07CB211BEC13E400C4ABB0 /* MIKMIDIConnectionManager.m */,
9D74EF5017A713A100BEE89F /* MIKMIDIObject.h */,
9D74EF5117A713A100BEE89F /* MIKMIDIObject.m */,
9D74EF5217A713A100BEE89F /* MIKMIDIObject_SubclassMethods.h */,
Expand Down Expand Up @@ -902,6 +910,7 @@
9D74EF8317A713A100BEE89F /* MIKMIDIObject.h in Headers */,
9D07CAC71BEA70E200C4ABB0 /* MIKMIDICompilerCompatibility.h in Headers */,
9D74EF8617A713A100BEE89F /* MIKMIDIOutputPort.h in Headers */,
9D07CB221BEC13E400C4ABB0 /* MIKMIDIConnectionManager.h in Headers */,
9D74EF8817A713A100BEE89F /* MIKMIDIPort.h in Headers */,
9D74EF8B17A713A100BEE89F /* MIKMIDIResponder.h in Headers */,
9D74EF8C17A713A100BEE89F /* MIKMIDISourceEndpoint.h in Headers */,
Expand Down Expand Up @@ -959,6 +968,7 @@
9D0895EF1B0D29F200A5872E /* MIKMIDIMappingItem.h in Headers */,
9DAF8B701A7B00A700F46528 /* MIKMIDIMetaCuePointEvent.h in Headers */,
9DAF8B671A7B008A00F46528 /* MIKMIDIProgramChangeCommand.h in Headers */,
9D07CB231BEC13E400C4ABB0 /* MIKMIDIConnectionManager.h in Headers */,
9DED4E231AA77DAC00DA8356 /* MIKMIDIPitchBendChangeEvent.h in Headers */,
9DED4E371AA90CA700DA8356 /* MIKMIDIPitchBendChangeCommand.h in Headers */,
9DB366F71A964D4A001D1CF3 /* MIKMIDISynthesizerInstrument.h in Headers */,
Expand Down Expand Up @@ -1196,6 +1206,7 @@
9DED4E381AA90CA700DA8356 /* MIKMIDIPitchBendChangeCommand.m in Sources */,
9D74EF8F17A713A100BEE89F /* MIKMIDISystemExclusiveCommand.m in Sources */,
9D74EF9117A713A100BEE89F /* MIKMIDISystemMessageCommand.m in Sources */,
9D07CB241BEC13E400C4ABB0 /* MIKMIDIConnectionManager.m in Sources */,
839D935419C3A2F5007589C3 /* MIKMIDIMetaEvent.m in Sources */,
9D7027D31ACC9D7A009AFAED /* MIKMIDIMacDebugQuickLookSupport.m in Sources */,
9D74EF9317A713A100BEE89F /* MIKMIDIUtilities.m in Sources */,
Expand Down Expand Up @@ -1264,6 +1275,7 @@
9DAF8B4C1A7AFF7500F46528 /* MIKMIDISequencer.m in Sources */,
9DB366F31A964C55001D1CF3 /* MIKMIDISynthesizer.m in Sources */,
9DAF8B4D1A7AFF7500F46528 /* MIKMIDIUtilities.m in Sources */,
9D07CB251BEC13E400C4ABB0 /* MIKMIDIConnectionManager.m in Sources */,
9DAF8B4E1A7AFF7500F46528 /* MIKMIDICommandThrottler.m in Sources */,
9DAF8B4F1A7AFF7500F46528 /* MIKMIDIClock.m in Sources */,
9DAF8B501A7AFF7500F46528 /* MIKMIDIPrivateUtilities.m in Sources */,
Expand Down
1 change: 1 addition & 0 deletions Source/MIKMIDI.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
// MIDI Device support
#import "MIKMIDIDevice.h"
#import "MIKMIDIDeviceManager.h"
#import "MIKMIDIConnectionManager.h"

#import "MIKMIDIEntity.h"

Expand Down
177 changes: 177 additions & 0 deletions Source/MIKMIDIConnectionManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
//
// MIKMIDIConnectionManager.h
// MIKMIDI
//
// Created by Andrew Madsen on 11/5/15.
// Copyright © 2015 Mixed In Key. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "MIKMIDICompilerCompatibility.h"
#import "MIKMIDISourceEndpoint.h"

@class MIKMIDIDevice;

@protocol MIKMIDIConnectionManagerDelegate;

NS_ASSUME_NONNULL_BEGIN

/**
* MIKMIDIConnectionManager can be used to manage a set of connected devices. It can be configured to automatically
* connect to devices as they are added, and disconnect from them as they are removed. It also supports saving
* the list of connected to NSUserDefaults and restoring them upon relaunch.
*
* The use of MIKMIDIConnectionManager is optional. It is meant to be useful in implementing functionality that
* many MIDI device enabled apps need. However, simple connection to devices or MIDI endpoints can be done with
* MIKMIDIDeviceManager directly, if desired.
*/
@interface MIKMIDIConnectionManager : NSObject

/**
* This method will throw an exception if called. Use -initWithName: instead.
*
* @return nil
*/
- (instancetype)init NS_UNAVAILABLE;

/**
* Initializes an instance of MIKMIDIConnectionManager. The passed in name is used to independently
* store and load the connection manager's configuration using NSUserDefaults. The passed in name
* should be unique across your application, and the same from launch to launch.
*
* @param name The name to give the connection manager.
*
* @return An initialized MIKMIDIConnectionManager instance.
*/
- (instancetype)initWithName:(NSString *)name NS_DESIGNATED_INITIALIZER;

/**
* Connect to the specified device. When MIDI messages are received, the connection manager's event handler
* block will be executed.
*
* @param device An MIKMIDIDevice instance.
* @param error If an error occurs, upon returns contains an NSError object that describes the problem.
* If you are not interested in possible errors, you may pass in NULL.
*
* @return YES if the connection was successful, NO if an error occurred.
*/
- (BOOL)connectToDevice:(MIKMIDIDevice *)device error:(NSError **)error;

/**
* Disconnect from a connected device. No further messages from the specified device will be processed.
*
* Note that you don't need to call this method when a previously-connected device was removed from the system.
* Disconnection in that situation is handled automatically.
*
* @param device An MIKMIDIDevice instance.
*/
- (void)disconnectFromDevice:(MIKMIDIDevice *)device;

/**
* This method can be used to determine if the receiver is connected to a given MIDI device.
*
* @param device An MIKMIDIDevice instance.
*
* @return YES if the receiver is connected to and processing MIDI input from the device, NO otherwise.
*/
- (BOOL)isConnectedToDevice:(MIKMIDIDevice *)device;

/**
* If YES (the default), the connection manager will automatically save its configuration at appropriate
* times. If this property is NO, -saveConfiguration can still be used to manually trigger saving the
* receiver's configuration. Note that -loadConfiguration must always be called manually, e.g. at launch.
*/
@property (nonatomic) BOOL automaticallySavesConfiguration;

/**
* Save the receiver's list of connected devices to disk for later restoration.
*/
- (void)saveConfiguration;

/**
* Load and reconnect to the devices previously saved to disk by a call to -saveConfiguration. For
* this to work, the receiver's name must be the same as it was upon the previous call to -saveConfiguration.
*
* @note: This method will only connect to new devices. It will not disconnect from devices not found in the
* saved configuration.
*/
- (void)loadConfiguration;

/**
* The name of the receiver. Used for configuration save/load.
*/
@property (nonatomic, copy, readonly) NSString *name;

/**
* An MIKMIDIEventHandlerBlock to be called with incoming MIDI messages from any connected device.
*
* If you need to determine which device sent the passed in messages, call source.entity.device on the
* passed in MIKMIDISourceEndpoint argument.
*/
@property (nonatomic, copy, null_resettable) MIKMIDIEventHandlerBlock eventHandler;

/**
* A delegate, used to customize MIKMIDIConnectionManager behavior.
*/
@property (nonatomic, weak) id<MIKMIDIConnectionManagerDelegate>delegate;

/**
* Controls whether the receiver's availableDevices property includes virtual devices (i.e. devices made
* up of automatically paired virtual sources and destinations).
*
* If this property is YES (the default), the connection manager will attempt to automtically related
* associated virtual sources and destinations and create "virtual" MIKMIDIDevice instances for them.
*
* If this property is NO, the connection manager's availableDevices array will _only_ contain non-virtual
* MIKMIDIDevices.
*
* For most applications, this should be left at the default YES, as even many physical MIDI devices present as
* "virtual" devices in software.
*
* @note: The caveat here is that this relies on some heuristics to match up source endpoints with destination endpoints.
* These heuristics are based on the way certain common MIDI devices behave, but may not be universal, and therefore
* may miss, or fail to properly associate endpoints for some devices. If this is a problem for your application,
* you should obtain and connect to virtual sources/endpoints using MIKMIDIDeviceManager directly instead.
*/
@property (nonatomic) BOOL includesVirtualDevices; // Default is YES

/**
* An array of available MIDI devices.
*
* This property is observable using Key Value Observing.
*/
@property (nonatomic, strong, readonly) MIKArrayOf(MIKMIDIDevice *) *availableDevices;

/**
* The set of MIDI devices to which the receiver is connected.
*
* This property is observable using Key Value Observing.
*/
@property (nonatomic, strong, readonly) MIKSetOf(MIKMIDIDevice *) *connectedDevices;

@end

/**
* Protocol containing method(s) to be implemented by delegates of MIKMIDIConnectionManager.
*/
@protocol MIKMIDIConnectionManagerDelegate <NSObject>

@optional

/**
* A connection manager's delegate can implement this method to determine whether or not to automatically connect
* to a newly added MIDI device.
*
* If this method is not implemented or returns NO, the device will be connected to if the most
*
* @param manager An instance of MIKMIDIConnectionManager.
* @param device The newly added MIDI device.
*
* @return YES to connect to device, NO to leave it unconnected.
*/
- (BOOL)connectionManager:(MIKMIDIConnectionManager *)manager shouldConnectToNewlyAddedDevice:(MIKMIDIDevice *)device;

@end

NS_ASSUME_NONNULL_END

Loading

0 comments on commit 8bc1638

Please sign in to comment.