/[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 2121 - (show annotations) (download) (as text)
Tue Sep 14 17:09:08 2010 UTC (8 years, 1 month ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 32200 byte(s)
* implemented Roland GS NRPN 1ArrH which allows to set volume per note
* implemented Roland GS NRPN 1CrrH which allows to set pan per note
* implemented Roland GS NRPN 1DrrH which allows to set reverb send per
  note (in this implementation of the sampler its simply hard routed to
  the 1st effect send of the sampler channel, no matter what the actual
  effect type is)
* implemented Roland GS NRPN 1ErrH which allows to set chorus send per
  note (in this implementation of the sampler its simply hard routed to
  the 2nd effect send of the sampler channel, no matter what the actual
  effect type is)
* bumped version to 1.0.0cvs4

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

  ViewVC Help
Powered by ViewVC