/[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 2063 - (show annotations) (download) (as text)
Sun Feb 28 07:28:56 2010 UTC (14 years, 1 month ago) by persson
File MIME type: text/x-c++hdr
File size: 31513 byte(s)
* sfz engine: added support for off_mode=normal

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

  ViewVC Help
Powered by ViewVC