hammerspoon/Pods/MIKMIDI/Source/MIKMIDICommand.h

249 lines
11 KiB
Objective-C

//
// MIKMIDICommand.h
// MIDI Testbed
//
// Created by Andrew Madsen on 3/7/13.
// Copyright (c) 2013 Mixed In Key. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreMIDI/CoreMIDI.h>
#import "MIKMIDICompilerCompatibility.h"
/**
* Types of MIDI messages. These values correspond directly to the MIDI command type values
* found in MIDI message data.
*
* @note Not all of these MIDI message types are currently explicitly supported by MIKMIDI.
*/
typedef NS_ENUM(NSUInteger, MIKMIDICommandType) {
/** Note off command. */
MIKMIDICommandTypeNoteOff = 0x8f,
/** Note on command. */
MIKMIDICommandTypeNoteOn = 0x9f,
/** Polyphonic key pressure command. */
MIKMIDICommandTypePolyphonicKeyPressure = 0xaf,
/** Control change command. This is the most common command sent by MIDI controllers. */
MIKMIDICommandTypeControlChange = 0xbf,
/** Program change command. */
MIKMIDICommandTypeProgramChange = 0xcf,
/** Channel pressure command. */
MIKMIDICommandTypeChannelPressure = 0xdf,
/** Pitch wheel change command. */
MIKMIDICommandTypePitchWheelChange = 0xef,
/** System message command. */
MIKMIDICommandTypeSystemMessage = 0xff,
/** System message command. */
MIKMIDICommandTypeSystemExclusive = 0xf0,
/** System exclusive (SysEx) command. */
MIKMIDICommandTypeSystemTimecodeQuarterFrame = 0xf1,
/** System song position pointer command. */
MIKMIDICommandTypeSystemSongPositionPointer = 0xf2,
/** System song select command. */
MIKMIDICommandTypeSystemSongSelect = 0xf3,
/** System tune request command. */
MIKMIDICommandTypeSystemTuneRequest = 0xf6,
/** System timing clock command. */
MIKMIDICommandTypeSystemTimingClock = 0xf8,
/** System timing clock command. */
MIKMIDICommandTypeSystemStartSequence = 0xfa,
/** System start sequence command. */
MIKMIDICommandTypeSystemContinueSequence = 0xfb,
/** System continue sequence command. */
MIKMIDICommandTypeSystemStopSequence = 0xfc,
/** System keep alive message. */
MIKMIDICommandTypeSystemKeepAlive = 0xfe,
};
@class MIKMIDIMappingItem;
NS_ASSUME_NONNULL_BEGIN
/**
* In MIKMIDI, MIDI messages are objects. Specifically, they are instances of MIKMIDICommand or one of its
* subclasses. MIKMIDICommand's subclasses each represent a specific type of MIDI message, for example,
* control change command messages will be instances of MIKMIDIControlChangeCommand.
* MIKMIDICommand includes properties for getting information and data common to all MIDI messages.
* Its subclasses implement additional method and properties specific to messages of their associated type.
*
* MIKMIDICommand is also available in mutable variants, most useful for creating commands to be sent out
* by your application.
*
* To create a new command, typically, you should use +commandForCommandType:.
*
* Subclass MIKMIDICommand
* -----------------------
*
* Support for the various MIDI message types is provided by type-specific subclasses of MIKMIDICommand.
* For example, Control Change messages are represented using MIKMIDIControlChangeCommand. MIKMIDI
* includes a limited number of MIKMIDICommand subclasses to support the most common MIDI message types.
* To support a new command type, you should create a new subclass of MIKMIDICommand (and please consider
* contributing it to the main MIKMIDI repository!). If you implement this subclass according to the rules
* explained below, it will automatically be used to represent incoming MIDI commands matching its MIDI command type.
*
* To successfully subclass MIKMIDICommand, you *must* override at least the following methods:
*
* - `+supportedMIDICommandTypes:` - Return an array of one or more MIKMIDICommandTypes that your subclass supports.
* - `+immutableCounterPartClass` - Return the subclass itself (eg. `return [MIKMIDINewTypeCommand class];`)
* - `+mutableCounterPartClass` - Return the mutable counterpart class (eg. `return [MIKMIDIMutableNewTypeCommand class;]`)
*
* Optionally, override `-additionalCommandDescription` to provide an additional, type-specific description string.
*
* You must also implement `+load` and call `[MIKMIDICommand registerSubclass:self]` to register your subclass with
* the MIKMIDICommand machinery.
*
* When creating a subclass of MIKMIDICommand, you should also create a mutable variant which is itself
* a subclass of your type-specific MIKMIDICommand subclass. The mutable subclass should override `+isMutable`
* and return YES.
*
* If your subclass adds additional properties, beyond those supported by MIKMIDICommand itself, those properties
* should only be settable on instances of the mutable variant class. The preferred way to accomplish this is to
* implement the setters on the *immutable*, base subclass. In their implementations, check to see if self is
* mutable, and if not, raise an exception. Use the following line of code:
*
* if (![[self class] isMutable]) return MIKMIDI_RAISE_MUTATION_ATTEMPT_EXCEPTION;
*
* For a straightforward example of a MIKMIDICommand subclass, see MIKMIDINoteOnCommand.
*
*/
@interface MIKMIDICommand : NSObject <NSCopying>
/**
* Convenience method for creating a new MIKMIDICommand instance from a MIDIPacket as received or created
* using CoreMIDI functions. For command types for which there is a specific MIKMIDICommand subclass,
* an instance of the appropriate subclass will be returned.
*
* @note This method is used by MIKMIDI's internal machinery, and its use by MIKMIDI
* clients, while not disallowed, is not typical. Normally, +commandForCommandType: should be used.
*
* @param packet A pointer to an MIDIPacket struct.
*
* @return For supported command types, an initialized MIKMIDICommand subclass. Otherwise, an instance
* of MIKMIDICommand itself. nil if there is an error.
*
* @see +commandForCommandType:
*/
+ (instancetype)commandWithMIDIPacket:(MIDIPacket * _Nullable)packet;
/**
* Convenience method for creating a new MIKMIDICommand instance from a MIDIPacket as received or created
* using CoreMIDI functions. For command types for which there is a specific MIKMIDICommand subclass,
* an instance of the appropriate subclass will be returned.
*
* @note This method is used by MIKMIDI's internal machinery, and its use by MIKMIDI
* clients, while not disallowed, is not typical. Normally, +commandForCommandType: should be used.
*
* @param packet A pointer to an MIDIPacket struct.
*
* @return An NSArray containing initialized MIKMIDICommand subclass instances for each MIDI
* message of a supported command type. For unsupported command types, an instance of
* MIKMIDICommand itself will be used. Returns nil if there is an error.
*
* @see +commandForCommandType:
*/
+ (MIKArrayOf(MIKMIDICommand *) *)commandsWithMIDIPacket:(MIDIPacket *)packet;
/**
* Convenience method for creating a new MIKMIDICommand. For command types for which there is a
* specific MIKMIDICommand subclass, an instance of the appropriate subclass will be returned.
*
* @param commandType The type of MIDI command to create. See MIKMIDICommandType for a list
* of possible values.
*
* @return For supported command types, an initialized MIKMIDICommand subclass. Otherwise, an instance
* of MIKMIDICommand itself. nil if there is an error.
*/
+ (__kindof instancetype)commandForCommandType:(MIKMIDICommandType)commandType; // Most useful for mutable commands
/**
* Returns a boolean value that indicates whether the receiver is equal to another command.
* Compares command type, timestamp, and raw data to determine if the two commands are equal.
*
* @param command The command with which to compare the receiver.
* @return YES if command is equivalent to the receiver, otherwise NO.
*/
- (BOOL)isEqualToCommand:(MIKMIDICommand *)command;
/**
* The time at which the MIDI message was received. Will be set for commands received from a connected MIDI source. For commands
* to be sent (ie. created by the MIKMIDI-using application), this must be set manually.
*/
@property (nonatomic, strong, readonly) NSDate *timestamp;
/**
* The receiver's command type. See MIKMIDICommandType for a list of possible values.
*/
@property (nonatomic, readonly) MIKMIDICommandType commandType;
/**
* The MIDI status byte. The exact meaning of the contents
* of this byte differ for different command types. See
* http://www.midi.org/techspecs/midimessages.php for a information
* about the contents of this value.
*/
@property (nonatomic, readonly) UInt8 statusByte;
/**
* The first byte of the MIDI data (after the command type).
*/
@property (nonatomic, readonly) UInt8 dataByte1;
/**
* The second byte of the MIDI data (after the command type).
*/
@property (nonatomic, readonly) UInt8 dataByte2;
/**
* The timestamp for the receiver, expressed as a host clock time. This is the timestamp
* used by CoreMIDI. Usually the timestamp property, which returns an NSDate, will be more useful.
*
* @see -timestamp
*/
@property (nonatomic, readonly) MIDITimeStamp midiTimestamp;
/**
* The raw data that makes up the receiver.
*/
@property (nonatomic, copy, readonly, null_resettable) NSData *data;
/**
* Optional mapping item used to route the command. This must be set by client code that handles
* receiving MIDI commands. Allows responders to understand how a command was mapped, especially
* useful to determine interaction type so that responders can interpret the command correctly.
*/
@property (nonatomic, strong, nullable) MIKMIDIMappingItem *mappingItem;
@end
/**
* Mutable subclass of MIKMIDICommand. All MIKMIDICommand subclasses have mutable variants.
*/
@interface MIKMutableMIDICommand : MIKMIDICommand
@property (nonatomic, strong, readwrite) NSDate *timestamp;
@property (nonatomic, readwrite) MIKMIDICommandType commandType;
@property (nonatomic, readwrite) UInt8 dataByte1;
@property (nonatomic, readwrite) UInt8 dataByte2;
@property (nonatomic, readwrite) MIDITimeStamp midiTimestamp;
@property (nonatomic, copy, readwrite) NSData *data;
@end
/**
* Allocates and returns (by reference) a CoreMIDI MIDIPacketList created from an array of MIKMIDICommand instances.
* The created MIDIPacketList will be sized according to the number of commands and their contents. Ownership is
* transfered to the caller which becomes responsible for freeing the allocated memory.
* Used by MIKMIDI when sending commands. Typically, this is not needed by clients of MIKMIDI.
*
* @param outPacketList A pointer to a pointer to a MIDIPacketList structure which will point to the created MIDIPacketList
* upon success.
* @param commands An array of MIKMIDICommand instances.
*
* @return YES if creating the packet list was successful, NO if an error occurred.
*/
BOOL MIKCreateMIDIPacketListFromCommands(MIDIPacketList * _Nonnull * _Nonnull outPacketList, MIKArrayOf(MIKMIDICommand *) *commands);
NS_ASSUME_NONNULL_END