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 AUInstrument Base Classes
7 */
8 
9 #ifndef __AUInstrumentBase__
10 #define __AUInstrumentBase__
11 
12 #include <vector>
13 #include <stdexcept>
14 #include <AudioUnit/AudioUnit.h>
15 #include <CoreAudio/CoreAudio.h>
16 #include <libkern/OSAtomic.h>
17 #include "MusicDeviceBase.h"
18 #include "LockFreeFIFO.h"
19 #include "SynthEvent.h"
20 #include "SynthNote.h"
21 #include "SynthElement.h"
22 
23 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
24 
25 typedef LockFreeFIFOWithFree<SynthEvent> SynthEventQueue;
26 
27 class AUInstrumentBase : public MusicDeviceBase
28 {
29 public:
30 			AUInstrumentBase(
31 							AudioComponentInstance			inInstance,
32 							UInt32							numInputs,
33 							UInt32							numOutputs,
34 							UInt32							numGroups = 16,
35 							UInt32							numParts = 1);
36 	virtual ~AUInstrumentBase();
37 
38 	virtual OSStatus			Initialize();
39 
40 	/*! @method Parts */
Parts()41 	AUScope &					Parts()	{ return mPartScope; }
42 
43 	/*! @method GetPart */
GetPart(AudioUnitElement inElement)44 	AUElement *					GetPart( AudioUnitElement inElement)
45 	{
46 		return mPartScope.SafeGetElement(inElement);
47 	}
48 
49 	virtual AUScope *			GetScopeExtended (AudioUnitScope inScope);
50 
51 	virtual AUElement *			CreateElement(			AudioUnitScope					inScope,
52 														AudioUnitElement				inElement);
53 
54 	virtual void				CreateExtendedElements();
55 
56 	virtual void				Cleanup();
57 
58 	virtual OSStatus			Reset(					AudioUnitScope 					inScope,
59 														AudioUnitElement 				inElement);
60 
61 	virtual bool				ValidFormat(			AudioUnitScope					inScope,
62 														AudioUnitElement				inElement,
63 														const CAStreamBasicDescription  & inNewFormat);
64 
65 	virtual bool				StreamFormatWritable(	AudioUnitScope					scope,
66 														AudioUnitElement				element);
67 
CanScheduleParameters()68 	virtual bool				CanScheduleParameters() const { return false; }
69 
70 	virtual OSStatus			Render(					AudioUnitRenderActionFlags &	ioActionFlags,
71 														const AudioTimeStamp &			inTimeStamp,
72 														UInt32							inNumberFrames);
73 
74 	virtual OSStatus			StartNote(		MusicDeviceInstrumentID 	inInstrument,
75 												MusicDeviceGroupID 			inGroupID,
76 												NoteInstanceID *			outNoteInstanceID,
77 												UInt32 						inOffsetSampleFrame,
78 												const MusicDeviceNoteParams &inParams);
79 
80 	virtual OSStatus			StopNote(		MusicDeviceGroupID 			inGroupID,
81 												NoteInstanceID 				inNoteInstanceID,
82 												UInt32 						inOffsetSampleFrame);
83 
84 	virtual OSStatus			RealTimeStartNote(		SynthGroupElement 			*inGroup,
85 														NoteInstanceID 				inNoteInstanceID,
86 														UInt32 						inOffsetSampleFrame,
87 														const MusicDeviceNoteParams &inParams);
88 
89 	virtual OSStatus			RealTimeStopNote(		MusicDeviceGroupID 			inGroupID,
90 														NoteInstanceID 				inNoteInstanceID,
91 														UInt32 						inOffsetSampleFrame);
92 
93 	virtual OSStatus	HandleControlChange(	UInt8	inChannel,
94 												UInt8 	inController,
95 												UInt8 	inValue,
96 												UInt32	inStartFrame);
97 
98 	virtual OSStatus	HandlePitchWheel(		UInt8 	inChannel,
99 												UInt8 	inPitch1,
100 												UInt8 	inPitch2,
101 												UInt32	inStartFrame);
102 
103 	virtual OSStatus	HandleChannelPressure(	UInt8 	inChannel,
104 												UInt8 	inValue,
105 												UInt32	inStartFrame);
106 
107 	virtual OSStatus	HandleProgramChange(	UInt8	inChannel,
108 												UInt8 	inValue);
109 
110 	virtual OSStatus	HandlePolyPressure(		UInt8 	inChannel,
111 												UInt8 	inKey,
112 												UInt8	inValue,
113 												UInt32	inStartFrame);
114 
115 	virtual OSStatus	HandleResetAllControllers(		UInt8 	inChannel);
116 
117 	virtual OSStatus	HandleAllNotesOff(				UInt8 	inChannel);
118 
119 	virtual OSStatus	HandleAllSoundOff(				UInt8 	inChannel);
120 
GetNote(UInt32 inIndex)121 	SynthNote*			GetNote(UInt32 inIndex)
122 						{
123 							if (!mNotes)
124 								throw std::runtime_error("no notes");
125 							return (SynthNote*)((char*)mNotes + inIndex * mNoteSize);
126 						}
127 
128 	SynthNote*			GetAFreeNote(UInt32 inFrame);
129 	void				AddFreeNote(SynthNote* inNote);
130 
131 	friend class SynthGroupElement;
132 protected:
133 
NextNoteID()134 	UInt32				NextNoteID() { return OSAtomicIncrement32((int32_t *)&mNoteIDCounter); }
135 
136 
137 	// call SetNotes in your Initialize() method to give the base class your note structures and to set the maximum
138 	// number of active notes. inNoteData should be an array of size inMaxActiveNotes.
139 	void				SetNotes(UInt32 inNumNotes, UInt32 inMaxActiveNotes, SynthNote* inNotes, UInt32 inNoteSize);
140 
141 	void				PerformEvents(   const AudioTimeStamp &			inTimeStamp);
142 	OSStatus			SendPedalEvent(MusicDeviceGroupID inGroupID, UInt32 inEventType, UInt32 inOffsetSampleFrame);
143 	virtual SynthNote*  VoiceStealing(UInt32 inFrame, bool inKillIt);
MaxActiveNotes()144 	UInt32				MaxActiveNotes() const { return mMaxActiveNotes; }
NumActiveNotes()145 	UInt32				NumActiveNotes() const { return mNumActiveNotes; }
IncNumActiveNotes()146 	void				IncNumActiveNotes() { ++mNumActiveNotes; }
DecNumActiveNotes()147 	void				DecNumActiveNotes() { --mNumActiveNotes; }
148 	UInt32				CountActiveNotes();
149 
150 	SynthPartElement *	GetPartElement (AudioUnitElement inPartElement);
151 
152 			// this call throws if there's no assigned element for the group ID
153 	virtual SynthGroupElement *	GetElForGroupID (MusicDeviceGroupID	inGroupID);
154 	virtual SynthGroupElement *	GetElForNoteID (NoteInstanceID inNoteID);
155 
156 	SInt64 mAbsoluteSampleFrame;
157 
158 
159 private:
160 
161 	SInt32 mNoteIDCounter;
162 
163 	SynthEventQueue mEventQueue;
164 
165 	UInt32 mNumNotes;
166 	UInt32 mNumActiveNotes;
167 	UInt32 mMaxActiveNotes;
168 	SynthNote* mNotes;
169 	SynthNoteList mFreeNotes;
170 	UInt32 mNoteSize;
171 
172 	AUScope			mPartScope;
173 	const UInt32	mInitNumPartEls;
174 };
175 
176 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
177 
178 class AUMonotimbralInstrumentBase : public AUInstrumentBase
179 {
180 public:
181 	AUMonotimbralInstrumentBase(
182 							AudioComponentInstance			inInstance,
183 							UInt32							numInputs,
184 							UInt32							numOutputs,
185 							UInt32							numGroups = 16,
186 							UInt32							numParts = 1);
187 
188 	virtual OSStatus			RealTimeStartNote(			SynthGroupElement 			*inGroup,
189 															NoteInstanceID 				inNoteInstanceID,
190 															UInt32 						inOffsetSampleFrame,
191 															const MusicDeviceNoteParams &inParams);
192 };
193 
194 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
195 
196 // this is a work in progress! The mono-timbral one is finished though!
197 class AUMultitimbralInstrumentBase : public AUInstrumentBase
198 {
199 public:
200 	AUMultitimbralInstrumentBase(
201 							AudioComponentInstance			inInstance,
202 							UInt32							numInputs,
203 							UInt32							numOutputs,
204 							UInt32							numGroups,
205 							UInt32							numParts);
206 
207 	virtual OSStatus			GetPropertyInfo(		AudioUnitPropertyID				inID,
208 														AudioUnitScope					inScope,
209 														AudioUnitElement				inElement,
210 														UInt32 &						outDataSize,
211 														Boolean &						outWritable);
212 
213 	virtual OSStatus			GetProperty(			AudioUnitPropertyID 			inID,
214 														AudioUnitScope 					inScope,
215 														AudioUnitElement			 	inElement,
216 														void *							outData);
217 
218 	virtual OSStatus			SetProperty(			AudioUnitPropertyID 			inID,
219 														AudioUnitScope 					inScope,
220 														AudioUnitElement 				inElement,
221 														const void *					inData,
222 														UInt32 							inDataSize);
223 
224 private:
225 
226 };
227 
228 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
229 
230 #endif
231 
232