/[svn]/linuxsampler/trunk/src/engines/common/MidiKeyboardManager.h
ViewVC logotype

Annotation of /linuxsampler/trunk/src/engines/common/MidiKeyboardManager.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2244 - (hide annotations) (download) (as text)
Thu Aug 18 11:32:33 2011 UTC (7 years, 2 months ago) by iliev
File MIME type: text/x-c++hdr
File size: 32640 byte(s)
* sfz engine: use common pool of CC objects to minimize RAM usage

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

  ViewVC Help
Powered by ViewVC