/[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 2114 by persson, Tue Aug 10 12:05:19 2010 UTC revision 2927 by schoenebeck, Thu Jun 30 16:44:46 2016 UTC
# Line 30  Line 30 
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                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    
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 ProcessReleaseTrigger(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 115  namespace LinuxSampler { Line 164  namespace LinuxSampler {
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.  
                 uint32_t*       pRoundRobinIndex; ///< 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 = false;
176                      pEvents        = NULL;                      pEvents        = NULL;
177                      VoiceTheftsQueued = 0;                      VoiceTheftsQueued = 0;
178                        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    = false;
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 174  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.  
             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;  
             uint32_t              RoundRobinIndexes[128];  
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;
# Line 191  namespace LinuxSampler { Line 239  namespace LinuxSampler {
239                  SostenutoPedal = false;                  SostenutoPedal = false;
240                  for (int i = 0 ; i < 128 ; i++) {                  for (int i = 0 ; i < 128 ; i++) {
241                      RoundRobinIndexes[i] = 0;                      RoundRobinIndexes[i] = 0;
242                        KeyDown[i] = false;
243    
244                      // by default use one counter for each key (the                      // by default use one counter for each key (the
245                      // gig engine will change this to one counter per                      // gig engine will change this to one counter per
246                      // region)                      // region)
247                      pMIDIKeyInfo[i].pRoundRobinIndex = &RoundRobinIndexes[i];                      pMIDIKeyInfo[i].pRoundRobinIndex = &RoundRobinIndexes[i];
248                  }                  }
249                    m_engineChannel = pEngineChannel;
250                    m_voicePool = NULL;
251              }              }
252    
253              virtual ~MidiKeyboardManager() {              virtual ~MidiKeyboardManager() {
# Line 209  namespace LinuxSampler { Line 260  namespace LinuxSampler {
260                  SoloKey = -1;    // no solo key active yet                  SoloKey = -1;    // no solo key active yet
261    
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 249  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               *  Removes the given voice from the MIDI key's list of active voices.               *  Removes the given voice from the MIDI key's list of active voices.
# Line 267  namespace LinuxSampler { Line 326  namespace LinuxSampler {
326               */               */
327              void FreeVoice(PoolVoiceIterator& itVoice) {              void FreeVoice(PoolVoiceIterator& itVoice) {
328                  if (itVoice) {                  if (itVoice) {
329                      MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey];                      //MidiKey* pKey = &pMIDIKeyInfo[itVoice->MIDIKey];
330    
331                      // if the sample and dimension region belong to an                      // if the sample and dimension region belong to an
332                      // instrument that is unloaded, tell the disk thread to                      // instrument that is unloaded, tell the disk thread to
# Line 279  namespace LinuxSampler { Line 338  namespace LinuxSampler {
338                      }                      }
339    
340                      // free the voice object                      // free the voice object
341                      pKey->pActiveVoices->free(itVoice);                      m_voicePool->free(itVoice);
342                  }                  }
343                  else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush;                  else std::cerr << "Couldn't release voice! (!itVoice)\n" << std::flush;
344              }              }
# Line 292  namespace LinuxSampler { Line 351  namespace LinuxSampler {
351               *  @param pKey - key which is now inactive               *  @param pKey - key which is now inactive
352               */               */
353              void FreeKey(MidiKey* pKey) {              void FreeKey(MidiKey* pKey) {
354                  if (pKey->pActiveVoices->isEmpty()) {                  if (pKey->pActiveNotes->isEmpty()) {
355                        if (m_engineChannel->pScript)
356                            m_engineChannel->pScript->pKeyEvents[pKey->itSelf]->clear();
357                      pKey->Active = false;                      pKey->Active = false;
358                      pActiveKeys->free(pKey->itSelf); // remove key from list of active keys                      pActiveKeys->free(pKey->itSelf); // remove key from list of active keys
359                      pKey->itSelf = RTList<uint>::Iterator();                      pKey->itSelf = RTList<uint>::Iterator();
# Line 310  namespace LinuxSampler { Line 371  namespace LinuxSampler {
371                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
372                  RTList<uint>::Iterator end    = pActiveKeys->end();                  RTList<uint>::Iterator end    = pActiveKeys->end();
373                  while (iuiKey != end) { // iterate through all active keys                  while (iuiKey != end) { // iterate through all active keys
374                     MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
375                      ++iuiKey;                      ++iuiKey;
376                      if (pKey->pActiveVoices->isEmpty()) FreeKey(pKey);                      for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
377                      #if CONFIG_DEVMODE                           itNotesEnd = pKey->pActiveNotes->end();
378                      else { // just a sanity check for debugging                           itNote != itNotesEnd; ++itNote)
379                          RTListVoiceIterator itVoice = pKey->pActiveVoices->first();                      { // iterate over all active notes on that key ...
380                          RTListVoiceIterator = pKey->pActiveVoices->end();                          if (itNote->pActiveVoices->isEmpty()) { // free note ...
381                          for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                              itNote->reset();
382                              if (itVoice->itKillEvent) {                              pKey->pActiveNotes->free(itNote);
383                                  dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n"));                          }
384                            #if CONFIG_DEVMODE
385                            else { // just a sanity check for debugging
386                                RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
387                                RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
388                                for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
389                                    if (itVoice->itKillEvent) {
390                                        dmsg(1,("gig::Engine: ERROR, killed voice survived !!!\n"));
391                                    }
392                              }                              }
393                          }                          }
394                            #endif // CONFIG_DEVMODE
395                      }                      }
396                      #endif // CONFIG_DEVMODE                      if (pKey->pActiveNotes->isEmpty()) FreeKey(pKey);
397                  }                  }
398              }              }
399    
400              int StealVoice (              int StealVoice (
401                  Pool<Event>::Iterator&   itNoteOnEvent,                  Pool<Event>::Iterator&   itNoteOnEvent,
402                  RTListVoiceIterator*     LastStolenVoice,                  RTListVoiceIterator*     LastStolenVoice,
403                    RTListNoteIterator*      LastStolenNote,
404                  RTList<uint>::Iterator*  LastStolenKey                  RTList<uint>::Iterator*  LastStolenKey
405              ) {              ) {
406                  RTListVoiceIterator itSelectedVoice;                  RTListVoiceIterator itSelectedVoice;
# Line 343  namespace LinuxSampler { Line 414  namespace LinuxSampler {
414                      // 'oldestkey' algorithm                      // 'oldestkey' algorithm
415                      case voice_steal_algo_oldestvoiceonkey: {                      case voice_steal_algo_oldestvoiceonkey: {
416                          MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];                          MidiKey* pSelectedKey = &pMIDIKeyInfo[itNoteOnEvent->Param.Note.Key];
417                          itSelectedVoice = pSelectedKey->pActiveVoices->first();                          for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(),
418                          // proceed iterating if voice was created in this fragment cycle                               itNotesEnd = pSelectedKey->pActiveNotes->end();
419                          while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                               itNote != itNotesEnd; ++itNote)
420                          // if we haven't found a voice then proceed with algorithm 'oldestkey'                          {
421                          if (itSelectedVoice && itSelectedVoice->IsStealable()) break;                              for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice)
422                                    if (itSelectedVoice->IsStealable()) // proceed iterating if voice was created in this audio fragment cycle
423                                        goto voiceFound; // selection succeeded
424                            }
425                            // if we haven't found a voice then proceed with algorithm 'oldestkey' ...
426                      } // no break - intentional !                      } // no break - intentional !
427    
428                      // try to pick the oldest voice on the oldest active key                      // try to pick the oldest voice on the oldest active key
429                      // from the same engine channel                      // from the same engine channel
430                      // (caution: must stay after 'oldestvoiceonkey' algorithm !)                      // (caution: must stay after 'oldestvoiceonkey' algorithm !)
431                      case voice_steal_algo_oldestkey: {                      case voice_steal_algo_oldestkey: {
432                          // 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
433                          if (*LastStolenVoice) {                          if (*LastStolenVoice) {
434                              itSelectedVoice = *LastStolenVoice;                              itSelectedVoice = *LastStolenVoice;
435                              do {                              do {
# Line 367  namespace LinuxSampler { Line 442  namespace LinuxSampler {
442                                  break; // selection succeeded                                  break; // selection succeeded
443                              }                              }
444                          }                          }
445    
446                            // get (next) oldest note
447                            if (*LastStolenNote) {
448                                for (RTListNoteIterator itNote = ++(*LastStolenNote);
449                                     itNote; ++itNote)
450                                {
451                                    for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
452                                        // proceed iterating if voice was created in this audio fragment cycle
453                                        if (itSelectedVoice->IsStealable()) {
454                                            // remember which voice on which note we stole, so we can simply proceed on next voice stealing
455                                            *LastStolenNote  = itNote;
456                                            *LastStolenVoice = itSelectedVoice;
457                                            goto voiceFound; // selection succeeded
458                                        }
459                                    }
460                                }
461                            }
462    
463                          // get (next) oldest key                          // get (next) oldest key
464                          RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first();                          RTList<uint>::Iterator iuiSelectedKey = (*LastStolenKey) ? ++(*LastStolenKey) : pActiveKeys->first();
465                          while (iuiSelectedKey) {                          for (; iuiSelectedKey; ++iuiSelectedKey) {
466                              MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey];                              MidiKey* pSelectedKey = &pMIDIKeyInfo[*iuiSelectedKey];
467                              itSelectedVoice = pSelectedKey->pActiveVoices->first();  
468                              // proceed iterating if voice was created in this fragment cycle                              for (RTListNoteIterator itNote = pSelectedKey->pActiveNotes->first(),
469                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                                   itNotesEnd = pSelectedKey->pActiveNotes->end();
470                              // found a "stealable" voice ?                                   itNote != itNotesEnd; ++itNote)
471                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              {
472                                  // remember which voice on which key we stole, so we can simply proceed on next voice stealing                                  for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
473                                  *LastStolenKey  = iuiSelectedKey;                                      // proceed iterating if voice was created in this audio fragment cycle
474                                  *LastStolenVoice = itSelectedVoice;                                      if (itSelectedVoice->IsStealable()) {
475                                  break; // selection succeeded                                          // remember which voice on which key we stole, so we can simply proceed on next voice stealing
476                                            *LastStolenKey  = iuiSelectedKey;
477                                            *LastStolenNote = itNote;
478                                            *LastStolenVoice = itSelectedVoice;
479                                            goto voiceFound; // selection succeeded
480                                        }
481                                    }
482                              }                              }
                             ++iuiSelectedKey; // get next oldest key  
483                          }                          }
484                          break;                          break;
485                      }                      }
# Line 393  namespace LinuxSampler { Line 491  namespace LinuxSampler {
491                          return -1;                          return -1;
492                      }                      }
493                  }                  }
494                    
495                    voiceFound:
496    
497                  if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1;                  if (!itSelectedVoice || !itSelectedVoice->IsStealable()) return -1;
498    
# Line 430  namespace LinuxSampler { Line 530  namespace LinuxSampler {
530                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
531                  }                  }
532              }              }
533    
534              /**              /**
535               * Kill all active voices.               * Kill all active voices.
536               * @returns The number of voices.               * @returns The number of voices.
# Line 437  namespace LinuxSampler { Line 538  namespace LinuxSampler {
538              int KillAllVoices(Pool<Event>::Iterator& itKillEvent) {              int KillAllVoices(Pool<Event>::Iterator& itKillEvent) {
539                  int count = 0;                  int count = 0;
540    
541                  RTList<uint>::Iterator iuiKey  = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
542                  RTList<uint>::Iterator end = pActiveKeys->end();                  RTList<uint>::Iterator end = pActiveKeys->end();
543                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
544                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
545                      RTListVoiceIterator itVoice = pKey->pActiveVoices->first();  
546                      RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();                      for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
547                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                           itNotesEnd = pKey->pActiveNotes->end();
548                          itVoice->Kill(itKillEvent);                           itNote != itNotesEnd; ++itNote)
549                          count++;                      {
550                            RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
551                            RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
552                            for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
553                                itVoice->Kill(itKillEvent);
554                                count++;
555                            }
556                      }                      }
557                  }                  }
558    
# Line 459  namespace LinuxSampler { Line 566  namespace LinuxSampler {
566              int KillAllVoicesImmediately() {              int KillAllVoicesImmediately() {
567                  int iPendingStreamDeletions = 0;                  int iPendingStreamDeletions = 0;
568    
569                  RTList<uint>::Iterator iuiKey  = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
570                  RTList<uint>::Iterator end = pActiveKeys->end();                  RTList<uint>::Iterator end = pActiveKeys->end();
571                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
572                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
573                      RTListVoiceIterator itVoice = pKey->pActiveVoices->first();  
574                      RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();                      for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
575                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                           itNotesEnd = pKey->pActiveNotes->end();
576                          // request a notification from disk thread side for stream deletion                           itNote != itNotesEnd; ++itNote)
577                          const Stream::Handle hStream = itVoice->KillImmediately(true);                      {
578                          if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream                          RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
579                              iPendingStreamDeletions++;                          RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
580                            for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
581                                // request a notification from disk thread side for stream deletion
582                                const Stream::Handle hStream = itVoice->KillImmediately(true);
583                                if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
584                                    iPendingStreamDeletions++;
585                                }
586                                // free the voice to the voice pool and update key info
587                                itVoice->VoiceFreed();
588                                FreeVoice(itVoice);
589                          }                          }
                         // free the voice to the voice pool and update key info  
                         FreeVoice(itVoice);  
590                      }                      }
591                  }                  }
592    
# Line 484  namespace LinuxSampler { Line 598  namespace LinuxSampler {
598               * 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.
599               */               */
600              void MarkAllActiveVoicesAsOrphans() {              void MarkAllActiveVoicesAsOrphans() {
601                  RTList<uint>::Iterator iuiKey  = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
602                  RTList<uint>::Iterator end = pActiveKeys->end();                  RTList<uint>::Iterator end = pActiveKeys->end();
603                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
604                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
605                      RTListVoiceIterator itVoice = pKey->pActiveVoices->first();  
606                      RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();                      for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
607                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                           itNotesEnd = pKey->pActiveNotes->end();
608                          itVoice->Orphan = true;                           itNote != itNotesEnd; ++itNote)
609                        {
610                            RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
611                            RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
612                            for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
613                                itVoice->Orphan = true;
614                            }
615                      }                      }
616                  }                  }
617              }              }
# Line 499  namespace LinuxSampler { Line 619  namespace LinuxSampler {
619              void ProcessActiveVoices(VoiceHandler* pVoiceHandler) {              void ProcessActiveVoices(VoiceHandler* pVoiceHandler) {
620                  if (pVoiceHandler == NULL) return;                  if (pVoiceHandler == NULL) return;
621    
622                  RTList<uint>::Iterator iuiKey  = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
623                  RTList<uint>::Iterator end = pActiveKeys->end();                  RTList<uint>::Iterator end = pActiveKeys->end();
624                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys                  for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
625                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];                      MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
626                      if (!pVoiceHandler->Process(pKey)) continue;                      if (!pVoiceHandler->Process(pKey)) continue;
627    
628                      RTListVoiceIterator itVoice = pKey->pActiveVoices->first();                      for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
629                      RTListVoiceIterator itVoicesEnd = pKey->pActiveVoices->end();                           itNotesEnd = pKey->pActiveNotes->end();
630                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                           itNote != itNotesEnd; ++itNote)
631                          pVoiceHandler->Process(itVoice);                      {
632                            RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
633                            RTListVoiceIterator itVoicesEnd = itNote->pActiveVoices->end();
634                            for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
635                                pVoiceHandler->Process(itVoice);
636                            }
637                      }                      }
638                  }                  }
639              }              }
640                
641                /**
642                 * Recalculate the pitch of all active voices.
643                 */
644                void OnScaleTuningChanged() {
645                    RTList<uint>::Iterator iuiKey = pActiveKeys->first();
646                    for (; iuiKey; ++iuiKey) {
647                        MidiKey* pKey = &pMIDIKeyInfo[*iuiKey];
648    
649                        for (RTListNoteIterator itNote = pKey->pActiveNotes->first(),
650                             itNotesEnd = pKey->pActiveNotes->end();
651                             itNote != itNotesEnd; ++itNote)
652                        {
653                            RTListVoiceIterator itVoice = itNote->pActiveVoices->first();
654                            for (; itVoice; ++itVoice) {
655                                itVoice->onScaleTuningChanged();
656                            }
657                        }
658                    }
659                }
660                
661              void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) {              void ProcessSustainPedalDown(Pool<Event>::Iterator& itEvent) {
662                  // Cancel release process of all voices                  // Cancel release process of all voices
663                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();                  RTList<uint>::Iterator iuiKey = pActiveKeys->first();
# Line 539  namespace LinuxSampler { Line 684  namespace LinuxSampler {
684                          if (itNewEvent) {                          if (itNewEvent) {
685                              *itNewEvent = *itEvent; // copy event to the key's own event list                              *itNewEvent = *itEvent; // copy event to the key's own event list
686                              itNewEvent->Type = Event::type_release; // transform event type                              itNewEvent->Type = Event::type_release; // transform event type
687                                itNewEvent->Param.Note.Key = *iuiKey;
688                                itNewEvent->Param.Note.Velocity = 127;
689                                if (!SostenutoActiveOnKey(*iuiKey)) {
690                                    //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
691                                    AbstractEngineChannel* pChannel = (AbstractEngineChannel*) itEvent->pEngineChannel;
692                                    const int8_t CC64Value = pChannel->ControllerTable[64];
693                                    pChannel->ControllerTable[64] = 127;
694    
695                                    // now spawn release trigger voices (if required)
696                                    ProcessReleaseTrigger(itNewEvent);
697    
698                                    //HACK: reset sustain pedal CC value to old one (see comment above)
699                                    pChannel->ControllerTable[64] = CC64Value;
700                                }
701                          }                          }
702                          else dmsg(1,("Event pool emtpy!\n"));                          else dmsg(1,("Event pool emtpy!\n"));
703                      }                      }
# Line 546  namespace LinuxSampler { Line 705  namespace LinuxSampler {
705              }              }
706    
707              /**              /**
708                 * Whether @a key is still kept active due to sostenuto pedal usage.
709                 *
710                 * @param key - note number of key
711                 */
712                inline bool SostenutoActiveOnKey(int key) const {
713                    if (SostenutoPedal) {
714                        for (int i = 0; i < SostenutoKeyCount; i++)
715                            if (key == SostenutoKeys[i]) return true;
716                    }
717                    return false;
718                }
719    
720                /**
721               * Determines whether the specified voice should be released.               * Determines whether the specified voice should be released.
722               *               *
723               * @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 554  namespace LinuxSampler { Line 726  namespace LinuxSampler {
726               */               */
727              bool ShouldReleaseVoice(int Key) {              bool ShouldReleaseVoice(int Key) {
728                  if (SustainPedal) return false;                  if (SustainPedal) return false;
729                    if (SostenutoActiveOnKey(Key)) return false;
                 if (SostenutoPedal) {  
                     for (int i = 0; i < SostenutoKeyCount; i++)  
                         if (Key == SostenutoKeys[i]) return false;  
                 }  
   
730                  return true;                  return true;
731              }              }
732    
# Line 593  namespace LinuxSampler { Line 760  namespace LinuxSampler {
760              void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); }              void RemoveMidiKeyboardListener(MidiKeyboardListener* l) { listeners.RemoveListener(l); }
761    
762          protected:          protected:
763                AbstractEngineChannel* m_engineChannel;
764                Pool<V>* m_voicePool;
765    
766              class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> {              class Listeners : public MidiKeyboardListener, public ListenerList<MidiKeyboardListener*> {
767              public:              public:
768                  REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t)                  REGISTER_FIRE_EVENT_METHOD_ARG2(PreProcessNoteOn, uint8_t, uint8_t)

Legend:
Removed from v.2114  
changed lines
  Added in v.2927

  ViewVC Help
Powered by ViewVC