-
Notifications
You must be signed in to change notification settings - Fork 595
/
Copy pathMIKMIDIEndpointSynthesizer.m
194 lines (159 loc) · 7.33 KB
/
MIKMIDIEndpointSynthesizer.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
//
// MIKMIDIEndpointSynthesizer.m
// MIKMIDI
//
// Created by Andrew Madsen on 5/27/14.
// Copyright (c) 2014 Mixed In Key. All rights reserved.
//
#import "MIKMIDIEndpointSynthesizer.h"
#import <AudioToolbox/AudioToolbox.h>
#import "MIKMIDI.h"
#import "MIKMIDIClientDestinationEndpoint.h"
#import "MIKMIDIPrivate.h"
#if !__has_feature(objc_arc)
#error MIKMIDIEndpointSynthesizer.m must be compiled with ARC. Either turn on ARC for the project or set the -fobjc-arc flag for MIKMIDIEndpointSynthesizer.m in the Build Phases for this target
#endif
@interface MIKMIDIEndpointSynthesizer ()
@property (nonatomic, strong, readwrite) MIKMIDIEndpoint *endpoint;
@property (nonatomic, strong) id connectionToken;
@end
@implementation MIKMIDIEndpointSynthesizer
+ (instancetype)playerWithMIDISource:(MIKMIDISourceEndpoint *)source error:(NSError **)error
{
return [[self alloc] initWithMIDISource:source error:error];
}
+ (instancetype)playerWithMIDISource:(MIKMIDISourceEndpoint *)source
componentDescription:(AudioComponentDescription)componentDescription
error:(NSError **)error
{
return [[self alloc] initWithMIDISource:source componentDescription:componentDescription error:error];
}
- (instancetype)initWithMIDISource:(MIKMIDISourceEndpoint *)source error:(NSError **)error
{
return [self initWithMIDISource:source componentDescription:[[self class] appleSynthComponentDescription] error:error];
}
- (instancetype)initWithMIDISource:(MIKMIDISourceEndpoint *)source
componentDescription:(AudioComponentDescription)componentDescription
error:(NSError **)error;
{
self = [super initWithAudioUnitDescription:componentDescription error:error];
if (self) {
if (source) {
NSError *error = nil;
if (![self connectToMIDISource:source error:&error]) {
NSLog(@"Unable to connect to MIDI source %@: %@", source, error);
return nil;
}
_endpoint = source;
}
}
return self;
}
+ (instancetype)synthesizerWithClientDestinationEndpoint:(MIKMIDIClientDestinationEndpoint *)destination
error:(NSError **)error
{
return [self synthesizerWithClientDestinationEndpoint:destination
componentDescription:[self appleSynthComponentDescription]
error:error];
}
+ (instancetype)synthesizerWithClientDestinationEndpoint:(MIKMIDIClientDestinationEndpoint *)destination
componentDescription:(AudioComponentDescription)componentDescription
error:(NSError **)error
{
return [[self alloc] initWithClientDestinationEndpoint:destination
componentDescription:componentDescription
error:error];
}
- (instancetype)initWithClientDestinationEndpoint:(MIKMIDIClientDestinationEndpoint *)destination
error:(NSError **)error
{
return [self initWithClientDestinationEndpoint:destination
componentDescription:[[self class] appleSynthComponentDescription]
error:error];
}
- (instancetype)initWithClientDestinationEndpoint:(MIKMIDIClientDestinationEndpoint *)destination
componentDescription:(AudioComponentDescription)componentDescription
error:(NSError **)error
{
if (!destination) {
[NSException raise:NSInvalidArgumentException format:@"%s requires a non-nil destination endpoint argument.", __PRETTY_FUNCTION__];
return nil;
}
self = [super initWithAudioUnitDescription:componentDescription error:error];
if (self) {
__weak MIKMIDIEndpointSynthesizer *weakSelf = self;
destination.receivedMessagesHandler = ^(MIKMIDIClientDestinationEndpoint *destination, NSArray *commands){
__strong MIKMIDIEndpointSynthesizer *strongSelf = weakSelf;
[strongSelf handleMIDIMessages:commands];
};
_endpoint = destination;
}
return self;
}
- (void)dealloc
{
if ([_endpoint isKindOfClass:[MIKMIDISourceEndpoint class]]) {
[[MIKMIDIDeviceManager sharedDeviceManager] disconnectConnectionForToken:self.connectionToken];
}
// Don't need to do anything for a destination endpoint. __weak reference in the messages handler will automatically nil out.
}
#pragma mark - Private
- (BOOL)connectToMIDISource:(MIKMIDISourceEndpoint *)source error:(NSError **)error
{
error = error ? error : &(NSError *__autoreleasing){ nil };
__weak MIKMIDIEndpointSynthesizer *weakSelf = self;
MIKMIDIDeviceManager *deviceManager = [MIKMIDIDeviceManager sharedDeviceManager];
id connectionToken = [deviceManager connectInput:source error:error eventHandler:^(MIKMIDISourceEndpoint *source, NSArray *commands) {
__strong MIKMIDIEndpointSynthesizer *strongSelf = weakSelf;
[strongSelf handleMIDIMessages:commands];
}];
if (!connectionToken) return NO;
self.endpoint = source;
self.connectionToken = connectionToken;
return YES;
}
#pragma mark - Deprecated
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-implementations"
+ (instancetype)playerWithMIDISource:(MIKMIDISourceEndpoint *)source
{
SHOW_STANDARD_DEPRECATION_WARNING;
return [self playerWithMIDISource:source error:NULL];
}
+ (instancetype)playerWithMIDISource:(MIKMIDISourceEndpoint *)source componentDescription:(AudioComponentDescription)componentDescription
{
SHOW_STANDARD_DEPRECATION_WARNING;
return [self playerWithMIDISource:source componentDescription:componentDescription error:NULL];
}
- (instancetype)initWithMIDISource:(MIKMIDISourceEndpoint *)source
{
SHOW_STANDARD_DEPRECATION_WARNING;
return [self initWithMIDISource:source error:NULL];
}
- (instancetype)initWithMIDISource:(MIKMIDISourceEndpoint *)source componentDescription:(AudioComponentDescription)componentDescription;
{
SHOW_STANDARD_DEPRECATION_WARNING;
return [self initWithMIDISource:source componentDescription:componentDescription error:NULL];
}
+ (instancetype)synthesizerWithClientDestinationEndpoint:(MIKMIDIClientDestinationEndpoint *)destination
{
SHOW_STANDARD_DEPRECATION_WARNING;
return [self synthesizerWithClientDestinationEndpoint:destination error:NULL];
}
+ (instancetype)synthesizerWithClientDestinationEndpoint:(MIKMIDIClientDestinationEndpoint *)destination componentDescription:(AudioComponentDescription)componentDescription
{
SHOW_STANDARD_DEPRECATION_WARNING;
return [self synthesizerWithClientDestinationEndpoint:destination componentDescription:componentDescription error:NULL];
}
- (instancetype)initWithClientDestinationEndpoint:(MIKMIDIClientDestinationEndpoint *)destination
{
SHOW_STANDARD_DEPRECATION_WARNING;
return [self initWithClientDestinationEndpoint:destination error:NULL];
}
- (instancetype)initWithClientDestinationEndpoint:(MIKMIDIClientDestinationEndpoint *)destination componentDescription:(AudioComponentDescription)componentDescription
{
SHOW_STANDARD_DEPRECATION_WARNING;
return [self initWithClientDestinationEndpoint:destination componentDescription:componentDescription error:NULL];
}
#pragma clang diagnostic pop
@end