/[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 2012 - (show annotations) (download) (as text)
Fri Oct 23 17:53:17 2009 UTC (14 years, 5 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 30747 byte(s)
* Refactoring: moved the independent code from
  the Gigasampler format engine to base classes
* SFZ format engine: experimental code (not usable yet)
* SoundFont format engine: experimental code (not usable yet)
* Fixed crash which may occur when MIDI key + transpose is out of range

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

  ViewVC Help
Powered by ViewVC