30 |
#include "../../EventListeners.h" |
#include "../../EventListeners.h" |
31 |
#include "../../common/Pool.h" |
#include "../../common/Pool.h" |
32 |
#include "../../common/global_private.h" |
#include "../../common/global_private.h" |
33 |
|
#include "Note.h" |
34 |
|
|
35 |
namespace LinuxSampler { |
namespace LinuxSampler { |
36 |
|
|
97 |
virtual void PreProcessSostenutoPedalDown() { } |
virtual void PreProcessSostenutoPedalDown() { } |
98 |
virtual void PostProcessSostenutoPedalDown() { } |
virtual void PostProcessSostenutoPedalDown() { } |
99 |
}; |
}; |
100 |
|
|
101 |
/** |
/** |
102 |
* This is the base class for class MidiKeyboardManager::MidiKey. It is |
* This is the base class for class MidiKeyboardManager::MidiKey. It is |
103 |
* not intended to be instantiated directly. Instead it just defines |
* not intended to be instantiated directly. Instead it just defines |
104 |
* the part of class MidiKey which is not dependant on a C++ template |
* the part of class MidiKey which is not dependant on a C++ template |
105 |
* parameter. |
* parameter. |
106 |
|
* |
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 |
*/ |
*/ |
116 |
class MidiKeyBase { |
class MidiKeyBase { |
117 |
public: |
public: |
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()) |
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 |
|
|
134 |
|
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 |
|
virtual void ProcessReleaseTrigger(RTList<Event>::Iterator& itEvent) = 0; |
147 |
|
}; |
148 |
|
|
149 |
template <class V> |
template <class V> |
150 |
class MidiKeyboardManager { |
class MidiKeyboardManager : public MidiKeyboardManagerBase { |
151 |
public: |
public: |
152 |
/** @brief Voice Stealing Algorithms |
/** @brief Voice Stealing Algorithms |
153 |
* |
* |
166 |
*/ |
*/ |
167 |
class MidiKey : public MidiKeyBase { |
class MidiKey : public MidiKeyBase { |
168 |
public: |
public: |
169 |
RTList<V>* pActiveVoices; ///< Contains the active voices associated with the MIDI key. |
RTList< Note<V> >* pActiveNotes; ///< Contains the active notes associated with the MIDI key. |
170 |
|
|
171 |
MidiKey() { |
MidiKey() { |
172 |
pActiveVoices = NULL; |
pActiveNotes = NULL; |
173 |
KeyPressed = false; |
KeyPressed = false; |
174 |
Active = false; |
Active = false; |
175 |
ReleaseTrigger = false; |
ReleaseTrigger = false; |
181 |
} |
} |
182 |
|
|
183 |
void Reset() { |
void Reset() { |
184 |
if (pActiveVoices) { |
if (pActiveNotes) { |
185 |
RTListVoiceIterator itVoice = pActiveVoices->first(); |
RTListNoteIterator itNote = pActiveNotes->first(); |
186 |
RTListVoiceIterator itVoicesEnd = pActiveVoices->end(); |
RTListNoteIterator itNotesEnd = pActiveNotes->end(); |
187 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
for (; itNote != itNotesEnd; ++itNote) { // iterate through all active notes on this key |
188 |
itVoice->VoiceFreed(); |
itNote->reset(); |
189 |
} |
} |
190 |
pActiveVoices->clear(); |
pActiveNotes->clear(); |
191 |
} |
} |
192 |
if (pEvents) pEvents->clear(); |
if (pEvents) pEvents->clear(); |
193 |
KeyPressed = false; |
KeyPressed = false; |
203 |
} |
} |
204 |
}; |
}; |
205 |
|
|
206 |
|
typedef typename RTList< Note<V> >::Iterator RTListNoteIterator; |
207 |
typedef typename RTList<V>::Iterator RTListVoiceIterator; |
typedef typename RTList<V>::Iterator RTListVoiceIterator; |
208 |
typedef typename Pool<V>::Iterator PoolVoiceIterator; |
typedef typename Pool<V>::Iterator PoolVoiceIterator; |
209 |
|
|
230 |
}; |
}; |
231 |
|
|
232 |
MidiKey* pMIDIKeyInfo; ///< Contains all active voices sorted by MIDI key number and other informations to the respective MIDI key |
MidiKey* pMIDIKeyInfo; ///< Contains all active voices sorted by MIDI key number and other informations to the respective MIDI key |
|
Pool<uint>* pActiveKeys; ///< Holds all keys in it's allocation list with active voices. |
|
|
bool SoloMode; ///< in Solo Mode we only play one voice (group) at a time |
|
|
int SoloKey; ///< Currently 'active' solo key, that is the key to which the currently sounding voice belongs to (only if SoloMode is enabled) |
|
|
bool SustainPedal; ///< true if sustain pedal is down |
|
|
bool SostenutoPedal; ///< true if sostenuto pedal is down |
|
|
int SostenutoKeys[128]; |
|
|
int SostenutoKeyCount; |
|
|
uint32_t RoundRobinIndexes[128]; |
|
233 |
|
|
234 |
MidiKeyboardManager() { |
MidiKeyboardManager(AbstractEngineChannel* pEngineChannel) { |
235 |
pMIDIKeyInfo = new MidiKey[128]; |
pMIDIKeyInfo = new MidiKey[128]; |
236 |
pActiveKeys = new Pool<uint>(128); |
pActiveKeys = new Pool<uint>(128); |
237 |
SoloMode = false; |
SoloMode = false; |
239 |
SostenutoPedal = false; |
SostenutoPedal = false; |
240 |
for (int i = 0 ; i < 128 ; i++) { |
for (int i = 0 ; i < 128 ; i++) { |
241 |
RoundRobinIndexes[i] = 0; |
RoundRobinIndexes[i] = 0; |
242 |
|
KeyDown[i] = false; |
243 |
|
|
244 |
// by default use one counter for each key (the |
// by default use one counter for each key (the |
245 |
// gig engine will change this to one counter per |
// gig engine will change this to one counter per |
246 |
// region) |
// region) |
247 |
pMIDIKeyInfo[i].pRoundRobinIndex = &RoundRobinIndexes[i]; |
pMIDIKeyInfo[i].pRoundRobinIndex = &RoundRobinIndexes[i]; |
248 |
} |
} |
249 |
|
m_engineChannel = pEngineChannel; |
250 |
|
m_voicePool = NULL; |
251 |
} |
} |
252 |
|
|
253 |
virtual ~MidiKeyboardManager() { |
virtual ~MidiKeyboardManager() { |
260 |
SoloKey = -1; // no solo key active yet |
SoloKey = -1; // no solo key active yet |
261 |
|
|
262 |
// reset key info |
// reset key info |
263 |
for (uint i = 0; i < 128; i++) pMIDIKeyInfo[i].Reset(); |
for (uint i = 0; i < 128; i++) { |
264 |
|
pMIDIKeyInfo[i].Reset(); |
265 |
|
KeyDown[i] = false; |
266 |
|
if (m_engineChannel->pScript) |
267 |
|
m_engineChannel->pScript->pKeyEvents[i]->clear(); |
268 |
|
} |
269 |
|
|
270 |
// free all active keys |
// free all active keys |
271 |
pActiveKeys->clear(); |
pActiveKeys->clear(); |
272 |
} |
} |
273 |
|
|
274 |
void AllocateActiveVoices(Pool<V>* pVoicePool) { |
void AllocateActiveNotesLists(Pool< Note<V> >* pNotePool, Pool<V>* pVoicePool) { |
275 |
DeleteActiveVoices(); |
DeleteActiveNotesLists(); |
276 |
|
|
277 |
|
m_voicePool = pVoicePool; |
278 |
|
|
279 |
for (uint i = 0; i < 128; i++) { |
for (uint i = 0; i < 128; i++) { |
280 |
pMIDIKeyInfo[i].pActiveVoices = new RTList<V>(pVoicePool); |
pMIDIKeyInfo[i].pActiveNotes = new RTList< Note<V> >(pNotePool); |
281 |
} |
} |
282 |
} |
} |
283 |
|
|
284 |
void DeleteActiveVoices() { |
void DeleteActiveNotesLists() { |
285 |
for (uint i = 0; i < 128; i++) { |
for (uint i = 0; i < 128; i++) { |
286 |
if (pMIDIKeyInfo[i].pActiveVoices) { |
if (pMIDIKeyInfo[i].pActiveNotes) { |
287 |
delete pMIDIKeyInfo[i].pActiveVoices; |
delete pMIDIKeyInfo[i].pActiveNotes; |
288 |
pMIDIKeyInfo[i].pActiveVoices = NULL; |
pMIDIKeyInfo[i].pActiveNotes = NULL; |
289 |
} |
} |
290 |
} |
} |
291 |
|
m_voicePool = NULL; |
292 |
} |
} |
293 |
|
|
294 |
void AllocateEvents(Pool<Event>* pEventPool) { |
void AllocateEventsLists(Pool<Event>* pEventPool) { |
295 |
DeleteEvents(); |
DeleteEventsLists(); |
296 |
|
|
297 |
for (uint i = 0; i < 128; i++) { |
for (uint i = 0; i < 128; i++) { |
298 |
pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEventPool); |
pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEventPool); |
299 |
} |
} |
300 |
} |
} |
301 |
|
|
302 |
void DeleteEvents() { |
void DeleteEventsLists() { |
303 |
for (uint i = 0; i < 128; i++) { |
for (uint i = 0; i < 128; i++) { |
304 |
if (pMIDIKeyInfo[i].pEvents) { |
if (pMIDIKeyInfo[i].pEvents) { |
305 |
delete pMIDIKeyInfo[i].pEvents; |
delete pMIDIKeyInfo[i].pEvents; |
308 |
} |
} |
309 |
} |
} |
310 |
|
|
311 |
void ClearAllActiveKeyEvents() { |
/*void ClearAllActiveKeyEvents() { |
312 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
313 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
RTList<uint>::Iterator end = pActiveKeys->end(); |
314 |
for(; iuiKey != end; ++iuiKey) { |
for(; iuiKey != end; ++iuiKey) { |
315 |
pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key |
pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key |
316 |
} |
} |
317 |
} |
}*/ |
318 |
|
|
319 |
/** |
/** |
320 |
* Removes the given voice from the MIDI key's list of active voices. |
* Removes the given voice from the MIDI key's list of active voices. |
326 |
*/ |
*/ |
327 |
void FreeVoice(PoolVoiceIterator& itVoice) { |
void FreeVoice(PoolVoiceIterator& itVoice) { |
328 |
if (itVoice) { |
if (itVoice) { |
329 |
MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey]; |
//MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey]; |
330 |
|
|
331 |
// if the sample and dimension region belong to an |
// if the sample and dimension region belong to an |
332 |
// instrument that is unloaded, tell the disk thread to |
// instrument that is unloaded, tell the disk thread to |
338 |
} |
} |
339 |
|
|
340 |
// free the voice object |
// free the voice object |
341 |
pKey->pActiveVoices->free(itVoice); |
m_voicePool->free(itVoice); |
342 |
} |
} |
343 |
else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush; |
else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush; |
344 |
} |
} |
351 |
* @param pKey - key which is now inactive |
* @param pKey - key which is now inactive |
352 |
*/ |
*/ |
353 |
void FreeKey(MidiKey* pKey) { |
void FreeKey(MidiKey* pKey) { |
354 |
if (pKey->pActiveVoices->isEmpty()) { |
if (pKey->pActiveNotes->isEmpty()) { |
355 |
|
if (m_engineChannel->pScript) |
356 |
|
m_engineChannel->pScript->pKeyEvents[pKey->itSelf]->clear(); |
357 |
pKey->Active = false; |
pKey->Active = false; |
358 |
pActiveKeys->free(pKey->itSelf); // remove key from list of active keys |
pActiveKeys->free(pKey->itSelf); // remove key from list of active keys |
359 |
pKey->itSelf = RTList<uint>::Iterator(); |
pKey->itSelf = RTList<uint>::Iterator(); |
371 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
372 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
RTList<uint>::Iterator end = pActiveKeys->end(); |
373 |
while (iuiKey != end) { // iterate through all active keys |
while (iuiKey != end) { // iterate through all active keys |
374 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
375 |
++iuiKey; |
++iuiKey; |
376 |
if (pKey->pActiveVoices->isEmpty()) FreeKey(pKey); |
for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), |
377 |
#if CONFIG_DEVMODE |
itNotesEnd = pKey->pActiveNotes->end(); |
378 |
else { // just a sanity check for debugging |
itNote != itNotesEnd; ++itNote) |
379 |
RTListVoiceIterator itVoice = pKey->pActiveVoices->first(); |
{ // iterate over all active notes on that key ... |
380 |
RTListVoiceIterator = pKey->pActiveVoices->end(); |
if (itNote->pActiveVoices->isEmpty()) { // free note ... |
381 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
itNote->reset(); |
382 |
if (itVoice->itKillEvent) { |
pKey->pActiveNotes->free(itNote); |
383 |
dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n")); |
} |
384 |
|
#if CONFIG_DEVMODE |
385 |
|
else { // just a sanity check for debugging |
386 |
|
RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); |
387 |
|
RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); |
388 |
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
389 |
|
if (itVoice->itKillEvent) { |
390 |
|
dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n")); |
391 |
|
} |
392 |
} |
} |
393 |
} |
} |
394 |
|
#endif // CONFIG_DEVMODE |
395 |
} |
} |
396 |
#endif // CONFIG_DEVMODE |
if (pKey->pActiveNotes->isEmpty()) FreeKey(pKey); |
397 |
} |
} |
398 |
} |
} |
399 |
|
|
400 |
int StealVoice ( |
int StealVoice ( |
401 |
Pool<Event>::Iterator& itNoteOnEvent, |
Pool<Event>::Iterator& itNoteOnEvent, |
402 |
RTListVoiceIterator* LastStolenVoice, |
RTListVoiceIterator* LastStolenVoice, |
403 |
|
RTListNoteIterator* LastStolenNote, |
404 |
RTList<uint>::Iterator* LastStolenKey |
RTList<uint>::Iterator* LastStolenKey |
405 |
) { |
) { |
406 |
RTListVoiceIterator itSelectedVoice; |
RTListVoiceIterator itSelectedVoice; |
414 |
// 'oldestkey' algorithm |
// 'oldestkey' algorithm |
415 |
case voice_steal_algo_oldestvoiceonkey: { |
case voice_steal_algo_oldestvoiceonkey: { |
416 |
MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key]; |
MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key]; |
417 |
itSelectedVoice = pSelectedKey->pActiveVoices->first(); |
for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(), |
418 |
// proceed iterating if voice was created in this fragment cycle |
itNotesEnd = pSelectedKey->pActiveNotes->end(); |
419 |
while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice; |
itNote != itNotesEnd; ++itNote) |
420 |
// if we haven't found a voice then proceed with algorithm 'oldestkey' |
{ |
421 |
if (itSelectedVoice && itSelectedVoice->IsStealable()) break; |
for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) |
422 |
|
if (itSelectedVoice->IsStealable()) // proceed iterating if voice was created in this audio fragment cycle |
423 |
|
goto voiceFound; // selection succeeded |
424 |
|
} |
425 |
|
// if we haven't found a voice then proceed with algorithm 'oldestkey' ... |
426 |
} // no break - intentional ! |
} // no break - intentional ! |
427 |
|
|
428 |
// try to pick the oldest voice on the oldest active key |
// try to pick the oldest voice on the oldest active key |
429 |
// from the same engine channel |
// from the same engine channel |
430 |
// (caution: must stay after 'oldestvoiceonkey' algorithm !) |
// (caution: must stay after 'oldestvoiceonkey' algorithm !) |
431 |
case voice_steal_algo_oldestkey: { |
case voice_steal_algo_oldestkey: { |
432 |
// if we already stole in this fragment, try to proceed on same key |
// if we already stole in this fragment, try to proceed to steal on same note |
433 |
if (*LastStolenVoice) { |
if (*LastStolenVoice) { |
434 |
itSelectedVoice = *LastStolenVoice; |
itSelectedVoice = *LastStolenVoice; |
435 |
do { |
do { |
442 |
break; // selection succeeded |
break; // selection succeeded |
443 |
} |
} |
444 |
} |
} |
445 |
|
|
446 |
|
// get (next) oldest note |
447 |
|
if (*LastStolenNote) { |
448 |
|
for (RTListNoteIterator itNote = ++(*LastStolenNote); |
449 |
|
itNote; ++itNote) |
450 |
|
{ |
451 |
|
for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) { |
452 |
|
// proceed iterating if voice was created in this audio fragment cycle |
453 |
|
if (itSelectedVoice->IsStealable()) { |
454 |
|
// remember which voice on which note we stole, so we can simply proceed on next voice stealing |
455 |
|
*LastStolenNote = itNote; |
456 |
|
*LastStolenVoice = itSelectedVoice; |
457 |
|
goto voiceFound; // selection succeeded |
458 |
|
} |
459 |
|
} |
460 |
|
} |
461 |
|
} |
462 |
|
|
463 |
// get (next) oldest key |
// get (next) oldest key |
464 |
RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first(); |
RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first(); |
465 |
while (iuiSelectedKey) { |
for (; iuiSelectedKey; ++iuiSelectedKey) { |
466 |
MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey]; |
MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey]; |
467 |
itSelectedVoice = pSelectedKey->pActiveVoices->first(); |
|
468 |
// proceed iterating if voice was created in this fragment cycle |
for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(), |
469 |
while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice; |
itNotesEnd = pSelectedKey->pActiveNotes->end(); |
470 |
// found a "stealable" voice ? |
itNote != itNotesEnd; ++itNote) |
471 |
if (itSelectedVoice && itSelectedVoice->IsStealable()) { |
{ |
472 |
// remember which voice on which key we stole, so we can simply proceed on next voice stealing |
for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) { |
473 |
*LastStolenKey = iuiSelectedKey; |
// proceed iterating if voice was created in this audio fragment cycle |
474 |
*LastStolenVoice = itSelectedVoice; |
if (itSelectedVoice->IsStealable()) { |
475 |
break; // selection succeeded |
// remember which voice on which key we stole, so we can simply proceed on next voice stealing |
476 |
|
*LastStolenKey = iuiSelectedKey; |
477 |
|
*LastStolenNote = itNote; |
478 |
|
*LastStolenVoice = itSelectedVoice; |
479 |
|
goto voiceFound; // selection succeeded |
480 |
|
} |
481 |
|
} |
482 |
} |
} |
|
++iuiSelectedKey; // get next oldest key |
|
483 |
} |
} |
484 |
break; |
break; |
485 |
} |
} |
491 |
return -1; |
return -1; |
492 |
} |
} |
493 |
} |
} |
494 |
|
|
495 |
|
voiceFound: |
496 |
|
|
497 |
if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1; |
if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1; |
498 |
|
|
530 |
else dmsg(1,("Event pool emtpy!\n")); |
else dmsg(1,("Event pool emtpy!\n")); |
531 |
} |
} |
532 |
} |
} |
533 |
|
|
534 |
/** |
/** |
535 |
* Kill all active voices. |
* Kill all active voices. |
536 |
* @returns The number of voices. |
* @returns The number of voices. |
538 |
int KillAllVoices(Pool<Event>::Iterator& itKillEvent) { |
int KillAllVoices(Pool<Event>::Iterator& itKillEvent) { |
539 |
int count = 0; |
int count = 0; |
540 |
|
|
541 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
542 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
RTList<uint>::Iterator end = pActiveKeys->end(); |
543 |
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
544 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
545 |
RTListVoiceIterator itVoice = pKey->pActiveVoices->first(); |
|
546 |
RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end(); |
for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), |
547 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
itNotesEnd = pKey->pActiveNotes->end(); |
548 |
itVoice->Kill(itKillEvent); |
itNote != itNotesEnd; ++itNote) |
549 |
count++; |
{ |
550 |
|
RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); |
551 |
|
RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); |
552 |
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
553 |
|
itVoice->Kill(itKillEvent); |
554 |
|
count++; |
555 |
|
} |
556 |
} |
} |
557 |
} |
} |
558 |
|
|
566 |
int KillAllVoicesImmediately() { |
int KillAllVoicesImmediately() { |
567 |
int iPendingStreamDeletions = 0; |
int iPendingStreamDeletions = 0; |
568 |
|
|
569 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
570 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
RTList<uint>::Iterator end = pActiveKeys->end(); |
571 |
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
572 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
573 |
RTListVoiceIterator itVoice = pKey->pActiveVoices->first(); |
|
574 |
RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end(); |
for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), |
575 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
itNotesEnd = pKey->pActiveNotes->end(); |
576 |
// request a notification from disk thread side for stream deletion |
itNote != itNotesEnd; ++itNote) |
577 |
const Stream::Handle hStream = itVoice->KillImmediately(true); |
{ |
578 |
if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream |
RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); |
579 |
iPendingStreamDeletions++; |
RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); |
580 |
} |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
581 |
// free the voice to the voice pool and update key info |
// request a notification from disk thread side for stream deletion |
582 |
itVoice->VoiceFreed(); |
const Stream::Handle hStream = itVoice->KillImmediately(true); |
583 |
FreeVoice(itVoice); |
if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream |
584 |
|
iPendingStreamDeletions++; |
585 |
|
} |
586 |
|
// free the voice to the voice pool and update key info |
587 |
|
itVoice->VoiceFreed(); |
588 |
|
FreeVoice(itVoice); |
589 |
|
} |
590 |
} |
} |
591 |
} |
} |
592 |
|
|
598 |
* samples they use should be released to the instrument manager when the voices die. |
* samples they use should be released to the instrument manager when the voices die. |
599 |
*/ |
*/ |
600 |
void MarkAllActiveVoicesAsOrphans() { |
void MarkAllActiveVoicesAsOrphans() { |
601 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
602 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
RTList<uint>::Iterator end = pActiveKeys->end(); |
603 |
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
604 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
605 |
RTListVoiceIterator itVoice = pKey->pActiveVoices->first(); |
|
606 |
RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end(); |
for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), |
607 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
itNotesEnd = pKey->pActiveNotes->end(); |
608 |
itVoice->Orphan = true; |
itNote != itNotesEnd; ++itNote) |
609 |
|
{ |
610 |
|
RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); |
611 |
|
RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); |
612 |
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
613 |
|
itVoice->Orphan = true; |
614 |
|
} |
615 |
} |
} |
616 |
} |
} |
617 |
} |
} |
619 |
void ProcessActiveVoices(VoiceHandler* pVoiceHandler) { |
void ProcessActiveVoices(VoiceHandler* pVoiceHandler) { |
620 |
if (pVoiceHandler == NULL) return; |
if (pVoiceHandler == NULL) return; |
621 |
|
|
622 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
623 |
RTList<uint>::Iterator end = pActiveKeys->end(); |
RTList<uint>::Iterator end = pActiveKeys->end(); |
624 |
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
for (; iuiKey != end; ++iuiKey) { // iterate through all active keys |
625 |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
626 |
if (!pVoiceHandler->Process(pKey)) continue; |
if (!pVoiceHandler->Process(pKey)) continue; |
627 |
|
|
628 |
RTListVoiceIterator itVoice = pKey->pActiveVoices->first(); |
for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), |
629 |
RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end(); |
itNotesEnd = pKey->pActiveNotes->end(); |
630 |
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
itNote != itNotesEnd; ++itNote) |
631 |
pVoiceHandler->Process(itVoice); |
{ |
632 |
|
RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); |
633 |
|
RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end(); |
634 |
|
for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key |
635 |
|
pVoiceHandler->Process(itVoice); |
636 |
|
} |
637 |
} |
} |
638 |
} |
} |
639 |
} |
} |
640 |
|
|
641 |
|
/** |
642 |
|
* Recalculate the pitch of all active voices. |
643 |
|
*/ |
644 |
|
void OnScaleTuningChanged() { |
645 |
|
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
646 |
|
for (; iuiKey; ++iuiKey) { |
647 |
|
MidiKey* pKey = &pMIDIKeyInfo[*iuiKey]; |
648 |
|
|
649 |
|
for (RTListNoteIterator itNote = pKey->pActiveNotes->first(), |
650 |
|
itNotesEnd = pKey->pActiveNotes->end(); |
651 |
|
itNote != itNotesEnd; ++itNote) |
652 |
|
{ |
653 |
|
RTListVoiceIterator itVoice = itNote->pActiveVoices->first(); |
654 |
|
for (; itVoice; ++itVoice) { |
655 |
|
itVoice->onScaleTuningChanged(); |
656 |
|
} |
657 |
|
} |
658 |
|
} |
659 |
|
} |
660 |
|
|
661 |
void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) { |
void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) { |
662 |
// Cancel release process of all voices |
// Cancel release process of all voices |
663 |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
RTList<uint>::Iterator iuiKey = pActiveKeys->first(); |
684 |
if (itNewEvent) { |
if (itNewEvent) { |
685 |
*itNewEvent = *itEvent; // copy event to the key's own event list |
*itNewEvent = *itEvent; // copy event to the key's own event list |
686 |
itNewEvent->Type = Event::type_release; // transform event type |
itNewEvent->Type = Event::type_release; // transform event type |
687 |
|
itNewEvent->Param.Note.Key = *iuiKey; |
688 |
|
itNewEvent->Param.Note.Velocity = 127; |
689 |
|
if (!SostenutoActiveOnKey(*iuiKey)) { |
690 |
|
//HACK: set sustain CC (64) as "pressed down" for a short moment, so that release trigger voices can distinguish between note off and sustain pedal up cases |
691 |
|
AbstractEngineChannel* pChannel = (AbstractEngineChannel*) itEvent->pEngineChannel; |
692 |
|
const int8_t CC64Value = pChannel->ControllerTable[64]; |
693 |
|
pChannel->ControllerTable[64] = 127; |
694 |
|
|
695 |
|
// now spawn release trigger voices (if required) |
696 |
|
ProcessReleaseTrigger(itNewEvent); |
697 |
|
|
698 |
|
//HACK: reset sustain pedal CC value to old one (see comment above) |
699 |
|
pChannel->ControllerTable[64] = CC64Value; |
700 |
|
} |
701 |
} |
} |
702 |
else dmsg(1,("Event pool emtpy!\n")); |
else dmsg(1,("Event pool emtpy!\n")); |
703 |
} |
} |
705 |
} |
} |
706 |
|
|
707 |
/** |
/** |
708 |
|
* Whether @a key is still kept active due to sostenuto pedal usage. |
709 |
|
* |
710 |
|
* @param key - note number of key |
711 |
|
*/ |
712 |
|
inline bool SostenutoActiveOnKey(int key) const { |
713 |
|
if (SostenutoPedal) { |
714 |
|
for (int i = 0; i < SostenutoKeyCount; i++) |
715 |
|
if (key == SostenutoKeys[i]) return true; |
716 |
|
} |
717 |
|
return false; |
718 |
|
} |
719 |
|
|
720 |
|
/** |
721 |
* Determines whether the specified voice should be released. |
* Determines whether the specified voice should be released. |
722 |
* |
* |
723 |
* @param pEngineChannel - The engine channel on which the voice should be checked |
* @param pEngineChannel - The engine channel on which the voice should be checked |
726 |
*/ |
*/ |
727 |
bool ShouldReleaseVoice(int Key) { |
bool ShouldReleaseVoice(int Key) { |
728 |
if (SustainPedal) return false; |
if (SustainPedal) return false; |
729 |
|
if (SostenutoActiveOnKey(Key)) return false; |
|
if (SostenutoPedal) { |
|
|
for (int i = 0; i < SostenutoKeyCount; i++) |
|
|
if (Key == SostenutoKeys[i]) return false; |
|
|
} |
|
|
|
|
730 |
return true; |
return true; |
731 |
} |
} |
732 |
|
|
760 |
void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); } |
void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); } |
761 |
|
|
762 |
protected: |
protected: |
763 |
|
AbstractEngineChannel* m_engineChannel; |
764 |
|
Pool<V>* m_voicePool; |
765 |
|
|
766 |
class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> { |
class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> { |
767 |
public: |
public: |
768 |
REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t) |
REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t) |