/[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 2645 - (hide annotations) (download) (as text)
Wed Jun 18 00:14:57 2014 UTC (9 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 34546 byte(s)
* RT instrument scripts: Pass/preserve polyphonic variable data
  from respective "note" event handler to "release" event handler.
* Fixed theoretical memory leak regarding instrument scripts.
* Bumped version (1.0.0.svn54).

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

  ViewVC Help
Powered by ViewVC