/[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 2613 - (hide annotations) (download) (as text)
Tue Jun 10 15:17:01 2014 UTC (9 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 33630 byte(s)
* Implemented built-in script int array variable $KEY_DOWN.
* Bumped version (1.0.0.svn48).

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

  ViewVC Help
Powered by ViewVC