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 __SynthNoteList__
10 #define __SynthNoteList__
11 
12 #include "SynthNote.h"
13 
14 #if DEBUG
15 #ifndef DEBUG_PRINT
16 	#define DEBUG_PRINT 0
17 #endif
18 	#define USE_SANITY_CHECK 0
19 #endif
20 
21 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
22 
23 struct SynthNoteList
24 {
SynthNoteListSynthNoteList25 	SynthNoteList() : mState(kNoteState_Unset), mHead(0), mTail(0) {}
26 
NotEmptySynthNoteList27 	bool NotEmpty() const { return mHead != NULL; }
IsEmptySynthNoteList28 	bool IsEmpty() const { return mHead == NULL; }
EmptySynthNoteList29 	void Empty() {
30 #if USE_SANITY_CHECK
31 		SanityCheck();
32 #endif
33 		mHead = mTail = NULL;
34 	}
35 
LengthSynthNoteList36 	UInt32 Length() const {
37 #if USE_SANITY_CHECK
38 		SanityCheck();
39 #endif
40 		UInt32 length = 0;
41 		for (SynthNote* note = mHead; note; note = note->mNext)
42 			length++;
43 		return length;
44 	};
45 
AddNoteSynthNoteList46 	void AddNote(SynthNote *inNote)
47 	{
48 #if DEBUG_PRINT
49 		printf("AddNote(inNote=%p) to state: %lu\n", inNote, mState);
50 #endif
51 #if USE_SANITY_CHECK
52 		SanityCheck();
53 #endif
54 		inNote->SetState(mState);
55 		inNote->mNext = mHead;
56 		inNote->mPrev = NULL;
57 
58 		if (mHead) { mHead->mPrev = inNote; mHead = inNote; }
59 		else mHead = mTail = inNote;
60 #if USE_SANITY_CHECK
61 		SanityCheck();
62 #endif
63 	}
64 
RemoveNoteSynthNoteList65 	void RemoveNote(SynthNote *inNote)
66 	{
67 #if DEBUG_PRINT
68 		printf("RemoveNote(inNote=%p) from state: %lu\n", inNote, mState);
69 #endif
70 #if USE_SANITY_CHECK
71 		SanityCheck();
72 #endif
73 		if (inNote->mPrev) inNote->mPrev->mNext = inNote->mNext;
74 		else mHead = inNote->mNext;
75 
76 		if (inNote->mNext) inNote->mNext->mPrev = inNote->mPrev;
77 		else mTail = inNote->mPrev;
78 
79 		inNote->mPrev = 0;
80 		inNote->mNext = 0;
81 #if USE_SANITY_CHECK
82 		SanityCheck();
83 #endif
84 	}
85 
TransferAllFromSynthNoteList86 	void TransferAllFrom(SynthNoteList *inNoteList, UInt32 inFrame)
87 	{
88 #if DEBUG_PRINT
89 		printf("TransferAllFrom: from state %lu into state %lu\n", inNoteList->mState, mState);
90 #endif
91 #if USE_SANITY_CHECK
92 		SanityCheck();
93 		inNoteList->SanityCheck();
94 #endif
95 		if (!inNoteList->mTail) return;
96 
97 		if (mState == kNoteState_Released)
98 		{
99 			for (SynthNote* note = inNoteList->mHead; note; note = note->mNext)
100 			{
101 #if DEBUG_PRINT
102 				printf("TransferAllFrom: releasing note %p\n", note);
103 #endif
104 				note->Release(inFrame);
105 				note->SetState(mState);
106 			}
107 		}
108 		else
109 		{
110 			for (SynthNote* note = inNoteList->mHead; note; note = note->mNext)
111 			{
112 				note->SetState(mState);
113 			}
114 		}
115 
116 		inNoteList->mTail->mNext = mHead;
117 
118 		if (mHead) mHead->mPrev = inNoteList->mTail;
119 		else mTail = inNoteList->mTail;
120 
121 		mHead = inNoteList->mHead;
122 
123 		inNoteList->mHead = NULL;
124 		inNoteList->mTail = NULL;
125 #if USE_SANITY_CHECK
126 		SanityCheck();
127 		inNoteList->SanityCheck();
128 #endif
129 	}
130 
FindOldestNoteSynthNoteList131 	SynthNote* FindOldestNote()
132 	{
133 #if DEBUG_PRINT
134 		printf("FindOldestNote\n");
135 #endif
136 #if USE_SANITY_CHECK
137 		SanityCheck();
138 #endif
139 		UInt64 minStartFrame = -1;
140 		SynthNote* oldestNote = NULL;
141 		for (SynthNote* note = mHead; note; note = note->mNext)
142 		{
143 			if (note->mAbsoluteStartFrame < minStartFrame)
144 			{
145 				oldestNote = note;
146 				minStartFrame = note->mAbsoluteStartFrame;
147 			}
148 		}
149 		return oldestNote;
150 	}
151 
FindMostQuietNoteSynthNoteList152 	SynthNote* FindMostQuietNote()
153 	{
154 #if DEBUG_PRINT
155 		printf("FindMostQuietNote\n");
156 #endif
157 		Float32 minAmplitude = 1e9f;
158 		UInt64 minStartFrame = -1;
159 		SynthNote* mostQuietNote = NULL;
160 		for (SynthNote* note = mHead; note; note = note->mNext)
161 		{
162 			Float32 amp = note->Amplitude();
163 #if DEBUG_PRINT
164 			printf("   amp %g   minAmplitude %g\n", amp, minAmplitude);
165 #endif
166 			if (amp < minAmplitude)
167 			{
168 				mostQuietNote = note;
169 				minAmplitude = amp;
170 				minStartFrame = note->mAbsoluteStartFrame;
171 			}
172 			else if (amp == minAmplitude && note->mAbsoluteStartFrame < minStartFrame)
173 			{
174 				// use earliest start time as a tie breaker
175 				mostQuietNote = note;
176 				minStartFrame = note->mAbsoluteStartFrame;
177 			}
178 		}
179 #if USE_SANITY_CHECK
180 		SanityCheck();
181 #endif
182 		return mostQuietNote;
183 	}
184 
185 	void SanityCheck() const;
186 
187 	SynthNoteState	mState;
188 	SynthNote *		mHead;
189 	SynthNote *		mTail;
190 };
191 
192 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
193 
194 #endif
195