/[svn]/linuxsampler/trunk/src/engines/common/MidiKeyboardManager.h
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/common/MidiKeyboardManager.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2012 by iliev, Fri Oct 23 17:53:17 2009 UTC revision 3445 by schoenebeck, Sun Dec 23 20:08:41 2018 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2009 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009 Grigor Iliev                                       *   *   Copyright (C) 2009-2010 Christian Schoenebeck and Grigor Iliev        *
8   *                                                                         *   *                                                                         *
9   *   This program is free software; you can redistribute it and/or modify  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 23  Line 23 
23   ***************************************************************************/   ***************************************************************************/
24    
25  #ifndef __LS_MIDIKEYBOARDMANAGER_H__  #ifndef __LS_MIDIKEYBOARDMANAGER_H__
26  #define __LS_MIDIKEYBOARDMANAGER_H__  #define __LS_MIDIKEYBOARDMANAGER_H__
27    
28  #include "Event.h"  #include "Event.h"
29  #include "Stream.h"  #include "Stream.h"
30  #include "../../EventListeners.h"  #include "../../EventListeners.h"
31  #include "../../common/Pool.h"  #include "../../common/Pool.h"
32  #include "../../common/global_private.h"  #include "../../common/global_private.h"
33    #include "Note.h"
34    
35  namespace LinuxSampler {  namespace LinuxSampler {
36    
# Line 97  namespace LinuxSampler { Line 98  namespace LinuxSampler {
98              virtual void PostProcessSostenutoPedalDown() { }              virtual void PostProcessSostenutoPedalDown() { }
99      };      };
100    
101        /**
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         *
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         */
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                release_trigger_t ReleaseTrigger; ///< If we have to launch release triggered voice(s) when either the key or sustain pedal 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    
134        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            virtual void ProcessReleaseTriggerBySustain(RTList<Event>::Iterator& itEvent) = 0;
147        };
148    
149      template <class V>      template <class V>
150      class MidiKeyboardManager {      class MidiKeyboardManager : public MidiKeyboardManagerBase {
151          public:          public:
152              /** @brief Voice Stealing Algorithms              /** @brief Voice Stealing Algorithms
153               *               *
# Line 109  namespace LinuxSampler { Line 158  namespace LinuxSampler {
158                  voice_steal_algo_oldestvoiceonkey,  ///< Try to kill the oldest voice from same key where the new voice should be spawned.                  voice_steal_algo_oldestvoiceonkey,  ///< Try to kill the oldest voice from same key where the new voice should be spawned.
159                  voice_steal_algo_oldestkey          ///< Try to kill the oldest voice from the oldest active key.                  voice_steal_algo_oldestkey          ///< Try to kill the oldest voice from the oldest active key.
160              };              };
161            
162    
163              /** @brief MIDI key runtime informations              /** @brief MIDI key runtime informations
164               *               *
165               * Reflects runtime informations for one MIDI key.               * Reflects runtime informations for one MIDI key.
166               */               */
167              class MidiKey {              class MidiKey : public MidiKeyBase {
168              public:              public:
169                  RTList<V>*      pActiveVoices;  ///< Contains the active voices associated with the MIDI key.                  RTList< Note<V> >* pActiveNotes; ///< Contains the active notes associated with the MIDI key.
                 bool            KeyPressed;     ///< Is true if the respective MIDI key is currently pressed.  
                 bool            Active;         ///< If the key contains active voices.  
                 bool            ReleaseTrigger; ///< If we have to launch release triggered voice(s) when the key is released  
                 Pool<uint>::Iterator itSelf;    ///< hack to allow fast deallocation of the key from the list of active keys  
                 RTList<Event>*  pEvents;        ///< Key specific events (only Note-on, Note-off and sustain pedal currently)  
                 int             VoiceTheftsQueued; ///< Amount of voices postponed due to shortage of voices.  
                 uint8_t         RoundRobinIndex; ///< For the round robin dimension: current articulation for this key, will be incremented for each note on  
                 uint8_t         Velocity;       ///< Latest Note-on velocity for this key  
                 unsigned long   NoteOnTime;     ///< Time for latest Note-on event for this key  
170    
171                  MidiKey() {                  MidiKey() {
172                      pActiveVoices  = NULL;                      pActiveNotes   = NULL;
173                      KeyPressed     = false;                      KeyPressed     = false;
174                      Active         = false;                      Active         = false;
175                      ReleaseTrigger = false;                      ReleaseTrigger = release_trigger_none;
176                      pEvents        = NULL;                      pEvents        = NULL;
177                      VoiceTheftsQueued = 0;                      VoiceTheftsQueued = 0;
178                      RoundRobinIndex = 0;                      Volume = 1.0f;
179                        PanLeft = 1.0f;
180                        PanRight = 1.0f;
181                  }                  }
182    
183                  void Reset() {                  void Reset() {
184                      if (pActiveVoices) pActiveVoices->clear();                      if (pActiveNotes) {
185                            RTListNoteIterator itNote = pActiveNotes->first();
186                            RTListNoteIterator itNotesEnd = pActiveNotes->end();
187                            for (; itNote != itNotesEnd; ++itNote) { // iterate through all active notes on this key
188                                itNote->reset();
189                            }
190                            pActiveNotes->clear();
191                        }
192                      if (pEvents) pEvents->clear();                      if (pEvents) pEvents->clear();
193                      KeyPressed        = false;                      KeyPressed        = false;
194                      Active            = false;                      Active            = false;
195                      ReleaseTrigger    = false;                      ReleaseTrigger    = release_trigger_none;
196                      itSelf            = Pool<uint>::Iterator();                      itSelf            = Pool<uint>::Iterator();
197                      VoiceTheftsQueued = 0;                      VoiceTheftsQueued = 0;
198                        Volume = 1.0f;
199                        PanLeft = 1.0f;
200                        PanRight = 1.0f;
201                        ReverbSend = optional<float>::nothing;
202                        ChorusSend = optional<float>::nothing;
203                  }                  }
204              };              };
205    
206                typedef typename RTList< Note<V> >::Iterator RTListNoteIterator;
207              typedef typename RTList<V>::Iterator RTListVoiceIterator;              typedef typename RTList<V>::Iterator RTListVoiceIterator;
208              typedef typename Pool<V>::Iterator PoolVoiceIterator;              typedef typename Pool<V>::Iterator PoolVoiceIterator;
209    
# Line 175  namespace LinuxSampler { Line 230  namespace LinuxSampler {
230              };              };
231    
232              MidiKey*              pMIDIKeyInfo; ///< Contains all active voices sorted by MIDI key number and other informations to the respective MIDI key              MidiKey*              pMIDIKeyInfo; ///< Contains all active voices sorted by MIDI key number and other informations to the respective MIDI key
             Pool<uint>*           pActiveKeys;  ///< Holds all keys in it's allocation list with active voices.  
             std::map<uint,uint*>  ActiveKeyGroups;  ///< Contains active keys (in case they belong to a key group) ordered by key group ID.  
             bool                  SoloMode;                 ///< in Solo Mode we only play one voice (group) at a time  
             int                   SoloKey;                  ///< Currently 'active' solo key, that is the key to which the currently sounding voice belongs to (only if SoloMode is enabled)  
             bool                  SustainPedal;             ///< true if sustain pedal is down  
             bool                  SostenutoPedal;           ///< true if sostenuto pedal is down  
             int                   SostenutoKeys[128];  
             int                   SostenutoKeyCount;  
233    
234              MidiKeyboardManager() {              MidiKeyboardManager(AbstractEngineChannel* pEngineChannel) {
235                  pMIDIKeyInfo = new MidiKey[128];                  pMIDIKeyInfo = new MidiKey[128];
236                  pActiveKeys  = new Pool<uint>(128);                  pActiveKeys  = new Pool<uint>(128);
237                  SoloMode     = false;                  SoloMode     = false;
238                  SustainPedal   = false;                  SustainPedal   = false;
239                  SostenutoPedal = false;                  SostenutoPedal = false;
240                    for (int i = 0 ; i < 128 ; i++) {
241                        RoundRobinIndexes[i] = 0;
242                        KeyDown[i] = false;
243    
244                        // by default use one counter for each key (the
245                        // gig engine will change this to one counter per
246                        // region)
247                        pMIDIKeyInfo[i].pRoundRobinIndex = &RoundRobinIndexes[i];
248                    }
249                    m_engineChannel = pEngineChannel;
250                    m_voicePool = NULL;
251              }              }
252    
253              virtual ~MidiKeyboardManager() {              virtual ~MidiKeyboardManager() {
# Line 198  namespace LinuxSampler { Line 256  namespace LinuxSampler {
256                  if (pMIDIKeyInfo) delete[] pMIDIKeyInfo;                  if (pMIDIKeyInfo) delete[] pMIDIKeyInfo;
257              }              }
258    
259              void Reset(){              void Reset() {
260                  SoloKey = -1;    // no solo key active yet                  SoloKey = -1;    // no solo key active yet
261    
                 // reset all key groups  
                 std::map<uint,uint*>::iterator iter = ActiveKeyGroups.begin();  
                 for (; iter != ActiveKeyGroups.end(); iter++) iter->second = NULL;  
   
262                  // reset key info                  // reset key info
263                  for (uint i = 0; i < 128; i++) pMIDIKeyInfo[i].Reset();                  for (uint i = 0; i < 128; i++) {
264                        pMIDIKeyInfo[i].Reset();
265                        KeyDown[i] = false;
266                        if (m_engineChannel->pScript)
267                            m_engineChannel->pScript->pKeyEvents[i]->clear();
268                    }
269    
270                  // free all active keys                  // free all active keys
271                  pActiveKeys->clear();                  pActiveKeys->clear();
272              }              }
273    
274              void AllocateActiveVoices(Pool<V>* pVoicePool) {              void AllocateActiveNotesLists(Pool< Note<V> >* pNotePool, Pool<V>* pVoicePool) {
275                  DeleteActiveVoices();                  DeleteActiveNotesLists();
276    
277                    m_voicePool = pVoicePool;
278    
279                  for (uint i = 0; i < 128; i++) {                  for (uint i = 0; i < 128; i++) {
280                      pMIDIKeyInfo[i].pActiveVoices = new RTList<V>(pVoicePool);                      pMIDIKeyInfo[i].pActiveNotes = new RTList< Note<V> >(pNotePool);
281                  }                  }
282              }              }
283    
284              void DeleteActiveVoices() {              void DeleteActiveNotesLists() {
285                  for (uint i = 0; i < 128; i++) {                  for (uint i = 0; i < 128; i++) {
286                      if (pMIDIKeyInfo[i].pActiveVoices) {                      if (pMIDIKeyInfo[i].pActiveNotes) {
287                          delete pMIDIKeyInfo[i].pActiveVoices;                          delete pMIDIKeyInfo[i].pActiveNotes;
288                          pMIDIKeyInfo[i].pActiveVoices = NULL;                          pMIDIKeyInfo[i].pActiveNotes = NULL;
289                      }                      }
290                  }                  }
291                    m_voicePool = NULL;
292              }              }
293    
294              void AllocateEvents(Pool<Event>* pEventPool) {              void AllocateEventsLists(Pool<Event>* pEventPool) {
295                  DeleteEvents();                  DeleteEventsLists();
296    
297                  for (uint i = 0; i < 128; i++) {                  for (uint i = 0; i < 128; i++) {
298                      pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEventPool);                      pMIDIKeyInfo[i].pEvents = new RTList<Event>(pEventPool);
299                  }                  }
300              }              }
301    
302              void DeleteEvents() {              void DeleteEventsLists() {
303                  for (uint i = 0; i < 128; i++) {                  for (uint i = 0; i < 128; i++) {
304                      if (pMIDIKeyInfo[i].pEvents) {                      if (pMIDIKeyInfo[i].pEvents) {
305                          delete pMIDIKeyInfo[i].pEvents;                          delete pMIDIKeyInfo[i].pEvents;
# Line 246  namespace LinuxSampler { Line 308  namespace LinuxSampler {
308                  }                  }
309              }              }
310    
311              void ClearAllActiveKeyEvents() {              /*void ClearAllActiveKeyEvents() {
312                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
313                  RTList<uint>::Iterator end    = pActiveKeys->end();                  RTList<uint>::Iterator end    = pActiveKeys->end();
314                  for(; iuiKey != end; ++iuiKey) {                  for(; iuiKey != end; ++iuiKey) {
315                      pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key                      pMIDIKeyInfo[*iuiKey].pEvents->clear(); // free all events on the key
316                  }                  }
317                }*/
318    
319                /**
320                 * Make sure the passed MIDI key is part of the list of active keys,
321                 * if it is not already, then add it to that list. Accordingly it is
322                 * safe to call this method even if the requested key is already
323                 * marked as active.
324                 */
325                void markKeyAsActive(MidiKey* pKey) {
326                    if (!pKey->Active) { // mark as active key
327                        pKey->Active = true;
328                        pKey->itSelf = pActiveKeys->allocAppend();
329                        const int iKey = pKey - &pMIDIKeyInfo[0];
330                        *pKey->itSelf = iKey;
331                    }
332              }              }
333    
334              /**              /**
# Line 264  namespace LinuxSampler { Line 341  namespace LinuxSampler {
341               */               */
342              void FreeVoice(PoolVoiceIterator& itVoice) {              void FreeVoice(PoolVoiceIterator& itVoice) {
343                  if (itVoice) {                  if (itVoice) {
344                      MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey];                      //MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey];
   
                     uint keygroup = itVoice->KeyGroup;  
345    
346                      // if the sample and dimension region belong to an                      // if the sample and dimension region belong to an
347                      // instrument that is unloaded, tell the disk thread to                      // instrument that is unloaded, tell the disk thread to
# Line 278  namespace LinuxSampler { Line 353  namespace LinuxSampler {
353                      }                      }
354    
355                      // free the voice object                      // free the voice object
356                      pKey->pActiveVoices->free(itVoice);                      m_voicePool->free(itVoice);
   
                     // if no other voices left and member of a key group, remove from key group  
                     if (pKey->pActiveVoices->isEmpty() && keygroup) {  
                         uint** ppKeyGroup = &ActiveKeyGroups[keygroup];  
                         if (*ppKeyGroup == &*pKey->itSelf) *ppKeyGroup = NULL; // remove key from key group  
                     }  
357                  }                  }
358                  else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush;                  else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush;
359              }              }
# Line 297  namespace LinuxSampler { Line 366  namespace LinuxSampler {
366               *  @param pKey - key which is now inactive               *  @param pKey - key which is now inactive
367               */               */
368              void FreeKey(MidiKey* pKey) {              void FreeKey(MidiKey* pKey) {
369                  if (pKey->pActiveVoices->isEmpty()) {                  if (pKey->pActiveNotes->isEmpty()) {
370                        if (m_engineChannel->pScript)
371                            m_engineChannel->pScript->pKeyEvents[pKey->itSelf]->clear();
372                      pKey->Active = false;                      pKey->Active = false;
373                      pActiveKeys->free(pKey->itSelf); // remove key from list of active keys                      pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
374                      pKey->itSelf = RTList<uint>::Iterator();                      pKey->itSelf = RTList<uint>::Iterator();
375                      pKey->ReleaseTrigger = false;                      pKey->ReleaseTrigger = release_trigger_none;
376                      pKey->pEvents->clear();                      pKey->pEvents->clear();
377                      dmsg(3,("Key has no more voices now\n"));                      dmsg(3,("Key has no more voices now\n"));
378                  }                  }
# Line 311  namespace LinuxSampler { Line 382  namespace LinuxSampler {
382              /**              /**
383               * Free all keys which have no active voices left               * Free all keys which have no active voices left
384               */               */
385              void FreeAllInactiveKyes() {              void FreeAllInactiveKeys() {
386                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
387                  RTList<uint>::Iterator end    = pActiveKeys->end();                  RTList<uint>::Iterator end    = pActiveKeys->end();
388                  while (iuiKey != end) { // iterate through all active keys                  while (iuiKey != end) { // iterate through all active keys
389                     MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
390                      ++iuiKey;                      ++iuiKey;
391                      if (pKey->pActiveVoices->isEmpty()) FreeKey(pKey);                      for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
392                      #if CONFIG_DEVMODE                           itNotesEnd = pKey->pActiveNotes->end();
393                      else { // just a sanity check for debugging                           itNote != itNotesEnd; ++itNote)
394                          RTListVoiceIterator itVoice = pKey->pActiveVoices->first();                      { // iterate over all active notes on that key ...
395                          RTListVoiceIterator = pKey->pActiveVoices->end();                          if (itNote->pActiveVoices->isEmpty()) { // free note ...
396                          for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                              itNote->reset();
397                              if (itVoice->itKillEvent) {                              pKey->pActiveNotes->free(itNote);
398                                  dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n"));                          }
399                            #if CONFIG_DEVMODE
400                            else { // just a sanity check for debugging
401                                RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
402                                RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
403                                for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
404                                    if (itVoice->itKillEvent) {
405                                        dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n"));
406                                    }
407                              }                              }
408                          }                          }
409                            #endif // CONFIG_DEVMODE
410                      }                      }
411                      #endif // CONFIG_DEVMODE                      if (pKey->pActiveNotes->isEmpty()) FreeKey(pKey);
412                  }                  }
413              }              }
414    
415              int StealVoice (              int StealVoice (
416                  Pool<Event>::Iterator&   itNoteOnEvent,                  Pool<Event>::Iterator&   itNoteOnEvent,
417                  RTListVoiceIterator*     LastStolenVoice,                  RTListVoiceIterator*     LastStolenVoice,
418                    RTListNoteIterator*      LastStolenNote,
419                  RTList<uint>::Iterator*  LastStolenKey                  RTList<uint>::Iterator*  LastStolenKey
420              ) {              ) {
421                  RTListVoiceIterator itSelectedVoice;                  RTListVoiceIterator itSelectedVoice;
# Line 348  namespace LinuxSampler { Line 429  namespace LinuxSampler {
429                      // 'oldestkey' algorithm                      // 'oldestkey' algorithm
430                      case voice_steal_algo_oldestvoiceonkey: {                      case voice_steal_algo_oldestvoiceonkey: {
431                          MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];                          MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
432                          itSelectedVoice = pSelectedKey->pActiveVoices->first();                          for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(),
433                          // proceed iterating if voice was created in this fragment cycle                               itNotesEnd = pSelectedKey->pActiveNotes->end();
434                          while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                               itNote != itNotesEnd; ++itNote)
435                          // if we haven't found a voice then proceed with algorithm 'oldestkey'                          {
436                          if (itSelectedVoice && itSelectedVoice->IsStealable()) break;                              for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice)
437                                    if (itSelectedVoice->IsStealable()) // proceed iterating if voice was created in this audio fragment cycle
438                                        goto voiceFound; // selection succeeded
439                            }
440                            // if we haven't found a voice then proceed with algorithm 'oldestkey' ...
441                      } // no break - intentional !                      } // no break - intentional !
442    
443                      // try to pick the oldest voice on the oldest active key                      // try to pick the oldest voice on the oldest active key
444                      // from the same engine channel                      // from the same engine channel
445                      // (caution: must stay after 'oldestvoiceonkey' algorithm !)                      // (caution: must stay after 'oldestvoiceonkey' algorithm !)
446                      case voice_steal_algo_oldestkey: {                      case voice_steal_algo_oldestkey: {
447                          // if we already stole in this fragment, try to proceed on same key                          // if we already stole in this fragment, try to proceed to steal on same note
448                          if (*LastStolenVoice) {                          if (*LastStolenVoice) {
449                              itSelectedVoice = *LastStolenVoice;                              itSelectedVoice = *LastStolenVoice;
450                              do {                              do {
# Line 372  namespace LinuxSampler { Line 457  namespace LinuxSampler {
457                                  break; // selection succeeded                                  break; // selection succeeded
458                              }                              }
459                          }                          }
460    
461                            // get (next) oldest note
462                            if (*LastStolenNote) {
463                                for (RTListNoteIterator itNote = ++(*LastStolenNote);
464                                     itNote; ++itNote)
465                                {
466                                    for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
467                                        // proceed iterating if voice was created in this audio fragment cycle
468                                        if (itSelectedVoice->IsStealable()) {
469                                            // remember which voice on which note we stole, so we can simply proceed on next voice stealing
470                                            *LastStolenNote  = itNote;
471                                            *LastStolenVoice = itSelectedVoice;
472                                            goto voiceFound; // selection succeeded
473                                        }
474                                    }
475                                }
476                            }
477    
478                          // get (next) oldest key                          // get (next) oldest key
479                          RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first();                          RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first();
480                          while (iuiSelectedKey) {                          for (; iuiSelectedKey; ++iuiSelectedKey) {
481                              MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey];                              MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey];
482                              itSelectedVoice = pSelectedKey->pActiveVoices->first();  
483                              // proceed iterating if voice was created in this fragment cycle                              for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(),
484                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                                   itNotesEnd = pSelectedKey->pActiveNotes->end();
485                              // found a "stealable" voice ?                                   itNote != itNotesEnd; ++itNote)
486                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              {
487                                  // remember which voice on which key we stole, so we can simply proceed on next voice stealing                                  for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
488                                  *LastStolenKey  = iuiSelectedKey;                                      // proceed iterating if voice was created in this audio fragment cycle
489                                  *LastStolenVoice = itSelectedVoice;                                      if (itSelectedVoice->IsStealable()) {
490                                  break; // selection succeeded                                          // remember which voice on which key we stole, so we can simply proceed on next voice stealing
491                                            *LastStolenKey  = iuiSelectedKey;
492                                            *LastStolenNote = itNote;
493                                            *LastStolenVoice = itSelectedVoice;
494                                            goto voiceFound; // selection succeeded
495                                        }
496                                    }
497                              }                              }
                             ++iuiSelectedKey; // get next oldest key  
498                          }                          }
499                          break;                          break;
500                      }                      }
# Line 398  namespace LinuxSampler { Line 506  namespace LinuxSampler {
506                          return -1;                          return -1;
507                      }                      }
508                  }                  }
509                    
510                    voiceFound:
511    
512                  if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1;                  if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1;
513    
# Line 430  namespace LinuxSampler { Line 540  namespace LinuxSampler {
540                      RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
541                      if (itNewEvent) {                      if (itNewEvent) {
542                          *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list)                          *itNewEvent = *itReleaseEvent; // copy original event (to the key's event list)
543                          itNewEvent->Type = Event::type_release; // transform event type                          itNewEvent->Type = Event::type_release_key; // transform event type
544                      }                      }
545                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
546                  }                  }
547              }              }
548    
549              /**              /**
550               * Kill all active voices.               * Kill all active voices.
551               * @returns The number of voices.               * @returns The number of voices.
# Line 442  namespace LinuxSampler { Line 553  namespace LinuxSampler {
553              int KillAllVoices(Pool<Event>::Iterator& itKillEvent) {              int KillAllVoices(Pool<Event>::Iterator& itKillEvent) {
554                  int count = 0;                  int count = 0;
555    
556                  RTList<uint>::Iterator iuiKey  = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
557                  RTList<uint>::Iterator end = pActiveKeys->end();                  RTList<uint>::Iterator end = pActiveKeys->end();
558                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
559                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
560                      RTListVoiceIterator itVoice = pKey->pActiveVoices->first();  
561                      RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();                      for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
562                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                           itNotesEnd = pKey->pActiveNotes->end();
563                          itVoice->Kill(itKillEvent);                           itNote != itNotesEnd; ++itNote)
564                          count++;                      {
565                            RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
566                            RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
567                            for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
568                                itVoice->Kill(itKillEvent);
569                                count++;
570                            }
571                      }                      }
572                  }                  }
573    
# Line 464  namespace LinuxSampler { Line 581  namespace LinuxSampler {
581              int KillAllVoicesImmediately() {              int KillAllVoicesImmediately() {
582                  int iPendingStreamDeletions = 0;                  int iPendingStreamDeletions = 0;
583    
584                  RTList<uint>::Iterator iuiKey  = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
585                  RTList<uint>::Iterator end = pActiveKeys->end();                  RTList<uint>::Iterator end = pActiveKeys->end();
586                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
587                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
588                      RTListVoiceIterator itVoice = pKey->pActiveVoices->first();  
589                      RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();                      for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
590                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                           itNotesEnd = pKey->pActiveNotes->end();
591                          // request a notification from disk thread side for stream deletion                           itNote != itNotesEnd; ++itNote)
592                          const Stream::Handle hStream = itVoice->KillImmediately(true);                      {
593                          if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream                          RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
594                              iPendingStreamDeletions++;                          RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
595                            for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
596                                // request a notification from disk thread side for stream deletion
597                                const Stream::Handle hStream = itVoice->KillImmediately(true);
598                                if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
599                                    iPendingStreamDeletions++;
600                                }
601                                // free the voice to the voice pool and update key info
602                                itVoice->VoiceFreed();
603                                FreeVoice(itVoice);
604                          }                          }
                         // free the voice to the voice pool and update key info  
                         FreeVoice(itVoice);  
605                      }                      }
606                  }                  }
607    
# Line 489  namespace LinuxSampler { Line 613  namespace LinuxSampler {
613               * samples they use should be released to the instrument manager when the voices die.               * samples they use should be released to the instrument manager when the voices die.
614               */               */
615              void MarkAllActiveVoicesAsOrphans() {              void MarkAllActiveVoicesAsOrphans() {
616                  RTList<uint>::Iterator iuiKey  = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
617                  RTList<uint>::Iterator end = pActiveKeys->end();                  RTList<uint>::Iterator end = pActiveKeys->end();
618                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
619                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
620                      RTListVoiceIterator itVoice = pKey->pActiveVoices->first();  
621                      RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();                      for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
622                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                           itNotesEnd = pKey->pActiveNotes->end();
623                          itVoice->Orphan = true;                           itNote != itNotesEnd; ++itNote)
624                        {
625                            RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
626                            RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
627                            for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
628                                itVoice->Orphan = true;
629                            }
630                      }                      }
631                  }                  }
632              }              }
# Line 504  namespace LinuxSampler { Line 634  namespace LinuxSampler {
634              void ProcessActiveVoices(VoiceHandler* pVoiceHandler) {              void ProcessActiveVoices(VoiceHandler* pVoiceHandler) {
635                  if (pVoiceHandler == NULL) return;                  if (pVoiceHandler == NULL) return;
636    
637                  RTList<uint>::Iterator iuiKey  = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
638                  RTList<uint>::Iterator end = pActiveKeys->end();                  RTList<uint>::Iterator end = pActiveKeys->end();
639                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
640                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
641                      if (!pVoiceHandler->Process(pKey)) continue;                      if (!pVoiceHandler->Process(pKey)) continue;
642    
643                      RTListVoiceIterator itVoice = pKey->pActiveVoices->first();                      for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
644                      RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();                           itNotesEnd = pKey->pActiveNotes->end();
645                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                           itNote != itNotesEnd; ++itNote)
646                          pVoiceHandler->Process(itVoice);                      {
647                            RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
648                            RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
649                            for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
650                                pVoiceHandler->Process(itVoice);
651                            }
652                      }                      }
653                  }                  }
654              }              }
655                
656                /**
657                 * Recalculate the pitch of all active voices.
658                 */
659                void OnScaleTuningChanged() {
660                    RTList<uint>::Iterator iuiKey = pActiveKeys->first();
661                    for (; iuiKey; ++iuiKey) {
662                        MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
663    
664                        for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
665                             itNotesEnd = pKey->pActiveNotes->end();
666                             itNote != itNotesEnd; ++itNote)
667                        {
668                            RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
669                            for (; itVoice; ++itVoice) {
670                                itVoice->onScaleTuningChanged();
671                            }
672                        }
673                    }
674                }
675                
676              void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) {              void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) {
677                  // Cancel release process of all voices                  // Cancel release process of all voices
678                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
# Line 527  namespace LinuxSampler { Line 682  namespace LinuxSampler {
682                          RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                          RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
683                          if (itNewEvent) {                          if (itNewEvent) {
684                              *itNewEvent = *itEvent; // copy event to the key's own event list                              *itNewEvent = *itEvent; // copy event to the key's own event list
685                              itNewEvent->Type = Event::type_cancel_release; // transform event type                              itNewEvent->Type = Event::type_cancel_release_key; // transform event type
686                          }                          }
687                          else dmsg(1,("Event pool emtpy!\n"));                          else dmsg(1,("Event pool emtpy!\n"));
688                      }                      }
# Line 543  namespace LinuxSampler { Line 698  namespace LinuxSampler {
698                          RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                          RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
699                          if (itNewEvent) {                          if (itNewEvent) {
700                              *itNewEvent = *itEvent; // copy event to the key's own event list                              *itNewEvent = *itEvent; // copy event to the key's own event list
701                              itNewEvent->Type = Event::type_release; // transform event type                              itNewEvent->Type = Event::type_release_key; // transform event type
702                                itNewEvent->Param.Note.Key = *iuiKey;
703                                itNewEvent->Param.Note.Velocity = 127;
704    
705                                // process release trigger (if requested)
706                                if (pKey->ReleaseTrigger & release_trigger_sustain) {
707                                    if (pKey->ReleaseTrigger & release_trigger_sustain_keyvelocity)
708                                        itNewEvent->Param.Note.Velocity = pKey->Velocity;
709    
710                                    //HACK: set sustain CC (64) as "pressed down" for a short moment, so that release trigger voices can distinguish between note off and sustain pedal up cases
711                                    AbstractEngineChannel* pChannel = (AbstractEngineChannel*) itEvent->pEngineChannel;
712                                    const int8_t CC64Value = pChannel->ControllerTable[64];
713                                    pChannel->ControllerTable[64] = 127;
714    
715                                    // now spawn release trigger voices (if required)
716                                    ProcessReleaseTriggerBySustain(itNewEvent);
717    
718                                    //HACK: reset sustain pedal CC value to old one (see comment above)
719                                    pChannel->ControllerTable[64] = CC64Value;  
720                                }
721                          }                          }
722                          else dmsg(1,("Event pool emtpy!\n"));                          else dmsg(1,("Event pool emtpy!\n"));
723                      }                      }
# Line 551  namespace LinuxSampler { Line 725  namespace LinuxSampler {
725              }              }
726    
727              /**              /**
728                 * Whether @a key is still kept active due to sostenuto pedal usage.
729                 *
730                 * @param key - note number of key
731                 */
732                inline bool SostenutoActiveOnKey(int key) const {
733                    if (SostenutoPedal) {
734                        for (int i = 0; i < SostenutoKeyCount; i++)
735                            if (key == SostenutoKeys[i]) return true;
736                    }
737                    return false;
738                }
739    
740                /**
741               * Determines whether the specified voice should be released.               * Determines whether the specified voice should be released.
742               *               *
743               * @param pEngineChannel - The engine channel on which the voice should be checked               * @param pEngineChannel - The engine channel on which the voice should be checked
# Line 559  namespace LinuxSampler { Line 746  namespace LinuxSampler {
746               */               */
747              bool ShouldReleaseVoice(int Key) {              bool ShouldReleaseVoice(int Key) {
748                  if (SustainPedal) return false;                  if (SustainPedal) return false;
749                    if (SostenutoActiveOnKey(Key)) return false;
                 if (SostenutoPedal) {  
                     for (int i = 0; i < SostenutoKeyCount; i++)  
                         if (Key == SostenutoKeys[i]) return false;  
                 }  
   
750                  return true;                  return true;
751              }              }
752    
# Line 586  namespace LinuxSampler { Line 768  namespace LinuxSampler {
768                          RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();                          RTList<Event>::Iterator itNewEvent = pKey->pEvents->allocAppend();
769                          if (itNewEvent) {                          if (itNewEvent) {
770                              *itNewEvent = *itEvent; // copy event to the key's own event list                              *itNewEvent = *itEvent; // copy event to the key's own event list
771                              itNewEvent->Type = Event::type_release; // transform event type                              itNewEvent->Type = Event::type_release_key; // transform event type
772                          }                          }
773                          else dmsg(1,("Event pool emtpy!\n"));                          else dmsg(1,("Event pool emtpy!\n"));
774                      }                      }
# Line 598  namespace LinuxSampler { Line 780  namespace LinuxSampler {
780              void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); }              void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); }
781    
782          protected:          protected:
783                AbstractEngineChannel* m_engineChannel;
784                Pool<V>* m_voicePool;
785    
786              class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> {              class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> {
787              public:              public:
788                  REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t)                  REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t)
# Line 616  namespace LinuxSampler { Line 801  namespace LinuxSampler {
801      };      };
802  } // namespace LinuxSampler  } // namespace LinuxSampler
803    
804  #endif  /* __LS_MIDIKEYBOARDMANAGER_H__ */  #endif  /* __LS_MIDIKEYBOARDMANAGER_H__ */
   

Legend:
Removed from v.2012  
changed lines
  Added in v.3445

  ViewVC Help
Powered by ViewVC