/[svn]/linuxsampler/trunk/src/engines/common/MidiKeyboardManager.h
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/common/MidiKeyboardManager.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3444 - (show annotations) (download) (as text)
Sun Dec 23 19:32:11 2018 UTC (5 years, 3 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 40954 byte(s)
* Only play release trigger samples on sustain pedal up if this behaviour
  was explicitly requested by the instrument (otherwise only on note-off).
* Bumped version (2.1.0.svn2).

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005-2008 Christian Schoenebeck *
7 * Copyright (C) 2009-2010 Christian Schoenebeck and Grigor Iliev *
8 * *
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 #define __LS_MIDIKEYBOARDMANAGER_H__
27
28 #include "Event.h"
29 #include "Stream.h"
30 #include "../../EventListeners.h"
31 #include "../../common/Pool.h"
32 #include "../../common/global_private.h"
33 #include "Note.h"
34
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
101 /**
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 *
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 {
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 release_trigger_t ReleaseTrigger; ///< If we have to launch release triggered voice(s) when either the key or sustain pedal 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
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 ProcessReleaseTriggerBySustain(RTList<Event>::Iterator& itEvent) = 0;
147 };
148
149 template <class V>
150 class MidiKeyboardManager : public MidiKeyboardManagerBase {
151 public:
152 /** @brief Voice Stealing Algorithms
153 *
154 * Enumeration of all possible voice stealing algorithms.
155 */
156 enum voice_steal_algo_t {
157 voice_steal_algo_none, ///< Voice stealing disabled.
158 voice_steal_algo_oldestvoiceonkey, ///< Try to kill the oldest voice from same key where the new voice should be spawned.
159 voice_steal_algo_oldestkey ///< Try to kill the oldest voice from the oldest active key.
160 };
161
162
163 /** @brief MIDI key runtime informations
164 *
165 * Reflects runtime informations for one MIDI key.
166 */
167 class MidiKey : public MidiKeyBase {
168 public:
169 RTList< Note<V> >* pActiveNotes; ///< Contains the active notes associated with the MIDI key.
170
171 MidiKey() {
172 pActiveNotes = NULL;
173 KeyPressed = false;
174 Active = false;
175 ReleaseTrigger = release_trigger_none;
176 pEvents = NULL;
177 VoiceTheftsQueued = 0;
178 Volume = 1.0f;
179 PanLeft = 1.0f;
180 PanRight = 1.0f;
181 }
182
183 void Reset() {
184 if (pActiveNotes) {
185 RTListNoteIterator itNote = pActiveNotes->first();
186 RTListNoteIterator itNotesEnd = pActiveNotes->end();
187 for (; itNote != itNotesEnd; ++itNote) { // iterate through all active notes on this key
188 itNote->reset();
189 }
190 pActiveNotes->clear();
191 }
192 if (pEvents) pEvents->clear();
193 KeyPressed = false;
194 Active = false;
195 ReleaseTrigger = release_trigger_none;
196 itSelf = Pool<uint>::Iterator();
197 VoiceTheftsQueued = 0;
198 Volume = 1.0f;
199 PanLeft = 1.0f;
200 PanRight = 1.0f;
201 ReverbSend = optional<float>::nothing;
202 ChorusSend = optional<float>::nothing;
203 }
204 };
205
206 typedef typename RTList< Note<V> >::Iterator RTListNoteIterator;
207 typedef typename RTList<V>::Iterator RTListVoiceIterator;
208 typedef typename Pool<V>::Iterator PoolVoiceIterator;
209
210 /**
211 * Override this class to iterate through all active keys/voices
212 * using ProcessActiveVoices() method.
213 */
214 class VoiceHandler {
215 public:
216 /**
217 * @returns true if the voices on the specified key should be processed
218 * adn false to cancel the processing of the active voices for the
219 * specified key
220 */
221 virtual bool Process(MidiKey* pMidiKey) = 0;
222
223 virtual void Process(RTListVoiceIterator& itVoice) = 0;
224 };
225
226 class VoiceHandlerBase : public VoiceHandler {
227 public:
228 virtual bool Process(MidiKey* pMidiKey) { return true; }
229 virtual void Process(RTListVoiceIterator& itVoice) { }
230 };
231
232 MidiKey* pMIDIKeyInfo; ///< Contains all active voices sorted by MIDI key number and other informations to the respective MIDI key
233
234 MidiKeyboardManager(AbstractEngineChannel* pEngineChannel) {
235 pMIDIKeyInfo = new MidiKey[128];
236 pActiveKeys = new Pool<uint>(128);
237 SoloMode = false;
238 SustainPedal = false;
239 SostenutoPedal = false;
240 for (int i = 0 ; i < 128 ; i++) {
241 RoundRobinIndexes[i] = 0;
242 KeyDown[i] = false;
243
244 // by default use one counter for each key (the
245 // gig engine will change this to one counter per
246 // region)
247 pMIDIKeyInfo[i].pRoundRobinIndex = &RoundRobinIndexes[i];
248 }
249 m_engineChannel = pEngineChannel;
250 m_voicePool = NULL;
251 }
252
253 virtual ~MidiKeyboardManager() {
254 listeners.RemoveAllListeners();
255 if (pActiveKeys) delete pActiveKeys;
256 if (pMIDIKeyInfo) delete[] pMIDIKeyInfo;
257 }
258
259 void Reset() {
260 SoloKey = -1; // no solo key active yet
261
262 // reset key info
263 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
271 pActiveKeys->clear();
272 }
273
274 void AllocateActiveNotesLists(Pool< Note<V> >* pNotePool, Pool<V>* pVoicePool) {
275 DeleteActiveNotesLists();
276
277 m_voicePool = pVoicePool;
278
279 for (uint i = 0; i < 128; i++) {
280 pMIDIKeyInfo[i].pActiveNotes = new RTList< Note<V> >(pNotePool);
281 }
282 }
283
284 void DeleteActiveNotesLists() {
285 for (uint i = 0; i < 128; i++) {
286 if (pMIDIKeyInfo[i].pActiveNotes) {
287 delete pMIDIKeyInfo[i].pActiveNotes;
288 pMIDIKeyInfo[i].pActiveNotes = NULL;
289 }
290 }
291 m_voicePool = NULL;
292 }
293
294 void AllocateEventsLists(Pool<Event>* pEventPool) {
295 DeleteEventsLists();
296
297 for (uint i = 0; i < 128; i++) {
298 pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEventPool);
299 }
300 }
301
302 void DeleteEventsLists() {
303 for (uint i = 0; i < 128; i++) {
304 if (pMIDIKeyInfo[i].pEvents) {
305 delete pMIDIKeyInfo[i].pEvents;
306 pMIDIKeyInfo[i].pEvents = NULL;
307 }
308 }
309 }
310
311 /*void ClearAllActiveKeyEvents() {
312 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
313 RTList<uint>::Iterator end = pActiveKeys->end();
314 for(; iuiKey != end; ++iuiKey) {
315 pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key
316 }
317 }*/
318
319 /**
320 * Make sure the passed MIDI key is part of the list of active keys,
321 * if it is not already, then add it to that list. Accordingly it is
322 * safe to call this method even if the requested key is already
323 * marked as active.
324 */
325 void markKeyAsActive(MidiKey* pKey) {
326 if (!pKey->Active) { // mark as active key
327 pKey->Active = true;
328 pKey->itSelf = pActiveKeys->allocAppend();
329 const int iKey = pKey - &pMIDIKeyInfo[0];
330 *pKey->itSelf = iKey;
331 }
332 }
333
334 /**
335 * Removes the given voice from the MIDI key's list of active voices.
336 * This method will be called when a voice went inactive, e.g. because
337 * it finished to playback its sample, finished its release stage or
338 * just was killed.
339 *
340 * @param itVoice - points to the voice to be freed
341 */
342 void FreeVoice(PoolVoiceIterator& itVoice) {
343 if (itVoice) {
344 //MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey];
345
346 // if the sample and dimension region belong to an
347 // instrument that is unloaded, tell the disk thread to
348 // release them
349 if (itVoice->Orphan) {
350 if(itVoice->pDiskThread != NULL) {
351 itVoice->pDiskThread->OrderDeletionOfRegion(itVoice->GetRegion());
352 }
353 }
354
355 // free the voice object
356 m_voicePool->free(itVoice);
357 }
358 else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush;
359 }
360
361 /**
362 * Called when there's no more voice left on a key, this call will
363 * update the key info respectively.
364 *
365 * @param pEngineChannel - engine channel on which this event occured on
366 * @param pKey - key which is now inactive
367 */
368 void FreeKey(MidiKey* pKey) {
369 if (pKey->pActiveNotes->isEmpty()) {
370 if (m_engineChannel->pScript)
371 m_engineChannel->pScript->pKeyEvents[pKey->itSelf]->clear();
372 pKey->Active = false;
373 pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
374 pKey->itSelf = RTList<uint>::Iterator();
375 pKey->ReleaseTrigger = release_trigger_none;
376 pKey->pEvents->clear();
377 dmsg(3,("Key has no more voices now\n"));
378 }
379 else dmsg(1,("MidiKeyboardManager: Oops, tried to free a key which contains voices.\n"));
380 }
381
382 /**
383 * Free all keys which have no active voices left
384 */
385 void FreeAllInactiveKeys() {
386 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
387 RTList<uint>::Iterator end = pActiveKeys->end();
388 while (iuiKey != end) { // iterate through all active keys
389 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
390 ++iuiKey;
391 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
392 itNotesEnd = pKey->pActiveNotes->end();
393 itNote != itNotesEnd; ++itNote)
394 { // iterate over all active notes on that key ...
395 if (itNote->pActiveVoices->isEmpty()) { // free note ...
396 itNote->reset();
397 pKey->pActiveNotes->free(itNote);
398 }
399 #if CONFIG_DEVMODE
400 else { // just a sanity check for debugging
401 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
402 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
403 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
404 if (itVoice->itKillEvent) {
405 dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n"));
406 }
407 }
408 }
409 #endif // CONFIG_DEVMODE
410 }
411 if (pKey->pActiveNotes->isEmpty()) FreeKey(pKey);
412 }
413 }
414
415 int StealVoice (
416 Pool<Event>::Iterator& itNoteOnEvent,
417 RTListVoiceIterator* LastStolenVoice,
418 RTListNoteIterator* LastStolenNote,
419 RTList<uint>::Iterator* LastStolenKey
420 ) {
421 RTListVoiceIterator itSelectedVoice;
422
423 // Select one voice for voice stealing
424 switch (CONFIG_VOICE_STEAL_ALGO) {
425
426 // try to pick the oldest voice on the key where the new
427 // voice should be spawned, if there is no voice on that
428 // key, or no voice left to kill, then procceed with
429 // 'oldestkey' algorithm
430 case voice_steal_algo_oldestvoiceonkey: {
431 MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
432 for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(),
433 itNotesEnd = pSelectedKey->pActiveNotes->end();
434 itNote != itNotesEnd; ++itNote)
435 {
436 for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice)
437 if (itSelectedVoice->IsStealable()) // proceed iterating if voice was created in this audio fragment cycle
438 goto voiceFound; // selection succeeded
439 }
440 // if we haven't found a voice then proceed with algorithm 'oldestkey' ...
441 } // no break - intentional !
442
443 // try to pick the oldest voice on the oldest active key
444 // from the same engine channel
445 // (caution: must stay after 'oldestvoiceonkey' algorithm !)
446 case voice_steal_algo_oldestkey: {
447 // if we already stole in this fragment, try to proceed to steal on same note
448 if (*LastStolenVoice) {
449 itSelectedVoice = *LastStolenVoice;
450 do {
451 ++itSelectedVoice;
452 } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
453 // found a "stealable" voice ?
454 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
455 // remember which voice we stole, so we can simply proceed on next voice stealing
456 *LastStolenVoice = itSelectedVoice;
457 break; // selection succeeded
458 }
459 }
460
461 // get (next) oldest note
462 if (*LastStolenNote) {
463 for (RTListNoteIterator itNote = ++(*LastStolenNote);
464 itNote; ++itNote)
465 {
466 for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
467 // proceed iterating if voice was created in this audio fragment cycle
468 if (itSelectedVoice->IsStealable()) {
469 // remember which voice on which note we stole, so we can simply proceed on next voice stealing
470 *LastStolenNote = itNote;
471 *LastStolenVoice = itSelectedVoice;
472 goto voiceFound; // selection succeeded
473 }
474 }
475 }
476 }
477
478 // get (next) oldest key
479 RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first();
480 for (; iuiSelectedKey; ++iuiSelectedKey) {
481 MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey];
482
483 for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(),
484 itNotesEnd = pSelectedKey->pActiveNotes->end();
485 itNote != itNotesEnd; ++itNote)
486 {
487 for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
488 // proceed iterating if voice was created in this audio fragment cycle
489 if (itSelectedVoice->IsStealable()) {
490 // remember which voice on which key we stole, so we can simply proceed on next voice stealing
491 *LastStolenKey = iuiSelectedKey;
492 *LastStolenNote = itNote;
493 *LastStolenVoice = itSelectedVoice;
494 goto voiceFound; // selection succeeded
495 }
496 }
497 }
498 }
499 break;
500 }
501
502 // don't steal anything
503 case voice_steal_algo_none:
504 default: {
505 dmsg(1,("No free voice (voice stealing disabled)!\n"));
506 return -1;
507 }
508 }
509
510 voiceFound:
511
512 if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1;
513
514 #if CONFIG_DEVMODE
515 if (!itSelectedVoice->IsActive()) {
516 dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));
517 return -1;
518 }
519 #endif // CONFIG_DEVMODE
520
521 // now kill the selected voice
522 itSelectedVoice->Kill(itNoteOnEvent);
523
524 return 0;
525 }
526
527 /**
528 * Releases all voices. All voices will go into
529 * the release stage and thus it might take some time (e.g. dependant to
530 * their envelope release time) until they actually die.
531 *
532 * @param itReleaseEvent - event which caused this releasing of all voices
533 */
534 void ReleaseAllVoices(Pool<Event>::Iterator& itReleaseEvent) {
535 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
536 while (iuiKey) {
537 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
538 ++iuiKey;
539 // append a 'release' event to the key's own event list
540 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
541 if (itNewEvent) {
542 *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list)
543 itNewEvent->Type = Event::type_release_key; // transform event type
544 }
545 else dmsg(1,("Event pool emtpy!\n"));
546 }
547 }
548
549 /**
550 * Kill all active voices.
551 * @returns The number of voices.
552 */
553 int KillAllVoices(Pool<Event>::Iterator& itKillEvent) {
554 int count = 0;
555
556 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
557 RTList<uint>::Iterator end = pActiveKeys->end();
558 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
559 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
560
561 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
562 itNotesEnd = pKey->pActiveNotes->end();
563 itNote != itNotesEnd; ++itNote)
564 {
565 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
566 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
567 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
568 itVoice->Kill(itKillEvent);
569 count++;
570 }
571 }
572 }
573
574 return count;
575 }
576
577 /**
578 * Kill all voices the *die hard* way.
579 * @returns The number of pending stream deletions
580 */
581 int KillAllVoicesImmediately() {
582 int iPendingStreamDeletions = 0;
583
584 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
585 RTList<uint>::Iterator end = pActiveKeys->end();
586 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
587 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
588
589 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
590 itNotesEnd = pKey->pActiveNotes->end();
591 itNote != itNotesEnd; ++itNote)
592 {
593 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
594 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
595 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
596 // request a notification from disk thread side for stream deletion
597 const Stream::Handle hStream = itVoice->KillImmediately(true);
598 if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
599 iPendingStreamDeletions++;
600 }
601 // free the voice to the voice pool and update key info
602 itVoice->VoiceFreed();
603 FreeVoice(itVoice);
604 }
605 }
606 }
607
608 return iPendingStreamDeletions;
609 }
610
611 /**
612 * Mark all currently active voices as "orphans", which means that the regions and
613 * samples they use should be released to the instrument manager when the voices die.
614 */
615 void MarkAllActiveVoicesAsOrphans() {
616 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
617 RTList<uint>::Iterator end = pActiveKeys->end();
618 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
619 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
620
621 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
622 itNotesEnd = pKey->pActiveNotes->end();
623 itNote != itNotesEnd; ++itNote)
624 {
625 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
626 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
627 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
628 itVoice->Orphan = true;
629 }
630 }
631 }
632 }
633
634 void ProcessActiveVoices(VoiceHandler* pVoiceHandler) {
635 if (pVoiceHandler == NULL) return;
636
637 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
638 RTList<uint>::Iterator end = pActiveKeys->end();
639 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
640 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
641 if (!pVoiceHandler->Process(pKey)) continue;
642
643 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
644 itNotesEnd = pKey->pActiveNotes->end();
645 itNote != itNotesEnd; ++itNote)
646 {
647 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
648 RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
649 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
650 pVoiceHandler->Process(itVoice);
651 }
652 }
653 }
654 }
655
656 /**
657 * Recalculate the pitch of all active voices.
658 */
659 void OnScaleTuningChanged() {
660 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
661 for (; iuiKey; ++iuiKey) {
662 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
663
664 for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
665 itNotesEnd = pKey->pActiveNotes->end();
666 itNote != itNotesEnd; ++itNote)
667 {
668 RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
669 for (; itVoice; ++itVoice) {
670 itVoice->onScaleTuningChanged();
671 }
672 }
673 }
674 }
675
676 void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) {
677 // Cancel release process of all voices
678 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
679 for (; iuiKey; ++iuiKey) {
680 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
681 if (!pKey->KeyPressed) {
682 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
683 if (itNewEvent) {
684 *itNewEvent = *itEvent; // copy event to the key's own event list
685 itNewEvent->Type = Event::type_cancel_release_key; // transform event type
686 }
687 else dmsg(1,("Event pool emtpy!\n"));
688 }
689 }
690 }
691
692 void ProcessSustainPedalUp(Pool<Event>::Iterator& itEvent) {
693 // release voices if their respective key is not pressed
694 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
695 for (; iuiKey; ++iuiKey) {
696 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
697 if (!pKey->KeyPressed &&
698 (pKey->ReleaseTrigger & release_trigger_sustain) &&
699 ShouldReleaseVoice(*iuiKey))
700 {
701 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
702 if (itNewEvent) {
703 *itNewEvent = *itEvent; // copy event to the key's own event list
704 itNewEvent->Type = Event::type_release_key; // transform event type
705 itNewEvent->Param.Note.Key = *iuiKey;
706 if (pKey->ReleaseTrigger & release_trigger_sustain_maxvelocity)
707 itNewEvent->Param.Note.Velocity = 127;
708 else // release_trigger_sustain_keyvelocity ...
709 itNewEvent->Param.Note.Velocity = pKey->Velocity;
710
711 //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
712 AbstractEngineChannel* pChannel = (AbstractEngineChannel*) itEvent->pEngineChannel;
713 const int8_t CC64Value = pChannel->ControllerTable[64];
714 pChannel->ControllerTable[64] = 127;
715
716 // now spawn release trigger voices (if required)
717 ProcessReleaseTriggerBySustain(itNewEvent);
718
719 //HACK: reset sustain pedal CC value to old one (see comment above)
720 pChannel->ControllerTable[64] = CC64Value;
721 }
722 else dmsg(1,("Event pool emtpy!\n"));
723 }
724 }
725 }
726
727 /**
728 * Whether @a key is still kept active due to sostenuto pedal usage.
729 *
730 * @param key - note number of key
731 */
732 inline bool SostenutoActiveOnKey(int key) const {
733 if (SostenutoPedal) {
734 for (int i = 0; i < SostenutoKeyCount; i++)
735 if (key == SostenutoKeys[i]) return true;
736 }
737 return false;
738 }
739
740 /**
741 * Determines whether the specified voice should be released.
742 *
743 * @param pEngineChannel - The engine channel on which the voice should be checked
744 * @param Key - The key number
745 * @returns true if the specified voice should be released, false otherwise.
746 */
747 bool ShouldReleaseVoice(int Key) {
748 if (SustainPedal) return false;
749 if (SostenutoActiveOnKey(Key)) return false;
750 return true;
751 }
752
753 void ProcessSostenutoPedalDown() {
754 SostenutoKeyCount = 0;
755 // Remeber the pressed keys
756 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
757 for (; iuiKey; ++iuiKey) {
758 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
759 if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
760 }
761 }
762
763 void ProcessSostenutoPedalUp(Pool<Event>::Iterator& itEvent) {
764 // release voices if the damper pedal is up and their respective key is not pressed
765 for (int i = 0; i < SostenutoKeyCount; i++) {
766 MidiKey* pKey = &pMIDIKeyInfo[SostenutoKeys[i]];
767 if (!pKey->KeyPressed && !SustainPedal) {
768 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
769 if (itNewEvent) {
770 *itNewEvent = *itEvent; // copy event to the key's own event list
771 itNewEvent->Type = Event::type_release_key; // transform event type
772 }
773 else dmsg(1,("Event pool emtpy!\n"));
774 }
775 }
776 }
777
778 void AddMidiKeyboardListener(MidiKeyboardListener* l) { listeners.AddListener(l); }
779
780 void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); }
781
782 protected:
783 AbstractEngineChannel* m_engineChannel;
784 Pool<V>* m_voicePool;
785
786 class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> {
787 public:
788 REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t)
789 REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOn, uint8_t, uint8_t)
790 REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOff, uint8_t, uint8_t)
791 REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOff, uint8_t, uint8_t)
792 REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalUp)
793 REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalUp)
794 REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalDown)
795 REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalDown)
796 REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalUp)
797 REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalUp)
798 REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalDown)
799 REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalDown)
800 } listeners;
801 };
802 } // namespace LinuxSampler
803
804 #endif /* __LS_MIDIKEYBOARDMANAGER_H__ */

  ViewVC Help
Powered by ViewVC