/[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 2613 - (show annotations) (download) (as text)
Tue Jun 10 15:17:01 2014 UTC (9 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 33630 byte(s)
* Implemented built-in script int array variable $KEY_DOWN.
* Bumped version (1.0.0.svn48).

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

  ViewVC Help
Powered by ViewVC