/[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 2114 - (show annotations) (download) (as text)
Tue Aug 10 12:05:19 2010 UTC (13 years, 8 months ago) by persson
File MIME type: text/x-c++hdr
File size: 30352 byte(s)
* sfz engine: improved support for exclusive groups (group, off_by and
  off_mode)
* minor valgrind fixes

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

  ViewVC Help
Powered by ViewVC