/[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 2114 - (hide annotations) (download) (as text)
Tue Aug 10 12:05:19 2010 UTC (13 years, 8 months ago) by persson
File MIME type: text/x-c++hdr
File size: 30352 byte(s)
* sfz engine: improved support for exclusive groups (group, off_by and
  off_mode)
* minor valgrind fixes

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

  ViewVC Help
Powered by ViewVC