diff --git a/Framework/MIKMIDI Tests/MIKMIDICommandTests.m b/Framework/MIKMIDI Tests/MIKMIDICommandTests.m new file mode 100644 index 00000000..0a293054 --- /dev/null +++ b/Framework/MIKMIDI Tests/MIKMIDICommandTests.m @@ -0,0 +1,45 @@ +// +// MIKMIDICommandTests.m +// MIKMIDI +// +// Created by Andrew Madsen on 11/12/15. +// Copyright © 2015 Mixed In Key. All rights reserved. +// + +#import +#import + +@interface MIKMIDICommandTests : XCTestCase + +@end + +@implementation MIKMIDICommandTests + +- (void)testPolyphonicKeyPressureCommand +{ + Class immutableClass = [MIKMIDIPolyphonicKeyPressureCommand class]; + Class mutableClass = [MIKMutableMIDIPolyphonicKeyPressureCommand class]; + + MIKMIDIPolyphonicKeyPressureCommand *command = [[immutableClass alloc] init]; + XCTAssert([command isMemberOfClass:[immutableClass class]], @"[[MIKMIDIPolyphonicKeyPressureCommand alloc] init] did not return an MIKMIDIPolyphonicKeyPressureCommand instance."); + XCTAssert([[MIKMIDICommand commandForCommandType:MIKMIDICommandTypePolyphonicKeyPressure] isMemberOfClass:[immutableClass class]], @"[MIKMIDICommand commandForCommandType:MIKMIDICommandTypePolyphonicKeyPressure] did not return an MIKMIDIPolyphonicKeyPressureCommand instance."); + XCTAssert([[command copy] isMemberOfClass:[immutableClass class]], @"[MIKMIDIPolyphonicKeyPressureCommand copy] did not return an MIKMIDIPolyphonicKeyPressureCommand instance."); + XCTAssertEqual(command.commandType, MIKMIDICommandTypePolyphonicKeyPressure, @"[[MIKMIDIPolyphonicKeyPressureCommand alloc] init] produced a command instance with the wrong command type."); + + MIKMutableMIDIPolyphonicKeyPressureCommand *mutableCommand = [command mutableCopy]; + XCTAssert([mutableCommand isMemberOfClass:[mutableClass class]], @"-[MIKMIDIPolyphonicKeyPressureCommand mutableCopy] did not return an mutableClass instance."); + XCTAssert([[mutableCommand copy] isMemberOfClass:[immutableClass class]], @"-[mutableClass mutableCopy] did not return an MIKMIDIPolyphonicKeyPressureCommand instance."); + + XCTAssertThrows([(MIKMutableMIDIPolyphonicKeyPressureCommand *)command setNote:64], @"-[MIKMIDIPolyphonicKeyPressureCommand setNote:] was allowed on immutable instance."); + XCTAssertThrows([(MIKMutableMIDIPolyphonicKeyPressureCommand *)command setPressure:64], @"-[MIKMIDIPolyphonicKeyPressureCommand setPressure:] was allowed on immutable instance."); + + XCTAssertNoThrow([mutableCommand setNote:64], @"-[MIKMIDIPolyphonicKeyPressureCommand setNote:] was not allowed on mutable instance."); + XCTAssertNoThrow([mutableCommand setPressure:64], @"-[MIKMIDIPolyphonicKeyPressureCommand setNote:] was not allowed on mutable instance."); + + mutableCommand.note = 42; + XCTAssertEqual(mutableCommand.note, 42, @"Setting the note on a MIKMutableMIDIPolyphonicKeyPressureCommand instance failed."); + mutableCommand.pressure = 27; + XCTAssertEqual(mutableCommand.pressure, 27, @"Setting the pressure on a MIKMutableMIDIPolyphonicKeyPressureCommand instance failed."); +} + +@end diff --git a/Framework/MIKMIDI.xcodeproj/project.pbxproj b/Framework/MIKMIDI.xcodeproj/project.pbxproj index 53772c2a..c528c071 100644 --- a/Framework/MIKMIDI.xcodeproj/project.pbxproj +++ b/Framework/MIKMIDI.xcodeproj/project.pbxproj @@ -63,6 +63,11 @@ 9D0895F11B0D29F200A5872E /* MIKMIDIMappingItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D0895ED1B0D29F200A5872E /* MIKMIDIMappingItem.m */; }; 9D0895F31B0D2A4700A5872E /* MIKMIDIMappableResponder.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D0895F21B0D2A4700A5872E /* MIKMIDIMappableResponder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D0895F41B0D2A4700A5872E /* MIKMIDIMappableResponder.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D0895F21B0D2A4700A5872E /* MIKMIDIMappableResponder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9D1D9C201BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D1D9C1E1BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9D1D9C211BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D1D9C1E1BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9D1D9C221BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D1D9C1F1BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.m */; }; + 9D1D9C231BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D1D9C1F1BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.m */; }; + 9D1D9C251BF542BB001377F7 /* MIKMIDICommandTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D1D9C241BF542BB001377F7 /* MIKMIDICommandTests.m */; }; 9D2ED25F1AFBD062000325CC /* MIKMIDIResponderChainTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D2ED25E1AFBD062000325CC /* MIKMIDIResponderChainTests.m */; }; 9D3781561AA407A7007A61BE /* MIKMIDIResponder.h in Headers */ = {isa = PBXBuildFile; fileRef = 9D74EF5817A713A100BEE89F /* MIKMIDIResponder.h */; settings = {ATTRIBUTES = (Public, ); }; }; 9D4DF13F1AAB57430065F004 /* MIKMIDI_Tests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9D4DF13E1AAB57430065F004 /* MIKMIDI_Tests.m */; }; @@ -354,6 +359,9 @@ 9D0895EC1B0D29F200A5872E /* MIKMIDIMappingItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIKMIDIMappingItem.h; sourceTree = ""; }; 9D0895ED1B0D29F200A5872E /* MIKMIDIMappingItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIKMIDIMappingItem.m; sourceTree = ""; }; 9D0895F21B0D2A4700A5872E /* MIKMIDIMappableResponder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIKMIDIMappableResponder.h; sourceTree = ""; }; + 9D1D9C1E1BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIKMIDIPolyphonicKeyPressureCommand.h; sourceTree = ""; }; + 9D1D9C1F1BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIKMIDIPolyphonicKeyPressureCommand.m; sourceTree = ""; }; + 9D1D9C241BF542BB001377F7 /* MIKMIDICommandTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIKMIDICommandTests.m; sourceTree = ""; }; 9D2ED25E1AFBD062000325CC /* MIKMIDIResponderChainTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIKMIDIResponderChainTests.m; sourceTree = ""; }; 9D4DF13A1AAB57430065F004 /* MIKMIDI Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "MIKMIDI Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 9D4DF13D1AAB57430065F004 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -517,6 +525,7 @@ isa = PBXGroup; children = ( 9D4DF13E1AAB57430065F004 /* MIKMIDI_Tests.m */, + 9D1D9C241BF542BB001377F7 /* MIKMIDICommandTests.m */, 9D4DF14C1AAB57800065F004 /* MIKMIDISequenceTests.m */, 9D4DF1531AAB60490065F004 /* MIKMIDITrackTests.m */, 9DCDDB591AB3514100F8347E /* MIKMIDISequencerTests.m */, @@ -810,6 +819,8 @@ 9D74EF3717A713A100BEE89F /* MIKMIDIControlChangeCommand.m */, 9DED4E341AA90CA700DA8356 /* MIKMIDIPitchBendChangeCommand.h */, 9DED4E351AA90CA700DA8356 /* MIKMIDIPitchBendChangeCommand.m */, + 9D1D9C1E1BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.h */, + 9D1D9C1F1BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.m */, 9D877DF91A670261001BA997 /* MIKMIDIProgramChangeCommand.h */, 9D877DFA1A670261001BA997 /* MIKMIDIProgramChangeCommand.m */, 9D74EF4E17A713A100BEE89F /* MIKMIDINoteOnCommand.h */, @@ -917,6 +928,7 @@ 9DF99E791831841A004EE5F4 /* MIKMIDICommandThrottler.h in Headers */, 9D74EF9017A713A100BEE89F /* MIKMIDISystemMessageCommand.h in Headers */, 83BC19BB1A23CD0D004F384F /* MIKMIDIMetronome.h in Headers */, + 9D1D9C201BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.h in Headers */, 9D74EF9217A713A100BEE89F /* MIKMIDIUtilities.h in Headers */, 83C3716719D607010017186B /* MIKMIDIClientDestinationEndpoint.h in Headers */, 9DAE7D8E19357AAF00B25DD7 /* MIKMIDIEndpointSynthesizer.h in Headers */, @@ -984,6 +996,7 @@ 9DAF8B791A7B00A700F46528 /* MIKMIDIMetaTrackSequenceNameEvent.h in Headers */, 9DAF8B6F1A7B00A700F46528 /* MIKMIDIMetaCopyrightEvent.h in Headers */, 9DAF8B531A7B005C00F46528 /* MIKMIDIErrors.h in Headers */, + 9D1D9C211BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.h in Headers */, 9D8495231AA7773500C52475 /* MIKMIDIPolyphonicKeyPressureEvent.h in Headers */, 9DAF8B7F1A7B00B100F46528 /* MIKMIDISequencer.h in Headers */, 9DBEBD681AAA303700E59734 /* MIKMIDIChannelPressureEvent.h in Headers */, @@ -1130,6 +1143,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 9D1D9C251BF542BB001377F7 /* MIKMIDICommandTests.m in Sources */, 9DCDDB5A1AB3514100F8347E /* MIKMIDISequencerTests.m in Sources */, 9D4DF13F1AAB57430065F004 /* MIKMIDI_Tests.m in Sources */, 9D2ED25F1AFBD062000325CC /* MIKMIDIResponderChainTests.m in Sources */, @@ -1188,6 +1202,7 @@ 9D74EF8717A713A100BEE89F /* MIKMIDIOutputPort.m in Sources */, 839D935219C3A2F5007589C3 /* MIKMIDIMetaCuePointEvent.m in Sources */, 9D74EF8917A713A100BEE89F /* MIKMIDIPort.m in Sources */, + 9D1D9C221BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.m in Sources */, 839D933619C3A2C9007589C3 /* MIKMIDIEventIterator.m in Sources */, 839D935A19C3A2F5007589C3 /* MIKMIDIMetaLyricEvent.m in Sources */, 9DB366F81A964D4A001D1CF3 /* MIKMIDISynthesizerInstrument.m in Sources */, @@ -1256,6 +1271,7 @@ 9DAF8B441A7AFF6B00F46528 /* MIKMIDIMetaTextEvent.m in Sources */, 9DBEBD6A1AAA303700E59734 /* MIKMIDIChannelPressureEvent.m in Sources */, 9DAF8B451A7AFF6B00F46528 /* MIKMIDIMetaTimeSignatureEvent.m in Sources */, + 9D1D9C231BF53C88001377F7 /* MIKMIDIPolyphonicKeyPressureCommand.m in Sources */, 9DAF8B461A7AFF6B00F46528 /* MIKMIDIMetaTrackSequenceNameEvent.m in Sources */, 9DAF8B471A7AFF6B00F46528 /* MIKMIDINoteEvent.m in Sources */, 9DAF8B481A7AFF6B00F46528 /* MIKMIDIPlayer.m in Sources */, diff --git a/Source/MIKMIDI.h b/Source/MIKMIDI.h index 5a77cefc..37d7238e 100644 --- a/Source/MIKMIDI.h +++ b/Source/MIKMIDI.h @@ -37,6 +37,7 @@ #import "MIKMIDIPitchBendChangeCommand.h" #import "MIKMIDINoteOnCommand.h" #import "MIKMIDINoteOffCommand.h" +#import "MIKMIDIPolyphonicKeyPressureCommand.h" #import "MIKMIDISystemExclusiveCommand.h" #import "MIKMIDISystemMessageCommand.h" diff --git a/Source/MIKMIDIChannelVoiceCommand.m b/Source/MIKMIDIChannelVoiceCommand.m index b37fdcc1..055fabb2 100644 --- a/Source/MIKMIDIChannelVoiceCommand.m +++ b/Source/MIKMIDIChannelVoiceCommand.m @@ -27,8 +27,7 @@ @implementation MIKMIDIChannelVoiceCommand + (void)load { [super load]; [MIKMIDICommand registerSubclass:self]; } + (NSArray *)supportedMIDICommandTypes { - return @[@(MIKMIDICommandTypePolyphonicKeyPressure), - @(MIKMIDICommandTypeChannelPressure)]; + return @[@(MIKMIDICommandTypeChannelPressure)]; } + (Class)immutableCounterpartClass; { return [MIKMIDIChannelVoiceCommand class]; } diff --git a/Source/MIKMIDIPolyphonicKeyPressureCommand.h b/Source/MIKMIDIPolyphonicKeyPressureCommand.h new file mode 100644 index 00000000..8e27ce53 --- /dev/null +++ b/Source/MIKMIDIPolyphonicKeyPressureCommand.h @@ -0,0 +1,41 @@ +// +// MIKMIDIPolyphonicKeyPressureCommand.h +// MIKMIDI +// +// Created by Andrew Madsen on 11/12/15. +// Copyright © 2015 Mixed In Key. All rights reserved. +// + +#import + +/** + * A MIDI polyphonic key pressure message. This message is most often sent by pressing + * down on the key after it "bottoms out". + */ +@interface MIKMIDIPolyphonicKeyPressureCommand : MIKMIDIChannelVoiceCommand + +/// The note number for the message. In the range 0-127. +@property (nonatomic, readonly) NSUInteger note; + +/// Key pressure of the polyphonic key pressure message. In the range 0-127. +@property (nonatomic, readonly) NSUInteger pressure; + +@end + +/** + * The mutable counterpart to MIKMIDIPolyphonicKeyPressureCommand. + */ +@interface MIKMutableMIDIPolyphonicKeyPressureCommand : MIKMIDIPolyphonicKeyPressureCommand + +/// The note number for the message. In the range 0-127. +@property (nonatomic, readwrite) NSUInteger note; + +/// Key pressure of the polyphonic key pressure message. In the range 0-127. +@property (nonatomic, readwrite) NSUInteger pressure; + +@property (nonatomic, strong, readwrite) NSDate *timestamp; +@property (nonatomic, readwrite) MIDITimeStamp midiTimestamp; +@property (nonatomic, readwrite) UInt8 channel; +@property (nonatomic, readwrite) NSUInteger value; + +@end diff --git a/Source/MIKMIDIPolyphonicKeyPressureCommand.m b/Source/MIKMIDIPolyphonicKeyPressureCommand.m new file mode 100644 index 00000000..619233bd --- /dev/null +++ b/Source/MIKMIDIPolyphonicKeyPressureCommand.m @@ -0,0 +1,67 @@ +// +// MIKMIDIPolyphonicKeyPressureCommand.m +// MIKMIDI +// +// Created by Andrew Madsen on 11/12/15. +// Copyright © 2015 Mixed In Key. All rights reserved. +// + +#import "MIKMIDIPolyphonicKeyPressureCommand.h" +#import "MIKMIDIChannelVoiceCommand_SubclassMethods.h" + +@interface MIKMIDIPolyphonicKeyPressureCommand () + +@property (nonatomic, readwrite) NSUInteger note; +@property (nonatomic, readwrite) NSUInteger pressure; + +@end + +@implementation MIKMIDIPolyphonicKeyPressureCommand + ++ (void)load { [super load]; [MIKMIDICommand registerSubclass:self]; } ++ (NSArray *)supportedMIDICommandTypes { return @[@(MIKMIDICommandTypePolyphonicKeyPressure)]; } + ++ (Class)immutableCounterpartClass; { return [MIKMIDIPolyphonicKeyPressureCommand class]; } ++ (Class)mutableCounterpartClass; { return [MIKMutableMIDIPolyphonicKeyPressureCommand class]; } + ++ (BOOL)isMutable { return NO; } + +#pragma mark - Properties + +- (NSUInteger)note { return self.dataByte1; } +- (void)setNote:(NSUInteger)value +{ + if (![[self class] isMutable]) return MIKMIDI_RAISE_MUTATION_ATTEMPT_EXCEPTION; + self.dataByte1 = (UInt8)value; +} + +- (NSUInteger)pressure { return self.value; } +- (void)setPressure:(NSUInteger)value +{ + if (![[self class] isMutable]) return MIKMIDI_RAISE_MUTATION_ATTEMPT_EXCEPTION; + self.value = value; +} + +@end + +#pragma mark - + +@implementation MIKMutableMIDIPolyphonicKeyPressureCommand + ++ (BOOL)isMutable { return YES; } + +#pragma mark - Properties + +@dynamic note; +@dynamic pressure; + +// MIKMIDICommand already implements these. This keeps the compiler happy. +@dynamic channel; +@dynamic value; +@dynamic timestamp; +@dynamic dataByte1; +@dynamic dataByte2; +@dynamic midiTimestamp; +@dynamic data; + +@end