11#import "IPlugAUPlayer.h"
15#if !__has_feature(objc_arc)
16#error This file must be compiled with Arc. Use -fobjc-arc flag
28@implementation IPlugAUPlayer
30 AVAudioEngine* engine;
31 AVAudioUnit* avAudioUnit;
35- (instancetype) initWithComponentType: (UInt32) unitComponentType
41 engine = [[AVAudioEngine alloc] init];
42 componentType = unitComponentType;
48- (void) loadAudioUnitWithComponentDescription:(AudioComponentDescription)desc
49 completion:(
void (^) (
void))completionBlock
51 [AVAudioUnit instantiateWithComponentDescription:desc options:0
52 completionHandler:^(AVAudioUnit* __nullable audioUnit, NSError* __nullable error) {
53 [
self onAudioUnitInstantiated:audioUnit error:error completion:completionBlock];
57- (void) onAudioUnitInstantiated:(AVAudioUnit* __nullable) audioUnit error:(NSError* __nullable) error completion:(
void (^) (
void))completionBlock
62 avAudioUnit = audioUnit;
64 [engine attachNode:avAudioUnit];
66 self.currentAudioUnit = avAudioUnit.AUAudioUnit;
71 [
self printEngineInfo];
72 [
self printSessionInfo];
75 [
self makeEngineConnections];
76 [
self addNotifications];
78 AVAudioSession* session = [AVAudioSession sharedInstance];
80 if (![session setActive:TRUE error: &error])
82 NSLog(
@"Error setting session active: %@", [error localizedDescription]);
85 if (![engine startAndReturnError: &error])
87 NSLog(
@"engine failed to start: %@", error);
95 [[NSNotificationCenter defaultCenter] removeObserver: self];
98- (void) restartAudioEngine
102 NSError *error = nil;
104 if (![engine startAndReturnError:&error])
106 NSLog(
@"Error re-starting audio engine: %@", error);
110 [
self printSessionInfo];
116 AVAudioSession* session = [AVAudioSession sharedInstance];
117 NSError* error = nil;
119 AVAudioSessionCategoryOptions options = AVAudioSessionCategoryOptionDefaultToSpeaker | AVAudioSessionCategoryOptionAllowBluetooth;
120 [session setCategory: isInstrument() ? AVAudioSessionCategoryPlayback
121 : AVAudioSessionCategoryPlayAndRecord
122 withOptions:options error: &error];
126 NSLog(
@"Error setting category: %@", error);
129 [session setPreferredSampleRate:iplug::DEFAULT_SAMPLE_RATE error: &error];
133 NSLog(
@"Error setting samplerate: %@", error);
136 [session setPreferredIOBufferDuration:128.0/iplug::DEFAULT_SAMPLE_RATE error: &error];
140 NSLog(
@"Error setting io buffer duration: %@", error);
144- (void) makeEngineConnections
148 AVAudioNode* inputNode = [engine inputNode];
149 AVAudioFormat* inputNodeFormat = [inputNode inputFormatForBus:0];
153 [engine connect:inputNode to:avAudioUnit format: inputNodeFormat];
155 @catch (NSException *exception) {
156 NSLog(
@"NSException when trying to connect input node: %@, Reason: %@", exception.name, exception.reason);
161 auto numOutputBuses = [avAudioUnit numberOfOutputs];
162 AVAudioMixerNode* mainMixer = [engine mainMixerNode];
163 AVAudioFormat* pluginOutputFormat = [avAudioUnit outputFormatForBus:0];
164 AVAudioNode* outputNode = [engine outputNode];
166 if (numOutputBuses > 1)
169 for (
int busIdx=0; busIdx<numOutputBuses; busIdx++)
171 [engine connect:avAudioUnit to:mainMixer fromBus: busIdx toBus:[mainMixer nextAvailableInputBus] format: pluginOutputFormat];
176 [engine connect:avAudioUnit to:outputNode format: pluginOutputFormat];
180- (void) printEngineInfo
184 AVAudioFormat* inputNodeFormat = [[engine inputNode] inputFormatForBus:0];
185 AVAudioFormat* pluginInputFormat = [avAudioUnit inputFormatForBus:0];
186 NSLog(
@"Input Node SR: %i",
int(inputNodeFormat.sampleRate));
187 NSLog(
@"Input Node Chans: %i", inputNodeFormat.channelCount);
188 NSLog(
@"Plugin Input SR: %i",
int(pluginInputFormat.sampleRate));
189 NSLog(
@"Plugin Input Chans: %i", pluginInputFormat.channelCount);
192 AVAudioFormat* pluginOutputFormat = [avAudioUnit outputFormatForBus:0];
193 AVAudioFormat* outputNodeFormat = [[engine outputNode] outputFormatForBus:0];
195 NSLog(
@"Plugin Output SR: %i",
int(pluginOutputFormat.sampleRate));
196 NSLog(
@"Plugin Output Chans: %i", pluginOutputFormat.channelCount);
197 NSLog(
@"Output Node SR: %i",
int(outputNodeFormat.sampleRate));
198 NSLog(
@"Output Node Chans: %i", outputNodeFormat.channelCount);
201- (void) printSessionInfo
203 AVAudioSession* session = [AVAudioSession sharedInstance];
204 NSLog(
@"Session SR: %i",
int(session.sampleRate));
205 NSLog(
@"Session IO Buffer: %i",
int((session.IOBufferDuration * session.sampleRate)+0.5));
206 if (!isInstrument()) NSLog(
@"Session Input Chans: %i",
int(session.inputNumberOfChannels));
207 NSLog(
@"Session Output Chans: %i",
int(session.outputNumberOfChannels));
208 if (!isInstrument()) NSLog(
@"Session Input Latency: %f ms", session.inputLatency * 1000.0f);
209 NSLog(
@"Session Output Latency: %f ms", session.outputLatency * 1000.0f);
210 AVAudioSessionRouteDescription *currentRoute = [session currentRoute];
211 for (AVAudioSessionPortDescription* input in currentRoute.inputs)
213 NSLog(
@"Input Port Name: %@", input.portName);
216 for (AVAudioSessionPortDescription* output in currentRoute.outputs)
218 NSLog(
@"Output Port Name: %@", output.portName);
222- (void) addNotifications
224 NSNotificationCenter* notifCtr = [NSNotificationCenter defaultCenter];
226 [notifCtr addObserver: self selector: @selector (onEngineConfigurationChange:) name:AVAudioEngineConfigurationChangeNotification object: engine];
229#pragma mark Notifications
230- (void) onEngineConfigurationChange: (NSNotification*) notification
232 [
self restartAudioEngine];
IPlug Constant definitions, Types, magic numbers.