1 /*
2 Copyright (C) 2016 Apple Inc. All Rights Reserved.
3 See LICENSE.txt for this sample’s licensing information
4 
5 Abstract:
6 Part of Core Audio AUBase Classes
7 */
8 
9 #include "MusicDeviceBase.h"
10 
11 // compatibility with older OS SDK releases
12 typedef OSStatus
13 (*TEMP_MusicDeviceMIDIEventProc)(	void *			inComponentStorage,
14 							UInt32					inStatus,
15 							UInt32					inData1,
16 							UInt32					inData2,
17 							UInt32					inOffsetSampleFrame);
18 
19 typedef OSStatus
20 (*TEMP_MusicDeviceStartNoteProc)(	void *				inComponentStorage,
21 						MusicDeviceInstrumentID			inInstrument,
22 						MusicDeviceGroupID				inGroupID,
23 						NoteInstanceID *				outNoteInstanceID,
24 						UInt32							inOffsetSampleFrame,
25 						const MusicDeviceNoteParams *	inParams);
26 
27 typedef OSStatus
28 (*TEMP_MusicDeviceStopNoteProc)(void *					inComponentStorage,
29 						MusicDeviceGroupID				inGroupID,
30 						NoteInstanceID					inNoteInstanceID,
31 						UInt32							inOffsetSampleFrame);
32 
33 #if !CA_USE_AUDIO_PLUGIN_ONLY
34 
35 static OSStatus		MusicDeviceBaseMIDIEvent(void *			inComponentStorage,
36 						UInt32				inStatus,
37 						UInt32				inData1,
38 						UInt32				inData2,
39 						UInt32				inOffsetSampleFrame);
40 
41 static OSStatus		MusicDeviceBaseStartNote(	void *		inComponentStorage,
42 						MusicDeviceInstrumentID			inInstrument,
43 						MusicDeviceGroupID				inGroupID,
44 						NoteInstanceID *				outNoteInstanceID,
45 						UInt32							inOffsetSampleFrame,
46 						const MusicDeviceNoteParams *	inParams);
47 
48 static OSStatus		MusicDeviceBaseStopNote(void *			inComponentStorage,
49 						MusicDeviceGroupID				inGroupID,
50 						NoteInstanceID					inNoteInstanceID,
51 						UInt32							inOffsetSampleFrame);
52 
53 #endif
54 
MusicDeviceBase(AudioComponentInstance inInstance,UInt32 numInputs,UInt32 numOutputs,UInt32 numGroups)55 MusicDeviceBase::MusicDeviceBase(AudioComponentInstance			inInstance,
56 									UInt32						numInputs,
57 									UInt32						numOutputs,
58 									UInt32						numGroups)
59 	: AUBase(inInstance, numInputs, numOutputs, numGroups),
60 	  AUMIDIBase(this)
61 {
62 }
63 
GetPropertyInfo(AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement,UInt32 & outDataSize,Boolean & outWritable)64 OSStatus			MusicDeviceBase::GetPropertyInfo(AudioUnitPropertyID	inID,
65 							AudioUnitScope				inScope,
66 							AudioUnitElement			inElement,
67 							UInt32 &				outDataSize,
68 							Boolean &				outWritable)
69 {
70 	OSStatus result;
71 
72 	switch (inID)
73 	{
74 #if !TARGET_OS_IPHONE
75 		case kMusicDeviceProperty_InstrumentCount:
76 			if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope;
77 			outDataSize = sizeof(UInt32);
78 			outWritable = false;
79 			result = noErr;
80 			break;
81 #endif
82 		default:
83 			result = AUBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
84 
85 			if (result == kAudioUnitErr_InvalidProperty)
86 				result = AUMIDIBase::DelegateGetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
87 			break;
88 	}
89 	return result;
90 }
91 
GetProperty(AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement,void * outData)92 OSStatus			MusicDeviceBase::GetProperty(	AudioUnitPropertyID			inID,
93 							AudioUnitScope 				inScope,
94 							AudioUnitElement		 	inElement,
95 							void *					outData)
96 {
97 	OSStatus result;
98 
99 	switch (inID)
100 	{
101 #if !CA_USE_AUDIO_PLUGIN_ONLY
102 		case kAudioUnitProperty_FastDispatch:
103 			if (!IsCMgrObject()) return kAudioUnitErr_InvalidProperty;
104 			if (inElement == kMusicDeviceMIDIEventSelect) {
105 				*(TEMP_MusicDeviceMIDIEventProc *)outData = MusicDeviceBaseMIDIEvent;
106 				return noErr;
107 			}
108 			else if (inElement == kMusicDeviceStartNoteSelect) {
109 				*(TEMP_MusicDeviceStartNoteProc *)outData = MusicDeviceBaseStartNote;
110 				return noErr;
111 			}
112 			else if (inElement == kMusicDeviceStopNoteSelect) {
113 				*(TEMP_MusicDeviceStopNoteProc *)outData = MusicDeviceBaseStopNote;
114 				return noErr;
115 			}
116 			return kAudioUnitErr_InvalidElement;
117 #endif
118 
119 #if !TARGET_OS_IPHONE
120 		case kMusicDeviceProperty_InstrumentCount:
121 			if (inScope != kAudioUnitScope_Global) return kAudioUnitErr_InvalidScope;
122 			return GetInstrumentCount (*(UInt32*)outData);
123 #endif
124 		default:
125 			result = AUBase::GetProperty (inID, inScope, inElement, outData);
126 
127 			if (result == kAudioUnitErr_InvalidProperty)
128 				result = AUMIDIBase::DelegateGetProperty (inID, inScope, inElement, outData);
129 	}
130 
131 	return result;
132 }
133 
134 
SetProperty(AudioUnitPropertyID inID,AudioUnitScope inScope,AudioUnitElement inElement,const void * inData,UInt32 inDataSize)135 OSStatus			MusicDeviceBase::SetProperty(	AudioUnitPropertyID 			inID,
136 							AudioUnitScope 				inScope,
137 							AudioUnitElement 			inElement,
138 							const void *				inData,
139 							UInt32 					inDataSize)
140 
141 {
142 
143 	OSStatus result = AUBase::SetProperty (inID, inScope, inElement, inData, inDataSize);
144 
145 	if (result == kAudioUnitErr_InvalidProperty)
146 		result = AUMIDIBase::DelegateSetProperty (inID, inScope, inElement, inData, inDataSize);
147 
148 	return result;
149 }
150 
151 // For a MusicDevice that doesn't support separate instruments (ie. is mono-timbral)
152 // then this call should return an instrument count of zero and noErr
GetInstrumentCount(UInt32 & outInstCount) const153 OSStatus			MusicDeviceBase::GetInstrumentCount (UInt32 &outInstCount) const
154 {
155 	outInstCount = 0;
156 	return noErr;
157 }
158 
HandleNoteOn(UInt8 inChannel,UInt8 inNoteNumber,UInt8 inVelocity,UInt32 inStartFrame)159 OSStatus	MusicDeviceBase::HandleNoteOn(	UInt8 	inChannel,
160 											UInt8 	inNoteNumber,
161 											UInt8 	inVelocity,
162 											UInt32 	inStartFrame)
163 {
164 	MusicDeviceNoteParams params;
165 	params.argCount = 2;
166 	params.mPitch = inNoteNumber;
167 	params.mVelocity = inVelocity;
168 	return StartNote (kMusicNoteEvent_UseGroupInstrument, inChannel, NULL, inStartFrame, params);
169 }
170 
HandleNoteOff(UInt8 inChannel,UInt8 inNoteNumber,UInt8 inVelocity,UInt32 inStartFrame)171 OSStatus	MusicDeviceBase::HandleNoteOff(	UInt8 	inChannel,
172 											UInt8 	inNoteNumber,
173 											UInt8 	inVelocity,
174 											UInt32 	inStartFrame)
175 {
176 	return StopNote (inChannel, inNoteNumber, inStartFrame);
177 }
178 
179 OSStatus
HandleStartNoteMessage(MusicDeviceInstrumentID inInstrument,MusicDeviceGroupID inGroupID,NoteInstanceID * outNoteInstanceID,UInt32 inOffsetSampleFrame,const MusicDeviceNoteParams * inParams)180 MusicDeviceBase::HandleStartNoteMessage (MusicDeviceInstrumentID		inInstrument,
181 										MusicDeviceGroupID				inGroupID,
182 										NoteInstanceID *				outNoteInstanceID,
183 										UInt32							inOffsetSampleFrame,
184 										const MusicDeviceNoteParams *	inParams)
185 {
186 	if (inParams == NULL || outNoteInstanceID == NULL) return kAudio_ParamError;
187 
188 	if (!IsInitialized()) return kAudioUnitErr_Uninitialized;
189 
190 	return StartNote (inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams);
191 }
192 
193 #if TARGET_OS_MAC
194 	#if __LP64__
195 		// comp instance, parameters in forward order
196 		#define PARAM(_typ, _name, _index, _nparams) \
197 			_typ _name = *(_typ *)&params->params[_index + 1];
198 	#else
199 		// parameters in reverse order, then comp instance
200 		#define PARAM(_typ, _name, _index, _nparams) \
201 			_typ _name = *(_typ *)&params->params[_nparams - 1 - _index];
202 	#endif
203 #elif TARGET_OS_WIN32
204 		// (no comp instance), parameters in forward order
205 		#define PARAM(_typ, _name, _index, _nparams) \
206 			_typ _name = *(_typ *)&params->params[_index];
207 #endif
208 
209 #if !CA_USE_AUDIO_PLUGIN_ONLY
ComponentEntryDispatch(ComponentParameters * params,MusicDeviceBase * This)210 OSStatus			MusicDeviceBase::ComponentEntryDispatch(	ComponentParameters *		params,
211 																MusicDeviceBase *			This)
212 {
213 	if (This == NULL) return kAudio_ParamError;
214 
215 	OSStatus result;
216 
217 	switch (params->what) {
218 	case kMusicDeviceMIDIEventSelect:
219 	case kMusicDeviceSysExSelect:
220 		{
221 			result = AUMIDIBase::ComponentEntryDispatch (params, This);
222 		}
223 		break;
224 	case kMusicDevicePrepareInstrumentSelect:
225 		{
226 			PARAM(MusicDeviceInstrumentID, inInstrument, 0, 1);
227 			result = This->PrepareInstrument(inInstrument);
228 		}
229 		break;
230 	case kMusicDeviceReleaseInstrumentSelect:
231 		{
232 			PARAM(MusicDeviceInstrumentID, inInstrument, 0, 1);
233 			result = This->ReleaseInstrument(inInstrument);
234 		}
235 		break;
236 	case kMusicDeviceStartNoteSelect:
237 		{
238 			PARAM(MusicDeviceInstrumentID, pbinInstrument, 0, 5);
239 			PARAM(MusicDeviceGroupID, pbinGroupID, 1, 5);
240 			PARAM(NoteInstanceID *, pboutNoteInstanceID, 2, 5);
241 			PARAM(UInt32, pbinOffsetSampleFrame, 3, 5);
242 			PARAM(const MusicDeviceNoteParams *, pbinParams, 4, 5);
243 			result = This->HandleStartNoteMessage(pbinInstrument, pbinGroupID, pboutNoteInstanceID, pbinOffsetSampleFrame, pbinParams);
244 		}
245 		break;
246 	case kMusicDeviceStopNoteSelect:
247 		{
248 			PARAM(MusicDeviceGroupID, pbinGroupID, 0, 3);
249 			PARAM(NoteInstanceID, pbinNoteInstanceID, 1, 3);
250 			PARAM(UInt32, pbinOffsetSampleFrame, 2, 3);
251 			result = This->StopNote(pbinGroupID, pbinNoteInstanceID, pbinOffsetSampleFrame);
252 		}
253 		break;
254 
255 	default:
256 		result = AUBase::ComponentEntryDispatch(params, This);
257 		break;
258 	}
259 
260 	return result;
261 }
262 #endif
263 
264 #if !CA_USE_AUDIO_PLUGIN_ONLY
265 
266 // fast dispatch
MusicDeviceBaseMIDIEvent(void * inComponentStorage,UInt32 inStatus,UInt32 inData1,UInt32 inData2,UInt32 inOffsetSampleFrame)267 static OSStatus		MusicDeviceBaseMIDIEvent(void *					inComponentStorage,
268 						UInt32					inStatus,
269 						UInt32					inData1,
270 						UInt32					inData2,
271 						UInt32					inOffsetSampleFrame)
272 {
273 	OSStatus result = noErr;
274 	try {
275 		MusicDeviceBase *This = static_cast<MusicDeviceBase *>(inComponentStorage);
276 		if (This == NULL) return kAudio_ParamError;
277 		result = This->MIDIEvent(inStatus, inData1, inData2, inOffsetSampleFrame);
278 	}
279 	COMPONENT_CATCH
280 	return result;
281 }
282 
MusicDeviceBaseStartNote(void * inComponentStorage,MusicDeviceInstrumentID inInstrument,MusicDeviceGroupID inGroupID,NoteInstanceID * outNoteInstanceID,UInt32 inOffsetSampleFrame,const MusicDeviceNoteParams * inParams)283 OSStatus		MusicDeviceBaseStartNote(	void *		inComponentStorage,
284 						MusicDeviceInstrumentID			inInstrument,
285 						MusicDeviceGroupID				inGroupID,
286 						NoteInstanceID *				outNoteInstanceID,
287 						UInt32							inOffsetSampleFrame,
288 						const MusicDeviceNoteParams *	inParams)
289 {
290 	OSStatus result = noErr;
291 	try {
292 		if (inParams == NULL || outNoteInstanceID == NULL) return kAudio_ParamError;
293 		MusicDeviceBase *This = static_cast<MusicDeviceBase *>(inComponentStorage);
294 		if (This == NULL) return kAudio_ParamError;
295 		result = This->StartNote(inInstrument, inGroupID, outNoteInstanceID, inOffsetSampleFrame, *inParams);
296 	}
297 	COMPONENT_CATCH
298 	return result;
299 }
300 
MusicDeviceBaseStopNote(void * inComponentStorage,MusicDeviceGroupID inGroupID,NoteInstanceID inNoteInstanceID,UInt32 inOffsetSampleFrame)301 OSStatus		MusicDeviceBaseStopNote(void *			inComponentStorage,
302 						MusicDeviceGroupID				inGroupID,
303 						NoteInstanceID					inNoteInstanceID,
304 						UInt32							inOffsetSampleFrame)
305 {
306 	OSStatus result = noErr;
307 	try {
308 		MusicDeviceBase *This = static_cast<MusicDeviceBase *>(inComponentStorage);
309 		if (This == NULL) return kAudio_ParamError;
310 		result = This->StopNote(inGroupID, inNoteInstanceID, inOffsetSampleFrame);
311 	}
312 	COMPONENT_CATCH
313 	return result;
314 }
315 
316 #endif
317