/[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 2645 - (show annotations) (download) (as text)
Wed Jun 18 00:14:57 2014 UTC (5 years, 8 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 34546 byte(s)
* RT instrument scripts: Pass/preserve polyphonic variable data
  from respective "note" event handler to "release" event handler.
* Fixed theoretical memory leak regarding instrument scripts.
* Bumped version (1.0.0.svn54).

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

  ViewVC Help
Powered by ViewVC