/[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 2879 - (hide annotations) (download) (as text)
Tue Apr 19 14:07:53 2016 UTC (2 years, 8 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 38507 byte(s)
* All engines: Active voices are now internally grouped to "Note" objects,
  instead of being directly assigned to a keyboard key. This allows more
  fine graded processing of voices, which is i.e. required for certain
  instrument script features.
* Built-in script function "play_note()": Added support for passing
  special value -1 for "duration-us" argument, which will cause the
  triggered note to be released once the original note was released.
* Bumped version (2.0.0.svn3).

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

  ViewVC Help
Powered by ViewVC