/[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 2244 - (show annotations) (download) (as text)
Thu Aug 18 11:32:33 2011 UTC (12 years, 8 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 32640 byte(s)
* sfz engine: use common pool of CC objects to minimize RAM usage

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
34 namespace LinuxSampler {
35
36 /**
37 * This class is used as a listener, which is notified
38 * when MIDI keyboard events occur like note on, note off, etc.
39 * Note that all events are triggered even when the channel is muted
40 */
41 class MidiKeyboardListener {
42 public:
43 /** Called before the engine start processing the note on event */
44 virtual void PreProcessNoteOn(uint8_t key, uint8_t velocity) = 0;
45
46 /** Called after the engine has processed the note on event */
47 virtual void PostProcessNoteOn(uint8_t key, uint8_t velocity) = 0;
48
49 /** Called before the engine start processing the note off event */
50 virtual void PreProcessNoteOff(uint8_t key, uint8_t velocity) = 0;
51
52 /** Called after the engine has processed the note off event */
53 virtual void PostProcessNoteOff(uint8_t key, uint8_t velocity) = 0;
54
55 /** Called before the engine start processing the sustain pedal up event */
56 virtual void PreProcessSustainPedalUp() = 0;
57
58 /** Called after the engine has processed the sustain pedal up event */
59 virtual void PostProcessSustainPedalUp() = 0;
60
61 /** Called before the engine start processing the sustain pedal down event */
62 virtual void PreProcessSustainPedalDown() = 0;
63
64 /** Called after the engine has processed the sustain pedal down event */
65 virtual void PostProcessSustainPedalDown() = 0;
66
67 /** Called before the engine start processing the sostenuto pedal up event */
68 virtual void PreProcessSostenutoPedalUp() = 0;
69
70 /** Called after the engine has processed the sostenuto pedal up event */
71 virtual void PostProcessSostenutoPedalUp() = 0;
72
73 /** Called before the engine start processing the sostenuto pedal down event */
74 virtual void PreProcessSostenutoPedalDown() = 0;
75
76 /** Called after the engine has processed the sostenuto pedal down event */
77 virtual void PostProcessSostenutoPedalDown() = 0;
78 };
79
80 /**
81 * This class exists as convenience for creating listener objects.
82 * The methods in this class are empty.
83 */
84 class MidiKeyboardAdapter : public MidiKeyboardListener {
85 public:
86 virtual void PreProcessNoteOn(uint8_t key, uint8_t velocity) { }
87 virtual void PostProcessNoteOn(uint8_t key, uint8_t velocity) { }
88 virtual void PreProcessNoteOff(uint8_t key, uint8_t velocity) { }
89 virtual void PostProcessNoteOff(uint8_t key, uint8_t velocity) { }
90 virtual void PreProcessSustainPedalUp() { }
91 virtual void PostProcessSustainPedalUp() { }
92 virtual void PreProcessSustainPedalDown() { }
93 virtual void PostProcessSustainPedalDown() { }
94 virtual void PreProcessSostenutoPedalUp() { }
95 virtual void PostProcessSostenutoPedalUp() { }
96 virtual void PreProcessSostenutoPedalDown() { }
97 virtual void PostProcessSostenutoPedalDown() { }
98 };
99
100 /**
101 * This is the base class for class MidiKeyboardManager::MidiKey. It is
102 * not intended to be instantiated directly. Instead it just defines
103 * the part of class MidiKey which is not dependant on a C++ template
104 * parameter.
105 */
106 class MidiKeyBase {
107 public:
108 bool KeyPressed; ///< Is true if the respective MIDI key is currently pressed.
109 bool Active; ///< If the key contains active voices.
110 bool ReleaseTrigger; ///< If we have to launch release triggered voice(s) when the key is released
111 Pool<uint>::Iterator itSelf; ///< hack to allow fast deallocation of the key from the list of active keys
112 RTList<Event>* pEvents; ///< Key specific events (only Note-on, Note-off and sustain pedal currently)
113 int VoiceTheftsQueued; ///< Amount of voices postponed due to shortage of voices.
114 uint32_t* pRoundRobinIndex; ///< For the round robin dimension: current articulation for this key, will be incremented for each note on
115 uint8_t Velocity; ///< Latest Note-on velocity for this key
116 unsigned long NoteOnTime; ///< Time for latest Note-on event for this key
117 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())
118 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())
119 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())
120 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())
121 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())
122 };
123
124 template <class V>
125 class MidiKeyboardManager {
126 public:
127 /** @brief Voice Stealing Algorithms
128 *
129 * Enumeration of all possible voice stealing algorithms.
130 */
131 enum voice_steal_algo_t {
132 voice_steal_algo_none, ///< Voice stealing disabled.
133 voice_steal_algo_oldestvoiceonkey, ///< Try to kill the oldest voice from same key where the new voice should be spawned.
134 voice_steal_algo_oldestkey ///< Try to kill the oldest voice from the oldest active key.
135 };
136
137
138 /** @brief MIDI key runtime informations
139 *
140 * Reflects runtime informations for one MIDI key.
141 */
142 class MidiKey : public MidiKeyBase {
143 public:
144 RTList<V>* pActiveVoices; ///< Contains the active voices associated with the MIDI key.
145
146 MidiKey() {
147 pActiveVoices = NULL;
148 KeyPressed = false;
149 Active = false;
150 ReleaseTrigger = false;
151 pEvents = NULL;
152 VoiceTheftsQueued = 0;
153 Volume = 1.0f;
154 PanLeft = 1.0f;
155 PanRight = 1.0f;
156 }
157
158 void Reset() {
159 if (pActiveVoices) {
160 RTListVoiceIterator itVoice = pActiveVoices->first();
161 RTListVoiceIterator itVoicesEnd = pActiveVoices->end();
162 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
163 itVoice->VoiceFreed();
164 }
165 pActiveVoices->clear();
166 }
167 if (pEvents) pEvents->clear();
168 KeyPressed = false;
169 Active = false;
170 ReleaseTrigger = false;
171 itSelf = Pool<uint>::Iterator();
172 VoiceTheftsQueued = 0;
173 Volume = 1.0f;
174 PanLeft = 1.0f;
175 PanRight = 1.0f;
176 ReverbSend = optional<float>::nothing;
177 ChorusSend = optional<float>::nothing;
178 }
179 };
180
181 typedef typename RTList<V>::Iterator RTListVoiceIterator;
182 typedef typename Pool<V>::Iterator PoolVoiceIterator;
183
184 /**
185 * Override this class to iterate through all active keys/voices
186 * using ProcessActiveVoices() method.
187 */
188 class VoiceHandler {
189 public:
190 /**
191 * @returns true if the voices on the specified key should be processed
192 * adn false to cancel the processing of the active voices for the
193 * specified key
194 */
195 virtual bool Process(MidiKey* pMidiKey) = 0;
196
197 virtual void Process(RTListVoiceIterator& itVoice) = 0;
198 };
199
200 class VoiceHandlerBase : public VoiceHandler {
201 public:
202 virtual bool Process(MidiKey* pMidiKey) { return true; }
203 virtual void Process(RTListVoiceIterator& itVoice) { }
204 };
205
206 MidiKey* pMIDIKeyInfo; ///< Contains all active voices sorted by MIDI key number and other informations to the respective MIDI key
207 Pool<uint>* pActiveKeys; ///< Holds all keys in it's allocation list with active voices.
208 bool SoloMode; ///< in Solo Mode we only play one voice (group) at a time
209 int SoloKey; ///< Currently 'active' solo key, that is the key to which the currently sounding voice belongs to (only if SoloMode is enabled)
210 bool SustainPedal; ///< true if sustain pedal is down
211 bool SostenutoPedal; ///< true if sostenuto pedal is down
212 int SostenutoKeys[128];
213 int SostenutoKeyCount;
214 uint32_t RoundRobinIndexes[128];
215
216 MidiKeyboardManager() {
217 pMIDIKeyInfo = new MidiKey[128];
218 pActiveKeys = new Pool<uint>(128);
219 SoloMode = false;
220 SustainPedal = false;
221 SostenutoPedal = false;
222 for (int i = 0 ; i < 128 ; i++) {
223 RoundRobinIndexes[i] = 0;
224
225 // by default use one counter for each key (the
226 // gig engine will change this to one counter per
227 // region)
228 pMIDIKeyInfo[i].pRoundRobinIndex = &RoundRobinIndexes[i];
229 }
230 }
231
232 virtual ~MidiKeyboardManager() {
233 listeners.RemoveAllListeners();
234 if (pActiveKeys) delete pActiveKeys;
235 if (pMIDIKeyInfo) delete[] pMIDIKeyInfo;
236 }
237
238 void Reset() {
239 SoloKey = -1; // no solo key active yet
240
241 // reset key info
242 for (uint i = 0; i < 128; i++) pMIDIKeyInfo[i].Reset();
243
244 // free all active keys
245 pActiveKeys->clear();
246 }
247
248 void AllocateActiveVoices(Pool<V>* pVoicePool) {
249 DeleteActiveVoices();
250
251 for (uint i = 0; i < 128; i++) {
252 pMIDIKeyInfo[i].pActiveVoices = new RTList<V>(pVoicePool);
253 }
254 }
255
256 void DeleteActiveVoices() {
257 for (uint i = 0; i < 128; i++) {
258 if (pMIDIKeyInfo[i].pActiveVoices) {
259 delete pMIDIKeyInfo[i].pActiveVoices;
260 pMIDIKeyInfo[i].pActiveVoices = NULL;
261 }
262 }
263 }
264
265 void AllocateEvents(Pool<Event>* pEventPool) {
266 DeleteEvents();
267
268 for (uint i = 0; i < 128; i++) {
269 pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEventPool);
270 }
271 }
272
273 void DeleteEvents() {
274 for (uint i = 0; i < 128; i++) {
275 if (pMIDIKeyInfo[i].pEvents) {
276 delete pMIDIKeyInfo[i].pEvents;
277 pMIDIKeyInfo[i].pEvents = NULL;
278 }
279 }
280 }
281
282 void ClearAllActiveKeyEvents() {
283 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
284 RTList<uint>::Iterator end = pActiveKeys->end();
285 for(; iuiKey != end; ++iuiKey) {
286 pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key
287 }
288 }
289
290 /**
291 * Removes the given voice from the MIDI key's list of active voices.
292 * This method will be called when a voice went inactive, e.g. because
293 * it finished to playback its sample, finished its release stage or
294 * just was killed.
295 *
296 * @param itVoice - points to the voice to be freed
297 */
298 void FreeVoice(PoolVoiceIterator& itVoice) {
299 if (itVoice) {
300 MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey];
301
302 // if the sample and dimension region belong to an
303 // instrument that is unloaded, tell the disk thread to
304 // release them
305 if (itVoice->Orphan) {
306 if(itVoice->pDiskThread != NULL) {
307 itVoice->pDiskThread->OrderDeletionOfRegion(itVoice->GetRegion());
308 }
309 }
310
311 // free the voice object
312 pKey->pActiveVoices->free(itVoice);
313 }
314 else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush;
315 }
316
317 /**
318 * Called when there's no more voice left on a key, this call will
319 * update the key info respectively.
320 *
321 * @param pEngineChannel - engine channel on which this event occured on
322 * @param pKey - key which is now inactive
323 */
324 void FreeKey(MidiKey* pKey) {
325 if (pKey->pActiveVoices->isEmpty()) {
326 pKey->Active = false;
327 pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
328 pKey->itSelf = RTList<uint>::Iterator();
329 pKey->ReleaseTrigger = false;
330 pKey->pEvents->clear();
331 dmsg(3,("Key has no more voices now\n"));
332 }
333 else dmsg(1,("MidiKeyboardManager: Oops, tried to free a key which contains voices.\n"));
334 }
335
336 /**
337 * Free all keys which have no active voices left
338 */
339 void FreeAllInactiveKyes() {
340 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
341 RTList<uint>::Iterator end = pActiveKeys->end();
342 while (iuiKey != end) { // iterate through all active keys
343 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
344 ++iuiKey;
345 if (pKey->pActiveVoices->isEmpty()) FreeKey(pKey);
346 #if CONFIG_DEVMODE
347 else { // just a sanity check for debugging
348 RTListVoiceIterator itVoice = pKey->pActiveVoices->first();
349 RTListVoiceIterator = pKey->pActiveVoices->end();
350 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
351 if (itVoice->itKillEvent) {
352 dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n"));
353 }
354 }
355 }
356 #endif // CONFIG_DEVMODE
357 }
358 }
359
360 int StealVoice (
361 Pool<Event>::Iterator& itNoteOnEvent,
362 RTListVoiceIterator* LastStolenVoice,
363 RTList<uint>::Iterator* LastStolenKey
364 ) {
365 RTListVoiceIterator itSelectedVoice;
366
367 // Select one voice for voice stealing
368 switch (CONFIG_VOICE_STEAL_ALGO) {
369
370 // try to pick the oldest voice on the key where the new
371 // voice should be spawned, if there is no voice on that
372 // key, or no voice left to kill, then procceed with
373 // 'oldestkey' algorithm
374 case voice_steal_algo_oldestvoiceonkey: {
375 MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
376 itSelectedVoice = pSelectedKey->pActiveVoices->first();
377 // proceed iterating if voice was created in this fragment cycle
378 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
379 // if we haven't found a voice then proceed with algorithm 'oldestkey'
380 if (itSelectedVoice && itSelectedVoice->IsStealable()) break;
381 } // no break - intentional !
382
383 // try to pick the oldest voice on the oldest active key
384 // from the same engine channel
385 // (caution: must stay after 'oldestvoiceonkey' algorithm !)
386 case voice_steal_algo_oldestkey: {
387 // if we already stole in this fragment, try to proceed on same key
388 if (*LastStolenVoice) {
389 itSelectedVoice = *LastStolenVoice;
390 do {
391 ++itSelectedVoice;
392 } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
393 // found a "stealable" voice ?
394 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
395 // remember which voice we stole, so we can simply proceed on next voice stealing
396 *LastStolenVoice = itSelectedVoice;
397 break; // selection succeeded
398 }
399 }
400 // get (next) oldest key
401 RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first();
402 while (iuiSelectedKey) {
403 MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey];
404 itSelectedVoice = pSelectedKey->pActiveVoices->first();
405 // proceed iterating if voice was created in this fragment cycle
406 while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
407 // found a "stealable" voice ?
408 if (itSelectedVoice && itSelectedVoice->IsStealable()) {
409 // remember which voice on which key we stole, so we can simply proceed on next voice stealing
410 *LastStolenKey = iuiSelectedKey;
411 *LastStolenVoice = itSelectedVoice;
412 break; // selection succeeded
413 }
414 ++iuiSelectedKey; // get next oldest key
415 }
416 break;
417 }
418
419 // don't steal anything
420 case voice_steal_algo_none:
421 default: {
422 dmsg(1,("No free voice (voice stealing disabled)!\n"));
423 return -1;
424 }
425 }
426
427 if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1;
428
429 #if CONFIG_DEVMODE
430 if (!itSelectedVoice->IsActive()) {
431 dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));
432 return -1;
433 }
434 #endif // CONFIG_DEVMODE
435
436 // now kill the selected voice
437 itSelectedVoice->Kill(itNoteOnEvent);
438
439 return 0;
440 }
441
442 /**
443 * Releases all voices. All voices will go into
444 * the release stage and thus it might take some time (e.g. dependant to
445 * their envelope release time) until they actually die.
446 *
447 * @param itReleaseEvent - event which caused this releasing of all voices
448 */
449 void ReleaseAllVoices(Pool<Event>::Iterator& itReleaseEvent) {
450 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
451 while (iuiKey) {
452 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
453 ++iuiKey;
454 // append a 'release' event to the key's own event list
455 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
456 if (itNewEvent) {
457 *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list)
458 itNewEvent->Type = Event::type_release; // transform event type
459 }
460 else dmsg(1,("Event pool emtpy!\n"));
461 }
462 }
463 /**
464 * Kill all active voices.
465 * @returns The number of voices.
466 */
467 int KillAllVoices(Pool<Event>::Iterator& itKillEvent) {
468 int count = 0;
469
470 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
471 RTList<uint>::Iterator end = pActiveKeys->end();
472 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
473 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
474 RTListVoiceIterator itVoice = pKey->pActiveVoices->first();
475 RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();
476 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
477 itVoice->Kill(itKillEvent);
478 count++;
479 }
480 }
481
482 return count;
483 }
484
485 /**
486 * Kill all voices the *die hard* way.
487 * @returns The number of pending stream deletions
488 */
489 int KillAllVoicesImmediately() {
490 int iPendingStreamDeletions = 0;
491
492 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
493 RTList<uint>::Iterator end = pActiveKeys->end();
494 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
495 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
496 RTListVoiceIterator itVoice = pKey->pActiveVoices->first();
497 RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();
498 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
499 // request a notification from disk thread side for stream deletion
500 const Stream::Handle hStream = itVoice->KillImmediately(true);
501 if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
502 iPendingStreamDeletions++;
503 }
504 // free the voice to the voice pool and update key info
505 itVoice->VoiceFreed();
506 FreeVoice(itVoice);
507 }
508 }
509
510 return iPendingStreamDeletions;
511 }
512
513 /**
514 * Mark all currently active voices as "orphans", which means that the regions and
515 * samples they use should be released to the instrument manager when the voices die.
516 */
517 void MarkAllActiveVoicesAsOrphans() {
518 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
519 RTList<uint>::Iterator end = pActiveKeys->end();
520 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
521 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
522 RTListVoiceIterator itVoice = pKey->pActiveVoices->first();
523 RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();
524 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
525 itVoice->Orphan = true;
526 }
527 }
528 }
529
530 void ProcessActiveVoices(VoiceHandler* pVoiceHandler) {
531 if (pVoiceHandler == NULL) return;
532
533 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
534 RTList<uint>::Iterator end = pActiveKeys->end();
535 for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
536 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
537 if (!pVoiceHandler->Process(pKey)) continue;
538
539 RTListVoiceIterator itVoice = pKey->pActiveVoices->first();
540 RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();
541 for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
542 pVoiceHandler->Process(itVoice);
543 }
544 }
545 }
546
547 void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) {
548 // Cancel release process of all voices
549 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
550 for (; iuiKey; ++iuiKey) {
551 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
552 if (!pKey->KeyPressed) {
553 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
554 if (itNewEvent) {
555 *itNewEvent = *itEvent; // copy event to the key's own event list
556 itNewEvent->Type = Event::type_cancel_release; // transform event type
557 }
558 else dmsg(1,("Event pool emtpy!\n"));
559 }
560 }
561 }
562
563 void ProcessSustainPedalUp(Pool<Event>::Iterator& itEvent) {
564 // release voices if their respective key is not pressed
565 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
566 for (; iuiKey; ++iuiKey) {
567 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
568 if (!pKey->KeyPressed && ShouldReleaseVoice(*iuiKey)) {
569 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
570 if (itNewEvent) {
571 *itNewEvent = *itEvent; // copy event to the key's own event list
572 itNewEvent->Type = Event::type_release; // transform event type
573 }
574 else dmsg(1,("Event pool emtpy!\n"));
575 }
576 }
577 }
578
579 /**
580 * Determines whether the specified voice should be released.
581 *
582 * @param pEngineChannel - The engine channel on which the voice should be checked
583 * @param Key - The key number
584 * @returns true if the specified voice should be released, false otherwise.
585 */
586 bool ShouldReleaseVoice(int Key) {
587 if (SustainPedal) return false;
588
589 if (SostenutoPedal) {
590 for (int i = 0; i < SostenutoKeyCount; i++)
591 if (Key == SostenutoKeys[i]) return false;
592 }
593
594 return true;
595 }
596
597 void ProcessSostenutoPedalDown() {
598 SostenutoKeyCount = 0;
599 // Remeber the pressed keys
600 RTList<uint>::Iterator iuiKey = pActiveKeys->first();
601 for (; iuiKey; ++iuiKey) {
602 MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
603 if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
604 }
605 }
606
607 void ProcessSostenutoPedalUp(Pool<Event>::Iterator& itEvent) {
608 // release voices if the damper pedal is up and their respective key is not pressed
609 for (int i = 0; i < SostenutoKeyCount; i++) {
610 MidiKey* pKey = &pMIDIKeyInfo[SostenutoKeys[i]];
611 if (!pKey->KeyPressed && !SustainPedal) {
612 RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
613 if (itNewEvent) {
614 *itNewEvent = *itEvent; // copy event to the key's own event list
615 itNewEvent->Type = Event::type_release; // transform event type
616 }
617 else dmsg(1,("Event pool emtpy!\n"));
618 }
619 }
620 }
621
622 void AddMidiKeyboardListener(MidiKeyboardListener* l) { listeners.AddListener(l); }
623
624 void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); }
625
626 protected:
627 class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> {
628 public:
629 REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t)
630 REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOn, uint8_t, uint8_t)
631 REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOff, uint8_t, uint8_t)
632 REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOff, uint8_t, uint8_t)
633 REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalUp)
634 REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalUp)
635 REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalDown)
636 REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalDown)
637 REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalUp)
638 REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalUp)
639 REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalDown)
640 REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalDown)
641 } listeners;
642 };
643 } // namespace LinuxSampler
644
645 #endif /* __LS_MIDIKEYBOARDMANAGER_H__ */

  ViewVC Help
Powered by ViewVC