1 |
iliev |
2012 |
/*************************************************************************** |
2 |
|
|
* * |
3 |
|
|
* LinuxSampler - modular, streaming capable sampler * |
4 |
|
|
* * |
5 |
|
|
* Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck * |
6 |
persson |
2114 |
* Copyright (C) 2005-2008 Christian Schoenebeck * |
7 |
|
|
* Copyright (C) 2009-2010 Christian Schoenebeck and Grigor Iliev * |
8 |
iliev |
2012 |
* * |
9 |
|
|
* This program is free software; you can redistribute it and/or modify * |
10 |
|
|
* it under the terms of the GNU General Public License as published by * |
11 |
|
|
* the Free Software Foundation; either version 2 of the License, or * |
12 |
|
|
* (at your option) any later version. * |
13 |
|
|
* * |
14 |
|
|
* This program is distributed in the hope that it will be useful, * |
15 |
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of * |
16 |
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
17 |
|
|
* GNU General Public License for more details. * |
18 |
|
|
* * |
19 |
|
|
* You should have received a copy of the GNU General Public License * |
20 |
|
|
* along with this program; if not, write to the Free Software * |
21 |
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, * |
22 |
|
|
* MA 02111-1307 USA * |
23 |
|
|
***************************************************************************/ |
24 |
|
|
|
25 |
|
|
#ifndef __LS_MIDIKEYBOARDMANAGER_H__ |
26 |
persson |
2114 |
#define __LS_MIDIKEYBOARDMANAGER_H__ |
27 |
iliev |
2012 |
|
28 |
|
|
#include "Event.h" |
29 |
|
|
#include "Stream.h" |
30 |
|
|
#include "../../EventListeners.h" |
31 |
|
|
#include "../../common/Pool.h" |
32 |
|
|
#include "../../common/global_private.h" |
33 |
schoenebeck |
2879 |
#include "Note.h" |
34 |
iliev |
2012 |
|
35 |
|
|
namespace LinuxSampler { |
36 |
|
|
|
37 |
|
|
/** |
38 |
|
|
* This class is used as a listener, which is notified |
39 |
|
|
* when MIDI keyboard events occur like note on, note off, etc. |
40 |
|
|
* Note that all events are triggered even when the channel is muted |
41 |
|
|
*/ |
42 |
|
|
class MidiKeyboardListener { |
43 |
|
|
public: |
44 |
|
|
/** Called before the engine start processing the note on event */ |
45 |
|
|
virtual void PreProcessNoteOn(uint8_t key, uint8_t velocity) = 0; |
46 |
|
|
|
47 |
|
|
/** Called after the engine has processed the note on event */ |
48 |
|
|
virtual void PostProcessNoteOn(uint8_t key, uint8_t velocity) = 0; |
49 |
|
|
|
50 |
|
|
/** Called before the engine start processing the note off event */ |
51 |
|
|
virtual void PreProcessNoteOff(uint8_t key, uint8_t velocity) = 0; |
52 |
|
|
|
53 |
|
|
/** Called after the engine has processed the note off event */ |
54 |
|
|
virtual void PostProcessNoteOff(uint8_t key, uint8_t velocity) = 0; |
55 |
|
|
|
56 |
|
|
/** Called before the engine start processing the sustain pedal up event */ |
57 |
|
|
virtual void PreProcessSustainPedalUp() = 0; |
58 |
|
|
|
59 |
|
|
/** Called after the engine has processed the sustain pedal up event */ |
60 |
|
|
virtual void PostProcessSustainPedalUp() = 0; |
61 |
|
|
|
62 |
|
|
/** Called before the engine start processing the sustain pedal down event */ |
63 |
|
|
virtual void PreProcessSustainPedalDown() = 0; |
64 |
|
|
|
65 |
|
|
/** Called after the engine has processed the sustain pedal down event */ |
66 |
|
|
virtual void PostProcessSustainPedalDown() = 0; |
67 |
|
|
|
68 |
|
|
/** Called before the engine start processing the sostenuto pedal up event */ |
69 |
|
|
virtual void PreProcessSostenutoPedalUp() = 0; |
70 |
|
|
|
71 |
|
|
/** Called after the engine has processed the sostenuto pedal up event */ |
72 |
|
|
virtual void PostProcessSostenutoPedalUp() = 0; |
73 |
|
|
|
74 |
|
|
/** Called before the engine start processing the sostenuto pedal down event */ |
75 |
|
|
virtual void PreProcessSostenutoPedalDown() = 0; |
76 |
|
|
|
77 |
|
|
/** Called after the engine has processed the sostenuto pedal down event */ |
78 |
|
|
virtual void PostProcessSostenutoPedalDown() = 0; |
79 |
|
|
}; |
80 |
|
|
|
81 |
|
|
/** |
82 |
|
|
* This class exists as convenience for creating listener objects. |
83 |
|
|
* The methods in this class are empty. |
84 |
|
|
*/ |
85 |
|
|
class MidiKeyboardAdapter : public MidiKeyboardListener { |
86 |
|
|
public: |
87 |
|
|
virtual void PreProcessNoteOn(uint8_t key, uint8_t velocity) { } |
88 |
|
|
virtual void PostProcessNoteOn(uint8_t key, uint8_t velocity) { } |
89 |
|
|
virtual void PreProcessNoteOff(uint8_t key, uint8_t velocity) { } |
90 |
|
|
virtual void PostProcessNoteOff(uint8_t key, uint8_t velocity) { } |
91 |
|
|
virtual void PreProcessSustainPedalUp() { } |
92 |
|
|
virtual void PostProcessSustainPedalUp() { } |
93 |
|
|
virtual void PreProcessSustainPedalDown() { } |
94 |
|
|
virtual void PostProcessSustainPedalDown() { } |
95 |
|
|
virtual void PreProcessSostenutoPedalUp() { } |
96 |
|
|
virtual void PostProcessSostenutoPedalUp() { } |
97 |
|
|
virtual void PreProcessSostenutoPedalDown() { } |
98 |
|
|
virtual void PostProcessSostenutoPedalDown() { } |
99 |
|
|
}; |
100 |
schoenebeck |
2645 |
|
101 |
schoenebeck |
2121 |
/** |
102 |
|
|
* This is the base class for class MidiKeyboardManager::MidiKey. It is |
103 |
|
|
* not intended to be instantiated directly. Instead it just defines |
104 |
|
|
* the part of class MidiKey which is not dependant on a C++ template |
105 |
|
|
* parameter. |
106 |
schoenebeck |
2645 |
* |
107 |
|
|
* There are also ScriptEvent lists maintained for each key, which are not |
108 |
|
|
* stored here though, but on the InstrumentScript structure. Simply because |
109 |
|
|
* RTLists are tied to one Pool instance, and it would be error prone to |
110 |
|
|
* maintain @c Pool<ScriptEvent> and @c RTList<ScriptEvent> separately, |
111 |
|
|
* since one would need to be very careful to reallocate the lists when the |
112 |
|
|
* script was changed or when the Engine instance changed, etc. |
113 |
|
|
* |
114 |
|
|
* @see InstrumentScript::pKeyEvents |
115 |
schoenebeck |
2121 |
*/ |
116 |
|
|
class MidiKeyBase { |
117 |
|
|
public: |
118 |
|
|
bool KeyPressed; ///< Is true if the respective MIDI key is currently pressed. |
119 |
|
|
bool Active; ///< If the key contains active voices. |
120 |
|
|
bool ReleaseTrigger; ///< If we have to launch release triggered voice(s) when the key is released |
121 |
|
|
Pool<uint>::Iterator itSelf; ///< hack to allow fast deallocation of the key from the list of active keys |
122 |
|
|
RTList<Event>* pEvents; ///< Key specific events (only Note-on, Note-off and sustain pedal currently) |
123 |
|
|
int VoiceTheftsQueued; ///< Amount of voices postponed due to shortage of voices. |
124 |
|
|
uint32_t* pRoundRobinIndex; ///< For the round robin dimension: current articulation for this key, will be incremented for each note on |
125 |
|
|
uint8_t Velocity; ///< Latest Note-on velocity for this key |
126 |
|
|
unsigned long NoteOnTime; ///< Time for latest Note-on event for this key |
127 |
|
|
float Volume; ///< Individual volume level for this MIDI key (usually 1.0f unless Roland GS NRPN 0x1Ann was received, nn reflecting the note number, see EngineBase::ProcessHardcodedControllers()) |
128 |
|
|
float PanLeft; ///< Individual volume balance (left channel coefficient) for this MIDI key (usually 1.0f unless Roland GS NRPN 0x1Cnn was received, nn reflecting the note number, see EngineBase::ProcessHardcodedControllers()) |
129 |
|
|
float PanRight; ///< Individual volume balance (right channel coefficient) for this MIDI key (usually 1.0f unless Roland GS NRPN 0x1Cnn was received, nn reflecting the note number, see EngineBase::ProcessHardcodedControllers()) |
130 |
|
|
optional<float> ReverbSend; ///< Optional individual reverb send level for this MIDI key (usually not set, unless Roland GS NRPN 0x1Dnn was received, nn reflecting the note number, see EngineBase::ProcessHardcodedControllers()) |
131 |
|
|
optional<float> ChorusSend; ///< Optional individual chorus send level for this MIDI key (usually not set, unless Roland GS NRPN 0x1Enn was received, nn reflecting the note number, see EngineBase::ProcessHardcodedControllers()) |
132 |
|
|
}; |
133 |
iliev |
2012 |
|
134 |
schoenebeck |
2613 |
class MidiKeyboardManagerBase { |
135 |
|
|
public: |
136 |
|
|
Pool<uint>* pActiveKeys; ///< Holds all keys in it's allocation list with active voices. |
137 |
|
|
bool SoloMode; ///< in Solo Mode we only play one voice (group) at a time |
138 |
|
|
int SoloKey; ///< Currently 'active' solo key, that is the key to which the currently sounding voice belongs to (only if SoloMode is enabled) |
139 |
|
|
bool SustainPedal; ///< true if sustain pedal is down |
140 |
|
|
bool SostenutoPedal; ///< true if sostenuto pedal is down |
141 |
|
|
int SostenutoKeys[128]; |
142 |
|
|
int SostenutoKeyCount; |
143 |
|
|
uint32_t RoundRobinIndexes[128]; |
144 |
|
|
int8_t KeyDown[128]; ///< True if the respective key is currently pressed down. Currently only used as built-in instrument script array variable %KEY_DOWN. It is currently not used by the sampler for any other purpose. |
145 |
|
|
}; |
146 |
|
|
|
147 |
iliev |
2012 |
template <class V> |
148 |
schoenebeck |
2613 |
class MidiKeyboardManager : public MidiKeyboardManagerBase { |
149 |
iliev |
2012 |
public: |
150 |
|
|
/** @brief Voice Stealing Algorithms |
151 |
|
|
* |
152 |
|
|
* Enumeration of all possible voice stealing algorithms. |
153 |
|
|
*/ |
154 |
|
|
enum voice_steal_algo_t { |
155 |
|
|
voice_steal_algo_none, ///< Voice stealing disabled. |
156 |
|
|
voice_steal_algo_oldestvoiceonkey, ///< Try to kill the oldest voice from same key where the new voice should be spawned. |
157 |
|
|
voice_steal_algo_oldestkey ///< Try to kill the oldest voice from the oldest active key. |
158 |
|
|
}; |
159 |
|
|
|
160 |
persson |
2043 |
|
161 |
iliev |
2012 |
/** @brief MIDI key runtime informations |
162 |
|
|
* |
163 |
|
|
* Reflects runtime informations for one MIDI key. |
164 |
|
|
*/ |
165 |
schoenebeck |
2121 |
class MidiKey : public MidiKeyBase { |
166 |
iliev |
2012 |
public: |
167 |
schoenebeck |
2879 |
RTList< Note<V> >* pActiveNotes; ///< Contains the active notes associated with the MIDI key. |
168 |
iliev |
2012 |
|
169 |
|
|
MidiKey() { |
170 |
schoenebeck |
2879 |
pActiveNotes = NULL; |
171 |
iliev |
2012 |
KeyPressed = false; |
172 |
|
|
Active = false; |
173 |
|
|
ReleaseTrigger = false; |
174 |
|
|
pEvents = NULL; |
175 |
|
|
VoiceTheftsQueued = 0; |
176 |
schoenebeck |
2121 |
Volume = 1.0f; |
177 |
|
|
PanLeft = 1.0f; |
178 |
|
|
PanRight = 1.0f; |
179 |
iliev |
2012 |
} |
180 |
|
|
|
181 |
|
|
void Reset() { |
182 |
schoenebeck |
2879 |
if (pActiveNotes) { |
183 |
|
|
RTListNoteIterator itNote = pActiveNotes->first(); |
184 |
|
|
RTListNoteIterator itNotesEnd = pActiveNotes->end(); |
185 |
|
|
for (; itNote != itNotesEnd; ++itNote) { // iterate through all active notes on this key |
186 |
|
|
itNote->reset(); |
187 |
iliev |
2244 |
} |
188 |
schoenebeck |
2879 |
pActiveNotes->clear(); |
189 |
iliev |
2244 |
} |
190 |
iliev |
2012 |
if (pEvents) pEvents->clear(); |
191 |
|
|
KeyPressed = false; |
192 |
|
|
Active = false; |
193 |
|
|
ReleaseTrigger = false; |
194 |
|
|
itSelf = Pool<uint>::Iterator(); |
195 |
|
|
VoiceTheftsQueued = 0; |
196 |
schoenebeck |
2121 |
Volume = 1.0f; |
197 |
|
|
PanLeft = 1.0f; |
198 |
|
|
PanRight = 1.0f; |
199 |
|
|
ReverbSend = optional<float>::nothing; |
200 |
|
|
ChorusSend = optional<float>::nothing; |
201 |
iliev |
2012 |
} |
202 |
|
|
}; |
203 |
|
|
|
204 |
schoenebeck |
2879 |
typedef typename RTList< Note<V> >::Iterator RTListNoteIterator; |
205 |
iliev |
2012 |
typedef typename RTList<V>::Iterator RTListVoiceIterator; |
206 |
|
|
typedef typename Pool<V>::Iterator PoolVoiceIterator; |
207 |
|
|
|
208 |
|
|
/** |
209 |
|
|
* Override this class to iterate through all active keys/voices |
210 |
|
|
* using ProcessActiveVoices() method. |
211 |
|
|
*/ |
212 |
|
|
class VoiceHandler { |
213 |
|
|
public: |
214 |
|
|
/** |
215 |
|
|
* @returns true if the voices on the specified key should be processed |
216 |
|
|
* adn false to cancel the processing of the active voices for the |
217 |
|
|
* specified key |
218 |
|
|
*/ |
219 |
|
|
virtual bool Process(MidiKey* pMidiKey) = 0; |
220 |
|
|
|
221 |
|
|
virtual void Process(RTListVoiceIterator& itVoice) = 0; |
222 |
|
|
}; |
223 |
|
|
|
224 |
|
|
class VoiceHandlerBase : public VoiceHandler { |
225 |
|
|
public: |
226 |
|
|
virtual bool Process(MidiKey* pMidiKey) { return true; } |
227 |
|
|
virtual void Process(RTListVoiceIterator& itVoice) { } |
228 |
|
|
}; |
229 |
|
|
|
230 |
|
|
MidiKey* pMIDIKeyInfo; ///< Contains all active voices sorted by MIDI key number and other informations to the respective MIDI key |
231 |
|
|
|
232 |
schoenebeck |
2645 |
MidiKeyboardManager(AbstractEngineChannel* pEngineChannel) { |
233 |
iliev |
2012 |
pMIDIKeyInfo = new MidiKey[128]; |
234 |
|
|
pActiveKeys = new Pool<uint>(128); |
235 |
|
|
SoloMode = false; |
236 |
|
|
SustainPedal = false; |
237 |
|
|
SostenutoPedal = false; |
238 |
persson |
2043 |
for (int i = 0 ; i < 128 ; i++) { |
239 |
|
|
RoundRobinIndexes[i] = 0; |
240 |
schoenebeck |
2613 |
KeyDown[i] = false; |
241 |
persson |
2043 |
|
242 |
|
|
// by default use one counter for each key (the |
243 |
|
|
// gig engine will change this to one counter per |
244 |
|
|
// region) |
245 |
|
|
pMIDIKeyInfo[i].pRoundRobinIndex = &RoundRobinIndexes[i]; |
246 |
|
|
} |
247 |
schoenebeck |
2645 |
m_engineChannel = pEngineChannel; |
248 |
schoenebeck |
2879 |
m_voicePool = NULL; |
249 |
iliev |
2012 |
} |
250 |
|
|
|
251 |
|
|
virtual ~MidiKeyboardManager() { |
252 |
|
|
listeners.RemoveAllListeners(); |
253 |
|
|
if (pActiveKeys) delete pActiveKeys; |
254 |
|
|
if (pMIDIKeyInfo) delete[] pMIDIKeyInfo; |
255 |
|
|
} |
256 |
|
|
|
257 |
persson |
2114 |
void Reset() { |
258 |
iliev |
2012 |
SoloKey = -1; // no solo key active yet |
259 |
|
|
|
260 |
|
|
// reset key info |
261 |
schoenebeck |
2613 |
for (uint i = 0; i < 128; i++) { |
262 |
|
|
pMIDIKeyInfo[i].Reset(); |
263 |
|
|
KeyDown[i] = false; |
264 |
schoenebeck |
2645 |
if (m_engineChannel->pScript) |
265 |
|
|
m_engineChannel->pScript->pKeyEvents[i]->clear(); |
266 |
schoenebeck |
2613 |
} |
267 |
iliev |
2012 |
|
268 |
|
|
// free all active keys |
269 |
|
|
pActiveKeys->clear(); |
270 |
|
|
} |
271 |
|
|
|
272 |
schoenebeck |
2879 |
void AllocateActiveNotesLists(Pool< Note<V> >* pNotePool, Pool<V>* pVoicePool) { |
273 |
|
|
DeleteActiveNotesLists(); |
274 |
iliev |
2012 |
|
275 |
schoenebeck |
2879 |
m_voicePool = pVoicePool; |
276 |
|
|
|
277 |
iliev |
2012 |
for (uint i = 0; i < 128; i++) { |
278 |
schoenebeck |
2879 |
pMIDIKeyInfo[i].pActiveNotes = new RTList< Note<V> >(pNotePool); |
279 |
iliev |
2012 |
} |
280 |
|
|
} |
281 |
|
|
|
282 |
schoenebeck |
2879 |
void DeleteActiveNotesLists() { |
283 |
iliev |
2012 |
for (uint i = 0; i < 128; i++) { |
284 |
schoenebeck |
2879 |
if (pMIDIKeyInfo[i].pActiveNotes) { |
285 |
|
|
delete pMIDIKeyInfo[i].pActiveNotes; |
286 |
|
|
pMIDIKeyInfo[i].pActiveNotes = NULL; |
287 |
iliev |
2012 |
} |
288 |
|
|
} |
289 |
schoenebeck |
2879 |
m_voicePool = NULL; |
290 |
iliev |
2012 |
} |
291 |
|
|
|
292 |
schoenebeck |
2879 |
void AllocateEventsLists(Pool<Event>* pEventPool) { |
293 |
|
|
DeleteEventsLists(); |
294 |
iliev |
2012 |
|
295 |
|
|
for (uint i = 0; i < 128; i++) { |
296 |
|
|
pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEventPool); |
297 |
|
|
} |
298 |
|
|
} |
299 |
|
|
|
300 |
schoenebeck |
2879 |
void DeleteEventsLists() { |
301 |
iliev |
2012 |
for (uint i = 0; i < 128; i++) { |
302 |
|
|
if (pMIDIKeyInfo[i].pEvents) { |
303 |
|
|
delete pMIDIKeyInfo[i].pEvents; |
304 |
|
|
pMIDIKeyInfo[i].pEvents = NULL; |
305 |
|
|
} |
306 |
|
|
} |
307 |
|
|
} |
308 |
|
|
|
309 |
schoenebeck |
2645 |
/*void ClearAllActiveKeyEvents() { |
310 |
iliev |
2012 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
311 |
|
|
RTList<uint>::Iterator end = pActiveKeys->end(); |
312 |
|
|
for(; iuiKey != end; ++iuiKey) { |
313 |
|
|
pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key |
314 |
|
|
} |
315 |
schoenebeck |
2645 |
}*/ |
316 |
iliev |
2012 |
|
317 |
|
|
/** |
318 |
|
|
* Removes the given voice from the MIDI key's list of active voices. |
319 |
|
|
* This method will be called when a voice went inactive, e.g. because |
320 |
|
|
* it finished to playback its sample, finished its release stage or |
321 |
|
|
* just was killed. |
322 |
|
|
* |
323 |
|
|
* @param itVoice - points to the voice to be freed |
324 |
|
|
*/ |
325 |
|
|
void FreeVoice(PoolVoiceIterator& itVoice) { |
326 |
|
|
if (itVoice) { |
327 |
schoenebeck |
2879 |
//MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey]; |
328 |
iliev |
2012 |
|
329 |
|
|
// if the sample and dimension region belong to an |
330 |
|
|
// instrument that is unloaded, tell the disk thread to |
331 |
|
|
// release them |
332 |
|
|
if (itVoice->Orphan) { |
333 |
|
|
if(itVoice->pDiskThread != NULL) { |
334 |
|
|
itVoice->pDiskThread->OrderDeletionOfRegion(itVoice->GetRegion()); |
335 |
|
|
} |
336 |
|
|
} |
337 |
|
|
|
338 |
|
|
// free the voice object |
339 |
schoenebeck |
2879 |
m_voicePool->free(itVoice); |
340 |
iliev |
2012 |
} |
341 |
|
|
else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush; |
342 |
|
|
} |
343 |
|
|
|
344 |
|
|
/** |
345 |
|
|
* Called when there's no more voice left on a key, this call will |
346 |
|
|
* update the key info respectively. |
347 |
|
|
* |
348 |
|
|
* @param pEngineChannel - engine channel on which this event occured on |
349 |
|
|
* @param pKey - key which is now inactive |
350 |
|
|
*/ |
351 |
|
|
void FreeKey(MidiKey* pKey) { |
352 |
schoenebeck |
2879 |
if (pKey->pActiveNotes->isEmpty()) { |
353 |
schoenebeck |
2645 |
if (m_engineChannel->pScript) |
354 |
|
|
m_engineChannel->pScript->pKeyEvents[pKey->itSelf]->clear(); |
355 |
iliev |
2012 |
pKey->Active = false; |
356 |
|
|
pActiveKeys->free(pKey->itSelf); // remove key from list of active keys |
357 |
|
|
pKey->itSelf = RTList<uint>::Iterator(); |
358 |
|
|
pKey->ReleaseTrigger = false; |
359 |
|
|
pKey->pEvents->clear(); |
360 |
|
|
dmsg(3,("Key has no more voices now\n")); |
361 |
|
|
} |
362 |
|
|
else dmsg(1,("MidiKeyboardManager: Oops, tried to free a key which contains voices.\n")); |
363 |
|
|
} |
364 |
|
|
|
365 |
|
|
/** |
366 |
|
|
* Free all keys which have no active voices left |
367 |
|
|
*/ |
368 |
|
|
void FreeAllInactiveKyes() { |
369 |
|
|
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
370 |
|
|
RTList<uint>::Iterator end = pActiveKeys->end(); |
371 |
|
|
while (iuiKey != end) { // iterate through all active keys |
372 |
schoenebeck |
2645 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
373 |
iliev |
2012 |
++iuiKey; |
374 |
schoenebeck |
2879 |
for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), |
375 |
|
|
itNotesEnd = pKey->pActiveNotes->end(); |
376 |
|
|
itNote != itNotesEnd; ++itNote) |
377 |
|
|
{ // iterate over all active notes on that key ... |
378 |
|
|
if (itNote->pActiveVoices->isEmpty()) { // free note ... |
379 |
|
|
itNote->reset(); |
380 |
|
|
pKey->pActiveNotes->free(itNote); |
381 |
|
|
} |
382 |
|
|
#if CONFIG_DEVMODE |
383 |
|
|
else { // just a sanity check for debugging |
384 |
|
|
RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); |
385 |
|
|
RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); |
386 |
|
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
387 |
|
|
if (itVoice->itKillEvent) { |
388 |
|
|
dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n")); |
389 |
|
|
} |
390 |
iliev |
2012 |
} |
391 |
|
|
} |
392 |
schoenebeck |
2879 |
#endif // CONFIG_DEVMODE |
393 |
iliev |
2012 |
} |
394 |
schoenebeck |
2879 |
if (pKey->pActiveNotes->isEmpty()) FreeKey(pKey); |
395 |
iliev |
2012 |
} |
396 |
|
|
} |
397 |
|
|
|
398 |
|
|
int StealVoice ( |
399 |
|
|
Pool<Event>::Iterator& itNoteOnEvent, |
400 |
|
|
RTListVoiceIterator* LastStolenVoice, |
401 |
schoenebeck |
2879 |
RTListNoteIterator* LastStolenNote, |
402 |
iliev |
2012 |
RTList<uint>::Iterator* LastStolenKey |
403 |
|
|
) { |
404 |
|
|
RTListVoiceIterator itSelectedVoice; |
405 |
|
|
|
406 |
|
|
// Select one voice for voice stealing |
407 |
|
|
switch (CONFIG_VOICE_STEAL_ALGO) { |
408 |
|
|
|
409 |
|
|
// try to pick the oldest voice on the key where the new |
410 |
|
|
// voice should be spawned, if there is no voice on that |
411 |
|
|
// key, or no voice left to kill, then procceed with |
412 |
|
|
// 'oldestkey' algorithm |
413 |
|
|
case voice_steal_algo_oldestvoiceonkey: { |
414 |
|
|
MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key]; |
415 |
schoenebeck |
2879 |
for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(), |
416 |
|
|
itNotesEnd = pSelectedKey->pActiveNotes->end(); |
417 |
|
|
itNote != itNotesEnd; ++itNote) |
418 |
|
|
{ |
419 |
|
|
for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) |
420 |
|
|
if (itSelectedVoice->IsStealable()) // proceed iterating if voice was created in this audio fragment cycle |
421 |
|
|
goto voiceFound; // selection succeeded |
422 |
|
|
} |
423 |
|
|
// if we haven't found a voice then proceed with algorithm 'oldestkey' ... |
424 |
iliev |
2012 |
} // no break - intentional ! |
425 |
|
|
|
426 |
|
|
// try to pick the oldest voice on the oldest active key |
427 |
|
|
// from the same engine channel |
428 |
|
|
// (caution: must stay after 'oldestvoiceonkey' algorithm !) |
429 |
|
|
case voice_steal_algo_oldestkey: { |
430 |
schoenebeck |
2879 |
// if we already stole in this fragment, try to proceed to steal on same note |
431 |
iliev |
2012 |
if (*LastStolenVoice) { |
432 |
|
|
itSelectedVoice = *LastStolenVoice; |
433 |
|
|
do { |
434 |
|
|
++itSelectedVoice; |
435 |
|
|
} while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle |
436 |
|
|
// found a "stealable" voice ? |
437 |
|
|
if (itSelectedVoice && itSelectedVoice->IsStealable()) { |
438 |
|
|
// remember which voice we stole, so we can simply proceed on next voice stealing |
439 |
|
|
*LastStolenVoice = itSelectedVoice; |
440 |
|
|
break; // selection succeeded |
441 |
|
|
} |
442 |
|
|
} |
443 |
schoenebeck |
2879 |
|
444 |
|
|
// get (next) oldest note |
445 |
|
|
if (*LastStolenNote) { |
446 |
|
|
for (RTListNoteIterator itNote = ++(*LastStolenNote); |
447 |
|
|
itNote; ++itNote) |
448 |
|
|
{ |
449 |
|
|
for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) { |
450 |
|
|
// proceed iterating if voice was created in this audio fragment cycle |
451 |
|
|
if (itSelectedVoice->IsStealable()) { |
452 |
|
|
// remember which voice on which note we stole, so we can simply proceed on next voice stealing |
453 |
|
|
*LastStolenNote = itNote; |
454 |
|
|
*LastStolenVoice = itSelectedVoice; |
455 |
|
|
goto voiceFound; // selection succeeded |
456 |
|
|
} |
457 |
|
|
} |
458 |
|
|
} |
459 |
|
|
} |
460 |
|
|
|
461 |
iliev |
2012 |
// get (next) oldest key |
462 |
|
|
RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first(); |
463 |
schoenebeck |
2879 |
for (; iuiSelectedKey; ++iuiSelectedKey) { |
464 |
iliev |
2012 |
MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey]; |
465 |
schoenebeck |
2879 |
|
466 |
|
|
for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(), |
467 |
|
|
itNotesEnd = pSelectedKey->pActiveNotes->end(); |
468 |
|
|
itNote != itNotesEnd; ++itNote) |
469 |
|
|
{ |
470 |
|
|
for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) { |
471 |
|
|
// proceed iterating if voice was created in this audio fragment cycle |
472 |
|
|
if (itSelectedVoice->IsStealable()) { |
473 |
|
|
// remember which voice on which key we stole, so we can simply proceed on next voice stealing |
474 |
|
|
*LastStolenKey = iuiSelectedKey; |
475 |
|
|
*LastStolenNote = itNote; |
476 |
|
|
*LastStolenVoice = itSelectedVoice; |
477 |
|
|
goto voiceFound; // selection succeeded |
478 |
|
|
} |
479 |
|
|
} |
480 |
iliev |
2012 |
} |
481 |
|
|
} |
482 |
|
|
break; |
483 |
|
|
} |
484 |
|
|
|
485 |
|
|
// don't steal anything |
486 |
|
|
case voice_steal_algo_none: |
487 |
|
|
default: { |
488 |
|
|
dmsg(1,("No free voice (voice stealing disabled)!\n")); |
489 |
|
|
return -1; |
490 |
|
|
} |
491 |
|
|
} |
492 |
schoenebeck |
2879 |
|
493 |
|
|
voiceFound: |
494 |
iliev |
2012 |
|
495 |
|
|
if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1; |
496 |
|
|
|
497 |
|
|
#if CONFIG_DEVMODE |
498 |
|
|
if (!itSelectedVoice->IsActive()) { |
499 |
|
|
dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n")); |
500 |
|
|
return -1; |
501 |
|
|
} |
502 |
|
|
#endif // CONFIG_DEVMODE |
503 |
|
|
|
504 |
|
|
// now kill the selected voice |
505 |
|
|
itSelectedVoice->Kill(itNoteOnEvent); |
506 |
|
|
|
507 |
|
|
return 0; |
508 |
|
|
} |
509 |
|
|
|
510 |
|
|
/** |
511 |
|
|
* Releases all voices. All voices will go into |
512 |
|
|
* the release stage and thus it might take some time (e.g. dependant to |
513 |
|
|
* their envelope release time) until they actually die. |
514 |
|
|
* |
515 |
|
|
* @param itReleaseEvent - event which caused this releasing of all voices |
516 |
|
|
*/ |
517 |
|
|
void ReleaseAllVoices(Pool<Event>::Iterator& itReleaseEvent) { |
518 |
|
|
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
519 |
|
|
while (iuiKey) { |
520 |
|
|
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
521 |
|
|
++iuiKey; |
522 |
|
|
// append a 'release' event to the key's own event list |
523 |
|
|
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
524 |
|
|
if (itNewEvent) { |
525 |
|
|
*itNewEvent = *itReleaseEvent; // copy original event (to the key's event list) |
526 |
|
|
itNewEvent->Type = Event::type_release; // transform event type |
527 |
|
|
} |
528 |
|
|
else dmsg(1,("Event pool emtpy!\n")); |
529 |
|
|
} |
530 |
|
|
} |
531 |
schoenebeck |
2879 |
|
532 |
iliev |
2012 |
/** |
533 |
|
|
* Kill all active voices. |
534 |
|
|
* @returns The number of voices. |
535 |
|
|
*/ |
536 |
|
|
int KillAllVoices(Pool<Event>::Iterator& itKillEvent) { |
537 |
|
|
int count = 0; |
538 |
|
|
|
539 |
schoenebeck |
2879 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
540 |
iliev |
2012 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
541 |
|
|
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
542 |
|
|
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
543 |
schoenebeck |
2879 |
|
544 |
|
|
for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), |
545 |
|
|
itNotesEnd = pKey->pActiveNotes->end(); |
546 |
|
|
itNote != itNotesEnd; ++itNote) |
547 |
|
|
{ |
548 |
|
|
RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); |
549 |
|
|
RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); |
550 |
|
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
551 |
|
|
itVoice->Kill(itKillEvent); |
552 |
|
|
count++; |
553 |
|
|
} |
554 |
iliev |
2012 |
} |
555 |
|
|
} |
556 |
|
|
|
557 |
|
|
return count; |
558 |
|
|
} |
559 |
|
|
|
560 |
|
|
/** |
561 |
|
|
* Kill all voices the *die hard* way. |
562 |
|
|
* @returns The number of pending stream deletions |
563 |
|
|
*/ |
564 |
|
|
int KillAllVoicesImmediately() { |
565 |
|
|
int iPendingStreamDeletions = 0; |
566 |
|
|
|
567 |
schoenebeck |
2879 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
568 |
iliev |
2012 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
569 |
|
|
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
570 |
|
|
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
571 |
schoenebeck |
2879 |
|
572 |
|
|
for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), |
573 |
|
|
itNotesEnd = pKey->pActiveNotes->end(); |
574 |
|
|
itNote != itNotesEnd; ++itNote) |
575 |
|
|
{ |
576 |
|
|
RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); |
577 |
|
|
RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); |
578 |
|
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
579 |
|
|
// request a notification from disk thread side for stream deletion |
580 |
|
|
const Stream::Handle hStream = itVoice->KillImmediately(true); |
581 |
|
|
if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream |
582 |
|
|
iPendingStreamDeletions++; |
583 |
|
|
} |
584 |
|
|
// free the voice to the voice pool and update key info |
585 |
|
|
itVoice->VoiceFreed(); |
586 |
|
|
FreeVoice(itVoice); |
587 |
iliev |
2012 |
} |
588 |
|
|
} |
589 |
|
|
} |
590 |
|
|
|
591 |
|
|
return iPendingStreamDeletions; |
592 |
|
|
} |
593 |
|
|
|
594 |
|
|
/** |
595 |
|
|
* Mark all currently active voices as "orphans", which means that the regions and |
596 |
|
|
* samples they use should be released to the instrument manager when the voices die. |
597 |
|
|
*/ |
598 |
|
|
void MarkAllActiveVoicesAsOrphans() { |
599 |
schoenebeck |
2879 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
600 |
iliev |
2012 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
601 |
|
|
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
602 |
|
|
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
603 |
schoenebeck |
2879 |
|
604 |
|
|
for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), |
605 |
|
|
itNotesEnd = pKey->pActiveNotes->end(); |
606 |
|
|
itNote != itNotesEnd; ++itNote) |
607 |
|
|
{ |
608 |
|
|
RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); |
609 |
|
|
RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); |
610 |
|
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
611 |
|
|
itVoice->Orphan = true; |
612 |
|
|
} |
613 |
iliev |
2012 |
} |
614 |
|
|
} |
615 |
|
|
} |
616 |
|
|
|
617 |
|
|
void ProcessActiveVoices(VoiceHandler* pVoiceHandler) { |
618 |
|
|
if (pVoiceHandler == NULL) return; |
619 |
|
|
|
620 |
schoenebeck |
2879 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
621 |
iliev |
2012 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
622 |
|
|
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
623 |
|
|
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
624 |
|
|
if (!pVoiceHandler->Process(pKey)) continue; |
625 |
|
|
|
626 |
schoenebeck |
2879 |
for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), |
627 |
|
|
itNotesEnd = pKey->pActiveNotes->end(); |
628 |
|
|
itNote != itNotesEnd; ++itNote) |
629 |
|
|
{ |
630 |
|
|
RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); |
631 |
|
|
RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); |
632 |
|
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
633 |
|
|
pVoiceHandler->Process(itVoice); |
634 |
|
|
} |
635 |
iliev |
2012 |
} |
636 |
|
|
} |
637 |
|
|
} |
638 |
schoenebeck |
2448 |
|
639 |
|
|
/** |
640 |
|
|
* Recalculate the pitch of all active voices. |
641 |
|
|
*/ |
642 |
|
|
void OnScaleTuningChanged() { |
643 |
|
|
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
644 |
|
|
for (; iuiKey; ++iuiKey) { |
645 |
|
|
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
646 |
schoenebeck |
2879 |
|
647 |
|
|
for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), |
648 |
|
|
itNotesEnd = pKey->pActiveNotes->end(); |
649 |
|
|
itNote != itNotesEnd; ++itNote) |
650 |
|
|
{ |
651 |
|
|
RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); |
652 |
|
|
for (; itVoice; ++itVoice) { |
653 |
|
|
itVoice->onScaleTuningChanged(); |
654 |
|
|
} |
655 |
schoenebeck |
2448 |
} |
656 |
|
|
} |
657 |
|
|
} |
658 |
|
|
|
659 |
iliev |
2012 |
void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) { |
660 |
|
|
// Cancel release process of all voices |
661 |
|
|
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
662 |
|
|
for (; iuiKey; ++iuiKey) { |
663 |
|
|
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
664 |
|
|
if (!pKey->KeyPressed) { |
665 |
|
|
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
666 |
|
|
if (itNewEvent) { |
667 |
|
|
*itNewEvent = *itEvent; // copy event to the key's own event list |
668 |
|
|
itNewEvent->Type = Event::type_cancel_release; // transform event type |
669 |
|
|
} |
670 |
|
|
else dmsg(1,("Event pool emtpy!\n")); |
671 |
|
|
} |
672 |
|
|
} |
673 |
|
|
} |
674 |
|
|
|
675 |
|
|
void ProcessSustainPedalUp(Pool<Event>::Iterator& itEvent) { |
676 |
|
|
// release voices if their respective key is not pressed |
677 |
|
|
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
678 |
|
|
for (; iuiKey; ++iuiKey) { |
679 |
|
|
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
680 |
|
|
if (!pKey->KeyPressed && ShouldReleaseVoice(*iuiKey)) { |
681 |
|
|
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
682 |
|
|
if (itNewEvent) { |
683 |
|
|
*itNewEvent = *itEvent; // copy event to the key's own event list |
684 |
|
|
itNewEvent->Type = Event::type_release; // transform event type |
685 |
|
|
} |
686 |
|
|
else dmsg(1,("Event pool emtpy!\n")); |
687 |
|
|
} |
688 |
|
|
} |
689 |
|
|
} |
690 |
|
|
|
691 |
|
|
/** |
692 |
|
|
* Determines whether the specified voice should be released. |
693 |
|
|
* |
694 |
|
|
* @param pEngineChannel - The engine channel on which the voice should be checked |
695 |
|
|
* @param Key - The key number |
696 |
|
|
* @returns true if the specified voice should be released, false otherwise. |
697 |
|
|
*/ |
698 |
|
|
bool ShouldReleaseVoice(int Key) { |
699 |
|
|
if (SustainPedal) return false; |
700 |
|
|
|
701 |
|
|
if (SostenutoPedal) { |
702 |
|
|
for (int i = 0; i < SostenutoKeyCount; i++) |
703 |
|
|
if (Key == SostenutoKeys[i]) return false; |
704 |
|
|
} |
705 |
|
|
|
706 |
|
|
return true; |
707 |
|
|
} |
708 |
|
|
|
709 |
|
|
void ProcessSostenutoPedalDown() { |
710 |
|
|
SostenutoKeyCount = 0; |
711 |
|
|
// Remeber the pressed keys |
712 |
|
|
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
713 |
|
|
for (; iuiKey; ++iuiKey) { |
714 |
|
|
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
715 |
|
|
if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey; |
716 |
|
|
} |
717 |
|
|
} |
718 |
|
|
|
719 |
|
|
void ProcessSostenutoPedalUp(Pool<Event>::Iterator& itEvent) { |
720 |
|
|
// release voices if the damper pedal is up and their respective key is not pressed |
721 |
|
|
for (int i = 0; i < SostenutoKeyCount; i++) { |
722 |
|
|
MidiKey* pKey = &pMIDIKeyInfo[SostenutoKeys[i]]; |
723 |
|
|
if (!pKey->KeyPressed && !SustainPedal) { |
724 |
|
|
RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend(); |
725 |
|
|
if (itNewEvent) { |
726 |
|
|
*itNewEvent = *itEvent; // copy event to the key's own event list |
727 |
|
|
itNewEvent->Type = Event::type_release; // transform event type |
728 |
|
|
} |
729 |
|
|
else dmsg(1,("Event pool emtpy!\n")); |
730 |
|
|
} |
731 |
|
|
} |
732 |
|
|
} |
733 |
|
|
|
734 |
|
|
void AddMidiKeyboardListener(MidiKeyboardListener* l) { listeners.AddListener(l); } |
735 |
|
|
|
736 |
|
|
void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); } |
737 |
|
|
|
738 |
|
|
protected: |
739 |
schoenebeck |
2645 |
AbstractEngineChannel* m_engineChannel; |
740 |
schoenebeck |
2879 |
Pool<V>* m_voicePool; |
741 |
schoenebeck |
2645 |
|
742 |
iliev |
2012 |
class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> { |
743 |
|
|
public: |
744 |
|
|
REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t) |
745 |
|
|
REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOn, uint8_t, uint8_t) |
746 |
|
|
REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOff, uint8_t, uint8_t) |
747 |
|
|
REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOff, uint8_t, uint8_t) |
748 |
|
|
REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalUp) |
749 |
|
|
REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalUp) |
750 |
|
|
REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalDown) |
751 |
|
|
REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalDown) |
752 |
|
|
REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalUp) |
753 |
|
|
REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalUp) |
754 |
|
|
REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalDown) |
755 |
|
|
REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalDown) |
756 |
|
|
} listeners; |
757 |
|
|
}; |
758 |
|
|
} // namespace LinuxSampler |
759 |
|
|
|
760 |
persson |
2114 |
#endif /* __LS_MIDIKEYBOARDMANAGER_H__ */ |