/[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 2063 - (hide annotations) (download) (as text)
Sun Feb 28 07:28:56 2010 UTC (14 years, 1 month ago) by persson
File MIME type: text/x-c++hdr
File size: 31513 byte(s)
* sfz engine: added support for off_mode=normal

1 iliev 2012 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5     * Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck *
6     * Copyright (C) 2005-2009 Christian Schoenebeck *
7     * Copyright (C) 2009 Grigor Iliev *
8     * *
9     * This program is free software; you can redistribute it and/or modify *
10     * it under the terms of the GNU General Public License as published by *
11     * the Free Software Foundation; either version 2 of the License, or *
12     * (at your option) any later version. *
13     * *
14     * This program is distributed in the hope that it will be useful, *
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17     * GNU General Public License for more details. *
18     * *
19     * You should have received a copy of the GNU General Public License *
20     * along with this program; if not, write to the Free Software *
21     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22     * MA 02111-1307 USA *
23     ***************************************************************************/
24    
25     #ifndef __LS_MIDIKEYBOARDMANAGER_H__
26     #define __LS_MIDIKEYBOARDMANAGER_H__
27    
28     #include "Event.h"
29     #include "Stream.h"
30     #include "../../EventListeners.h"
31     #include "../../common/Pool.h"
32     #include "../../common/global_private.h"
33    
34     namespace LinuxSampler {
35    
36     /**
37     * This class is used as a listener, which is notified
38     * when MIDI keyboard events occur like note on, note off, etc.
39     * Note that all events are triggered even when the channel is muted
40     */
41     class MidiKeyboardListener {
42     public:
43     /** Called before the engine start processing the note on event */
44     virtual void PreProcessNoteOn(uint8_t key, uint8_t velocity) = 0;
45    
46     /** Called after the engine has processed the note on event */
47     virtual void PostProcessNoteOn(uint8_t key, uint8_t velocity) = 0;
48    
49     /** Called before the engine start processing the note off event */
50     virtual void PreProcessNoteOff(uint8_t key, uint8_t velocity) = 0;
51    
52     /** Called after the engine has processed the note off event */
53     virtual void PostProcessNoteOff(uint8_t key, uint8_t velocity) = 0;
54    
55     /** Called before the engine start processing the sustain pedal up event */
56     virtual void PreProcessSustainPedalUp() = 0;
57    
58     /** Called after the engine has processed the sustain pedal up event */
59     virtual void PostProcessSustainPedalUp() = 0;
60    
61     /** Called before the engine start processing the sustain pedal down event */
62     virtual void PreProcessSustainPedalDown() = 0;
63    
64     /** Called after the engine has processed the sustain pedal down event */
65     virtual void PostProcessSustainPedalDown() = 0;
66    
67     /** Called before the engine start processing the sostenuto pedal up event */
68     virtual void PreProcessSostenutoPedalUp() = 0;
69    
70     /** Called after the engine has processed the sostenuto pedal up event */
71     virtual void PostProcessSostenutoPedalUp() = 0;
72    
73     /** Called before the engine start processing the sostenuto pedal down event */
74     virtual void PreProcessSostenutoPedalDown() = 0;
75    
76     /** Called after the engine has processed the sostenuto pedal down event */
77     virtual void PostProcessSostenutoPedalDown() = 0;
78     };
79    
80     /**
81     * This class exists as convenience for creating listener objects.
82     * The methods in this class are empty.
83     */
84     class MidiKeyboardAdapter : public MidiKeyboardListener {
85     public:
86     virtual void PreProcessNoteOn(uint8_t key, uint8_t velocity) { }
87     virtual void PostProcessNoteOn(uint8_t key, uint8_t velocity) { }
88     virtual void PreProcessNoteOff(uint8_t key, uint8_t velocity) { }
89     virtual void PostProcessNoteOff(uint8_t key, uint8_t velocity) { }
90     virtual void PreProcessSustainPedalUp() { }
91     virtual void PostProcessSustainPedalUp() { }
92     virtual void PreProcessSustainPedalDown() { }
93     virtual void PostProcessSustainPedalDown() { }
94     virtual void PreProcessSostenutoPedalUp() { }
95     virtual void PostProcessSostenutoPedalUp() { }
96     virtual void PreProcessSostenutoPedalDown() { }
97     virtual void PostProcessSostenutoPedalDown() { }
98     };
99    
100     template <class V>
101     class MidiKeyboardManager {
102     public:
103     /** @brief Voice Stealing Algorithms
104     *
105     * Enumeration of all possible voice stealing algorithms.
106     */
107     enum voice_steal_algo_t {
108     voice_steal_algo_none, ///< Voice stealing disabled.
109     voice_steal_algo_oldestvoiceonkey, ///< Try to kill the oldest voice from same key where the new voice should be spawned.
110     voice_steal_algo_oldestkey ///< Try to kill the oldest voice from the oldest active key.
111     };
112    
113 persson 2043
114 iliev 2012 /** @brief MIDI key runtime informations
115     *
116     * Reflects runtime informations for one MIDI key.
117     */
118     class MidiKey {
119     public:
120     RTList<V>* pActiveVoices; ///< Contains the active voices associated with the MIDI key.
121     bool KeyPressed; ///< Is true if the respective MIDI key is currently pressed.
122     bool Active; ///< If the key contains active voices.
123     bool ReleaseTrigger; ///< If we have to launch release triggered voice(s) when the key is released
124     Pool<uint>::Iterator itSelf; ///< hack to allow fast deallocation of the key from the list of active keys
125     RTList<Event>* pEvents; ///< Key specific events (only Note-on, Note-off and sustain pedal currently)
126     int VoiceTheftsQueued; ///< Amount of voices postponed due to shortage of voices.
127 persson 2043 uint32_t* pRoundRobinIndex; ///< For the round robin dimension: current articulation for this key, will be incremented for each note on
128 iliev 2012 uint8_t Velocity; ///< Latest Note-on velocity for this key
129     unsigned long NoteOnTime; ///< Time for latest Note-on event for this key
130    
131     MidiKey() {
132     pActiveVoices = NULL;
133     KeyPressed = false;
134     Active = false;
135     ReleaseTrigger = false;
136     pEvents = NULL;
137     VoiceTheftsQueued = 0;
138     }
139    
140     void Reset() {
141     if (pActiveVoices) pActiveVoices->clear();
142     if (pEvents) pEvents->clear();
143     KeyPressed = false;
144     Active = false;
145     ReleaseTrigger = false;
146     itSelf = Pool<uint>::Iterator();
147     VoiceTheftsQueued = 0;
148     }
149     };
150    
151     typedef typename RTList<V>::Iterator RTListVoiceIterator;
152     typedef typename Pool<V>::Iterator PoolVoiceIterator;
153    
154     /**
155     * Override this class to iterate through all active keys/voices
156     * using ProcessActiveVoices() method.
157     */
158     class VoiceHandler {
159     public:
160     /**
161     * @returns true if the voices on the specified key should be processed
162     * adn false to cancel the processing of the active voices for the
163     * specified key
164     */
165     virtual bool Process(MidiKey* pMidiKey) = 0;
166    
167     virtual void Process(RTListVoiceIterator& itVoice) = 0;
168     };
169    
170     class VoiceHandlerBase : public VoiceHandler {
171     public:
172     virtual bool Process(MidiKey* pMidiKey) { return true; }
173     virtual void Process(RTListVoiceIterator& itVoice) { }
174     };
175    
176     MidiKey* pMIDIKeyInfo; ///< Contains all active voices sorted by MIDI key number and other informations to the respective MIDI key
177     Pool<uint>* pActiveKeys; ///< Holds all keys in it's allocation list with active voices.
178     std::map<uint,uint*> ActiveKeyGroups; ///< Contains active keys (in case they belong to a key group) ordered by key group ID.
179     bool SoloMode; ///< in Solo Mode we only play one voice (group) at a time
180     int SoloKey; ///< Currently 'active' solo key, that is the key to which the currently sounding voice belongs to (only if SoloMode is enabled)
181     bool SustainPedal; ///< true if sustain pedal is down
182     bool SostenutoPedal; ///< true if sostenuto pedal is down
183     int SostenutoKeys[128];
184     int SostenutoKeyCount;
185 persson 2043 uint32_t RoundRobinIndexes[128];
186 iliev 2012
187     MidiKeyboardManager() {
188     pMIDIKeyInfo = new MidiKey[128];
189     pActiveKeys = new Pool<uint>(128);
190     SoloMode = false;
191     SustainPedal = false;
192     SostenutoPedal = false;
193 persson 2043 for (int i = 0 ; i < 128 ; i++) {
194     RoundRobinIndexes[i] = 0;
195    
196     // by default use one counter for each key (the
197     // gig engine will change this to one counter per
198     // region)
199     pMIDIKeyInfo[i].pRoundRobinIndex = &RoundRobinIndexes[i];
200     }
201 iliev 2012 }
202    
203     virtual ~MidiKeyboardManager() {
204     listeners.RemoveAllListeners();
205     if (pActiveKeys) delete pActiveKeys;
206     if (pMIDIKeyInfo) delete[] pMIDIKeyInfo;
207     }
208    
209     void Reset(){
210     SoloKey = -1; // no solo key active yet
211    
212     // reset all key groups
213     std::map<uint,uint*>::iterator iter = ActiveKeyGroups.begin();
214     for (; iter != ActiveKeyGroups.end(); iter++) iter->second = NULL;
215    
216     // reset key info
217     for (uint i = 0; i < 128; i++) pMIDIKeyInfo[i].Reset();
218    
219     // free all active keys
220     pActiveKeys->clear();
221     }
222    
223     void AllocateActiveVoices(Pool<V>* pVoicePool) {
224     DeleteActiveVoices();
225    
226     for (uint i = 0; i < 128; i++) {
227     pMIDIKeyInfo[i].pActiveVoices = new RTList<V>(pVoicePool);
228     }
229     }
230    
231     void DeleteActiveVoices() {
232     for (uint i = 0; i < 128; i++) {
233     if (pMIDIKeyInfo[i].pActiveVoices) {
234     delete pMIDIKeyInfo[i].pActiveVoices;
235     pMIDIKeyInfo[i].pActiveVoices = NULL;
236     }
237     }
238     }
239    
240     void AllocateEvents(Pool<Event>* pEventPool) {
241     DeleteEvents();
242    
243     for (uint i = 0; i < 128; i++) {
244     pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEventPool);
245     }
246     }
247    
248     void DeleteEvents() {
249     for (uint i = 0; i < 128; i++) {
250     if (pMIDIKeyInfo[i].pEvents) {
251     delete pMIDIKeyInfo[i].pEvents;
252     pMIDIKeyInfo[i].pEvents = NULL;
253     }
254     }
255     }
256    
257     void ClearAllActiveKeyEvents() {
258     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
259     RTList<uint>::Iterator end = pActiveKeys->end();
260     for(; iuiKey != end; ++iuiKey) {
261     pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key
262     }
263     }
264    
265     /**
266     * Removes the given voice from the MIDI key's list of active voices.
267     * This method will be called when a voice went inactive, e.g. because
268     * it finished to playback its sample, finished its release stage or
269     * just was killed.
270     *
271     * @param itVoice - points to the voice to be freed
272     */
273     void FreeVoice(PoolVoiceIterator& itVoice) {
274     if (itVoice) {
275     MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey];
276    
277     uint keygroup = itVoice->KeyGroup;
278    
279     // if the sample and dimension region belong to an
280     // instrument that is unloaded, tell the disk thread to
281     // release them
282     if (itVoice->Orphan) {
283     if(itVoice->pDiskThread != NULL) {
284     itVoice->pDiskThread->OrderDeletionOfRegion(itVoice->GetRegion());
285     }
286     }
287    
288     // free the voice object
289     pKey->pActiveVoices->free(itVoice);
290    
291 persson 2063 // if member of a key group and no other non-release-trigger
292     // voices left, remove from key group
293     if (keygroup) {
294     RTListVoiceIterator it = pKey->pActiveVoices->first();
295     RTListVoiceIterator end = pKey->pActiveVoices->end();
296     for (; it != end ; ++it) {
297     if (it->Type != V::type_release_trigger) break;
298     }
299     if (it == end) {
300     uint** ppKeyGroup = &ActiveKeyGroups[keygroup];
301     if (*ppKeyGroup == &*pKey->itSelf) *ppKeyGroup = NULL; // remove key from key group
302     }
303 iliev 2012 }
304     }
305     else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush;
306     }
307    
308     /**
309     * Called when there's no more voice left on a key, this call will
310     * update the key info respectively.
311     *
312     * @param pEngineChannel - engine channel on which this event occured on
313     * @param pKey - key which is now inactive
314     */
315     void FreeKey(MidiKey* pKey) {
316     if (pKey->pActiveVoices->isEmpty()) {
317     pKey->Active = false;
318     pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
319     pKey->itSelf = RTList<uint>::Iterator();
320     pKey->ReleaseTrigger = false;
321     pKey->pEvents->clear();
322     dmsg(3,("Key has no more voices now\n"));
323     }
324     else dmsg(1,("MidiKeyboardManager: Oops, tried to free a key which contains voices.\n"));
325     }
326    
327     /**
328     * Free all keys which have no active voices left
329     */
330     void FreeAllInactiveKyes() {
331     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
332     RTList<uint>::Iterator end = pActiveKeys->end();
333     while (iuiKey != end) { // iterate through all active keys
334     MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
335     ++iuiKey;
336     if (pKey->pActiveVoices->isEmpty()) FreeKey(pKey);
337     #if CONFIG_DEVMODE
338     else { // just a sanity check for debugging
339     RTListVoiceIterator itVoice = pKey->pActiveVoices->first();
340     RTListVoiceIterator = pKey->pActiveVoices->end();
341     for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
342     if (itVoice->itKillEvent) {
343     dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n"));
344     }
345     }
346     }
347     #endif // CONFIG_DEVMODE
348     }
349     }
350    
351     int StealVoice (
352     Pool<Event>::Iterator& itNoteOnEvent,
353     RTListVoiceIterator* LastStolenVoice,
354     RTList<uint>::Iterator* LastStolenKey
355     ) {
356     RTListVoiceIterator itSelectedVoice;
357    
358     // Select one voice for voice stealing
359     switch (CONFIG_VOICE_STEAL_ALGO) {
360    
361     // try to pick the oldest voice on the key where the new
362     // voice should be spawned, if there is no voice on that
363     // key, or no voice left to kill, then procceed with
364     // 'oldestkey' algorithm
365     case voice_steal_algo_oldestvoiceonkey: {
366     MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
367     itSelectedVoice = pSelectedKey->pActiveVoices->first();
368     // proceed iterating if voice was created in this fragment cycle
369     while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
370     // if we haven't found a voice then proceed with algorithm 'oldestkey'
371     if (itSelectedVoice && itSelectedVoice->IsStealable()) break;
372     } // no break - intentional !
373    
374     // try to pick the oldest voice on the oldest active key
375     // from the same engine channel
376     // (caution: must stay after 'oldestvoiceonkey' algorithm !)
377     case voice_steal_algo_oldestkey: {
378     // if we already stole in this fragment, try to proceed on same key
379     if (*LastStolenVoice) {
380     itSelectedVoice = *LastStolenVoice;
381     do {
382     ++itSelectedVoice;
383     } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
384     // found a "stealable" voice ?
385     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
386     // remember which voice we stole, so we can simply proceed on next voice stealing
387     *LastStolenVoice = itSelectedVoice;
388     break; // selection succeeded
389     }
390     }
391     // get (next) oldest key
392     RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first();
393     while (iuiSelectedKey) {
394     MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey];
395     itSelectedVoice = pSelectedKey->pActiveVoices->first();
396     // proceed iterating if voice was created in this fragment cycle
397     while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
398     // found a "stealable" voice ?
399     if (itSelectedVoice && itSelectedVoice->IsStealable()) {
400     // remember which voice on which key we stole, so we can simply proceed on next voice stealing
401     *LastStolenKey = iuiSelectedKey;
402     *LastStolenVoice = itSelectedVoice;
403     break; // selection succeeded
404     }
405     ++iuiSelectedKey; // get next oldest key
406     }
407     break;
408     }
409    
410     // don't steal anything
411     case voice_steal_algo_none:
412     default: {
413     dmsg(1,("No free voice (voice stealing disabled)!\n"));
414     return -1;
415     }
416     }
417    
418     if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1;
419    
420     #if CONFIG_DEVMODE
421     if (!itSelectedVoice->IsActive()) {
422     dmsg(1,("gig::Engine: ERROR, tried to steal a voice which was not active !!!\n"));
423     return -1;
424     }
425     #endif // CONFIG_DEVMODE
426    
427     // now kill the selected voice
428     itSelectedVoice->Kill(itNoteOnEvent);
429    
430     return 0;
431     }
432    
433     /**
434     * Releases all voices. All voices will go into
435     * the release stage and thus it might take some time (e.g. dependant to
436     * their envelope release time) until they actually die.
437     *
438     * @param itReleaseEvent - event which caused this releasing of all voices
439     */
440     void ReleaseAllVoices(Pool<Event>::Iterator& itReleaseEvent) {
441     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
442     while (iuiKey) {
443     MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
444     ++iuiKey;
445     // append a 'release' event to the key's own event list
446     RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
447     if (itNewEvent) {
448     *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list)
449     itNewEvent->Type = Event::type_release; // transform event type
450     }
451     else dmsg(1,("Event pool emtpy!\n"));
452     }
453     }
454     /**
455     * Kill all active voices.
456     * @returns The number of voices.
457     */
458     int KillAllVoices(Pool<Event>::Iterator& itKillEvent) {
459     int count = 0;
460    
461     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
462     RTList<uint>::Iterator end = pActiveKeys->end();
463     for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
464     MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
465     RTListVoiceIterator itVoice = pKey->pActiveVoices->first();
466     RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();
467     for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
468     itVoice->Kill(itKillEvent);
469     count++;
470     }
471     }
472    
473     return count;
474     }
475    
476     /**
477     * Kill all voices the *die hard* way.
478     * @returns The number of pending stream deletions
479     */
480     int KillAllVoicesImmediately() {
481     int iPendingStreamDeletions = 0;
482    
483     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
484     RTList<uint>::Iterator end = pActiveKeys->end();
485     for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
486     MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
487     RTListVoiceIterator itVoice = pKey->pActiveVoices->first();
488     RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();
489     for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
490     // request a notification from disk thread side for stream deletion
491     const Stream::Handle hStream = itVoice->KillImmediately(true);
492     if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
493     iPendingStreamDeletions++;
494     }
495     // free the voice to the voice pool and update key info
496     FreeVoice(itVoice);
497     }
498     }
499    
500     return iPendingStreamDeletions;
501     }
502    
503     /**
504     * Mark all currently active voices as "orphans", which means that the regions and
505     * samples they use should be released to the instrument manager when the voices die.
506     */
507     void MarkAllActiveVoicesAsOrphans() {
508     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
509     RTList<uint>::Iterator end = pActiveKeys->end();
510     for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
511     MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
512     RTListVoiceIterator itVoice = pKey->pActiveVoices->first();
513     RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();
514     for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
515     itVoice->Orphan = true;
516     }
517     }
518     }
519    
520     void ProcessActiveVoices(VoiceHandler* pVoiceHandler) {
521     if (pVoiceHandler == NULL) return;
522    
523     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
524     RTList<uint>::Iterator end = pActiveKeys->end();
525     for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
526     MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
527     if (!pVoiceHandler->Process(pKey)) continue;
528    
529     RTListVoiceIterator itVoice = pKey->pActiveVoices->first();
530     RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();
531     for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
532     pVoiceHandler->Process(itVoice);
533     }
534     }
535     }
536    
537     void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) {
538     // Cancel release process of all voices
539     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
540     for (; iuiKey; ++iuiKey) {
541     MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
542     if (!pKey->KeyPressed) {
543     RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
544     if (itNewEvent) {
545     *itNewEvent = *itEvent; // copy event to the key's own event list
546     itNewEvent->Type = Event::type_cancel_release; // transform event type
547     }
548     else dmsg(1,("Event pool emtpy!\n"));
549     }
550     }
551     }
552    
553     void ProcessSustainPedalUp(Pool<Event>::Iterator& itEvent) {
554     // release voices if their respective key is not pressed
555     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
556     for (; iuiKey; ++iuiKey) {
557     MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
558     if (!pKey->KeyPressed && ShouldReleaseVoice(*iuiKey)) {
559     RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
560     if (itNewEvent) {
561     *itNewEvent = *itEvent; // copy event to the key's own event list
562     itNewEvent->Type = Event::type_release; // transform event type
563     }
564     else dmsg(1,("Event pool emtpy!\n"));
565     }
566     }
567     }
568    
569     /**
570     * Determines whether the specified voice should be released.
571     *
572     * @param pEngineChannel - The engine channel on which the voice should be checked
573     * @param Key - The key number
574     * @returns true if the specified voice should be released, false otherwise.
575     */
576     bool ShouldReleaseVoice(int Key) {
577     if (SustainPedal) return false;
578    
579     if (SostenutoPedal) {
580     for (int i = 0; i < SostenutoKeyCount; i++)
581     if (Key == SostenutoKeys[i]) return false;
582     }
583    
584     return true;
585     }
586    
587     void ProcessSostenutoPedalDown() {
588     SostenutoKeyCount = 0;
589     // Remeber the pressed keys
590     RTList<uint>::Iterator iuiKey = pActiveKeys->first();
591     for (; iuiKey; ++iuiKey) {
592     MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
593     if (pKey->KeyPressed && SostenutoKeyCount < 128) SostenutoKeys[SostenutoKeyCount++] = *iuiKey;
594     }
595     }
596    
597     void ProcessSostenutoPedalUp(Pool<Event>::Iterator& itEvent) {
598     // release voices if the damper pedal is up and their respective key is not pressed
599     for (int i = 0; i < SostenutoKeyCount; i++) {
600     MidiKey* pKey = &pMIDIKeyInfo[SostenutoKeys[i]];
601     if (!pKey->KeyPressed && !SustainPedal) {
602     RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
603     if (itNewEvent) {
604     *itNewEvent = *itEvent; // copy event to the key's own event list
605     itNewEvent->Type = Event::type_release; // transform event type
606     }
607     else dmsg(1,("Event pool emtpy!\n"));
608     }
609     }
610     }
611    
612     void AddMidiKeyboardListener(MidiKeyboardListener* l) { listeners.AddListener(l); }
613    
614     void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); }
615    
616     protected:
617     class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> {
618     public:
619     REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t)
620     REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOn, uint8_t, uint8_t)
621     REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOff, uint8_t, uint8_t)
622     REGISTER_FIRE_EVENT_METHOD_ARG2(PostProcessNoteOff, uint8_t, uint8_t)
623     REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalUp)
624     REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalUp)
625     REGISTER_FIRE_EVENT_METHOD(PreProcessSustainPedalDown)
626     REGISTER_FIRE_EVENT_METHOD(PostProcessSustainPedalDown)
627     REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalUp)
628     REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalUp)
629     REGISTER_FIRE_EVENT_METHOD(PreProcessSostenutoPedalDown)
630     REGISTER_FIRE_EVENT_METHOD(PostProcessSostenutoPedalDown)
631     } listeners;
632     };
633     } // namespace LinuxSampler
634    
635     #endif /* __LS_MIDIKEYBOARDMANAGER_H__ */
636    

  ViewVC Help
Powered by ViewVC