/[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 2121 - (hide annotations) (download) (as text)
Tue Sep 14 17:09:08 2010 UTC (13 years, 7 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 32200 byte(s)
* implemented Roland GS NRPN 1ArrH which allows to set volume per note
* implemented Roland GS NRPN 1CrrH which allows to set pan per note
* implemented Roland GS NRPN 1DrrH which allows to set reverb send per
  note (in this implementation of the sampler its simply hard routed to
  the 1st effect send of the sampler channel, no matter what the actual
  effect type is)
* implemented Roland GS NRPN 1ErrH which allows to set chorus send per
  note (in this implementation of the sampler its simply hard routed to
  the 2nd effect send of the sampler channel, no matter what the actual
  effect type is)
* bumped version to 1.0.0cvs4

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

  ViewVC Help
Powered by ViewVC