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

Diff of /linuxsampler/trunk/src/engines/EngineBase.h

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

revision 2871 by schoenebeck, Sun Apr 10 18:22:23 2016 UTC revision 2927 by schoenebeck, Thu Jun 30 16:44:46 2016 UTC
# Line 33  Line 33 
33  #include "InstrumentManager.h"  #include "InstrumentManager.h"
34  #include "../common/global_private.h"  #include "../common/global_private.h"
35    
36    // a bit headroom over CONFIG_MAX_VOICES to avoid minor complications i.e. under voice stealing conditions
37    #define MAX_NOTES_HEADROOM  3
38    #define GLOBAL_MAX_NOTES    (GLOBAL_MAX_VOICES * MAX_NOTES_HEADROOM)
39    
40  namespace LinuxSampler {  namespace LinuxSampler {
41    
# Line 46  namespace LinuxSampler { Line 49  namespace LinuxSampler {
49          class IM  /* Instrument Manager */,          class IM  /* Instrument Manager */,
50          class I   /* Instrument */          class I   /* Instrument */
51      >      >
52      class EngineBase: public AbstractEngine, public RegionPools<R>, public VoicePool<V> {      class EngineBase: public AbstractEngine, public RegionPools<R>, public NotePool<V> {
53    
54          public:          public:
55                typedef typename RTList< Note<V> >::Iterator NoteIterator;
56              typedef typename RTList<V>::Iterator VoiceIterator;              typedef typename RTList<V>::Iterator VoiceIterator;
57              typedef typename Pool<V>::Iterator PoolVoiceIterator;              typedef typename Pool<V>::Iterator PoolVoiceIterator;
58              typedef typename RTList<RR*>::Iterator RootRegionIterator;              typedef typename RTList<RR*>::Iterator RootRegionIterator;
59              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;              typedef typename MidiKeyboardManager<V>::MidiKey MidiKey;
60                            
61              EngineBase() : SuspendedRegions(128) {              EngineBase() : SuspendedRegions(128), noteIDPool(GLOBAL_MAX_NOTES) {
62                  pDiskThread          = NULL;                  pDiskThread          = NULL;
63                    pNotePool            = new Pool< Note<V> >(GLOBAL_MAX_NOTES);
64                    pNotePool->setPoolElementIDsReservedBits(INSTR_SCRIPT_EVENT_ID_RESERVED_BITS);
65                  pVoicePool           = new Pool<V>(GLOBAL_MAX_VOICES);                  pVoicePool           = new Pool<V>(GLOBAL_MAX_VOICES);
66                  pRegionPool[0]       = new Pool<R*>(GLOBAL_MAX_VOICES);                  pRegionPool[0]       = new Pool<R*>(GLOBAL_MAX_VOICES);
67                  pRegionPool[1]       = new Pool<R*>(GLOBAL_MAX_VOICES);                  pRegionPool[1]       = new Pool<R*>(GLOBAL_MAX_VOICES);
68                  pVoiceStealingQueue  = new RTList<Event>(pEventPool);                  pVoiceStealingQueue  = new RTList<Event>(pEventPool);
69                  iMaxDiskStreams      = GLOBAL_MAX_STREAMS;                  iMaxDiskStreams      = GLOBAL_MAX_STREAMS;
70    
71                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  // init all Voice objects in voice pool
72                    for (VoiceIterator iterVoice = pVoicePool->allocAppend();
73                         iterVoice; iterVoice = pVoicePool->allocAppend())
74                    {
75                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
76                  }                  }
77                  pVoicePool->clear();                  pVoicePool->clear();
78    
79                    // init all Note objects in note pool
80                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
81                         itNote = pNotePool->allocAppend())
82                    {
83                        itNote->init(pVoicePool, &noteIDPool);
84                    }
85                    pNotePool->clear();
86    
87                  ResetInternal();                  ResetInternal();
88                  ResetScaleTuning();                  ResetScaleTuning();
89                  ResetSuspendedRegions();                  ResetSuspendedRegions();
# Line 80  namespace LinuxSampler { Line 97  namespace LinuxSampler {
97                      dmsg(1,("OK\n"));                      dmsg(1,("OK\n"));
98                  }                  }
99    
100                    if (pNotePool) {
101                        pNotePool->clear();
102                        delete pNotePool;
103                    }
104    
105                  if (pVoicePool) {                  if (pVoicePool) {
106                      pVoicePool->clear();                      pVoicePool->clear();
107                      delete pVoicePool;                      delete pVoicePool;
# Line 236  namespace LinuxSampler { Line 258  namespace LinuxSampler {
258                      pChannel->ResetRegionsInUse(pRegionPool);                      pChannel->ResetRegionsInUse(pRegionPool);
259                  }                  }
260    
261                    // FIXME: Shouldn't all those pool elements be freed before resizing the pools?
262                  try {                  try {
263                      pVoicePool->resizePool(iVoices);                      pVoicePool->resizePool(iVoices);
264                        pNotePool->resizePool(iVoices * MAX_NOTES_HEADROOM);
265                        noteIDPool.resizePool(iVoices * MAX_NOTES_HEADROOM);
266                  } catch (...) {                  } catch (...) {
267                      throw Exception("FATAL: Could not resize voice pool!");                      throw Exception("FATAL: Could not resize voice pool!");
268                  }                  }
269    
270                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend();
271                         iterVoice; iterVoice = pVoicePool->allocAppend())
272                    {
273                      iterVoice->SetEngine(this);                      iterVoice->SetEngine(this);
274                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
275                  }                  }
276                  pVoicePool->clear();                  pVoicePool->clear();
277    
278                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
279                         itNote = pNotePool->allocAppend())
280                    {
281                        itNote->init(pVoicePool, &noteIDPool);
282                    }
283                    pNotePool->clear();
284    
285                  PostSetMaxVoices(iVoices);                  PostSetMaxVoices(iVoices);
286                  ResumeAll();                  ResumeAll();
287              }              }
# Line 316  namespace LinuxSampler { Line 350  namespace LinuxSampler {
350                      MinFadeOutSamples = MaxSamplesPerCycle;                      MinFadeOutSamples = MaxSamplesPerCycle;
351                      // lower minimum release time                      // lower minimum release time
352                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
353                        pVoicePool->clear();
354                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
355                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
356                      }                      }
# Line 336  namespace LinuxSampler { Line 371  namespace LinuxSampler {
371                      exit(EXIT_FAILURE);                      exit(EXIT_FAILURE);
372                  }                  }
373    
374                    pVoicePool->clear();
375                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
376                      iterVoice->pDiskThread = this->pDiskThread;                      iterVoice->pDiskThread = this->pDiskThread;
377                      dmsg(3,("d"));                      dmsg(3,("d"));
# Line 565  namespace LinuxSampler { Line 601  namespace LinuxSampler {
601                  return pRegionPool[index];                  return pRegionPool[index];
602              }              }
603    
604              // implementation of abstract method derived from class 'LinuxSampler::VoicePool'              // implementation of abstract methods derived from class 'LinuxSampler::NotePool'
605              virtual Pool<V>* GetVoicePool() { return pVoicePool; }              virtual Pool<V>* GetVoicePool() OVERRIDE { return pVoicePool; }
606                virtual Pool< Note<V> >* GetNotePool() OVERRIDE { return pNotePool; }
607                virtual Pool<note_id_t>* GetNodeIDPool() OVERRIDE { return &noteIDPool; }
608    
609              D* GetDiskThread() { return pDiskThread; }              D* GetDiskThread() { return pDiskThread; }
610    
# Line 586  namespace LinuxSampler { Line 624  namespace LinuxSampler {
624                  }                  }
625    
626                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
627                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();                      NoteIterator  itNote  = pMidiKey->pActiveNotes->first();
628                        VoiceIterator itVoice = itNote->pActiveVoices->first();
629                      // if current key is not associated with this region, skip this key                      // if current key is not associated with this region, skip this key
630                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
631    
# Line 609  namespace LinuxSampler { Line 648  namespace LinuxSampler {
648    
649              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)              int                          ActiveVoiceCountTemp;  ///< number of currently active voices (for internal usage, will be used for incrementation)
650              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.              VoiceIterator                itLastStolenVoice;     ///< Only for voice stealing: points to the last voice which was theft in current audio fragment, NULL otherwise.
651                NoteIterator                 itLastStolenNote;      ///< Only for voice stealing: points to the last note from which was theft in current audio fragment, NULL otherwise.
652              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.              RTList<uint>::Iterator       iuiLastStolenKey;      ///< Only for voice stealing: key number of last key on which the last voice was theft in current audio fragment, NULL otherwise.
653              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.              EngineChannelBase<V, R, I>*  pLastStolenChannel;    ///< Only for voice stealing: points to the engine channel on which the previous voice was stolen in this audio fragment.
654              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally              VoiceIterator                itLastStolenVoiceGlobally; ///< Same as itLastStolenVoice, but engine globally
655                NoteIterator                 itLastStolenNoteGlobally; ///< Same as itLastStolenNote, but engine globally
656              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally              RTList<uint>::Iterator       iuiLastStolenKeyGlobally;  ///< Same as iuiLastStolenKey, but engine globally
657              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.              RTList<Event>*               pVoiceStealingQueue;   ///< All voice-launching events which had to be postponed due to free voice shortage.
658              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).              Mutex                        ResetInternalMutex;    ///< Mutex to protect the ResetInternal function for concurrent usage (e.g. by the lscp and instrument loader threads).
659              int iMaxDiskStreams;              int iMaxDiskStreams;
660    
661                NoteBase* NoteByID(note_id_t id) OVERRIDE {
662                    NoteIterator itNote = GetNotePool()->fromID(id);
663                    if (!itNote) return NULL;
664                    return &*itNote;
665                }
666    
667                /**
668                 * Gets a new @c Note object from the note pool, initializes it
669                 * appropriately, links it with requested parent note (if
670                 * requested), moves it to the appropriate key's list of active
671                 * notes it, and sticks the new note's unique ID to the
672                 * passed @a pNoteOnEvent.
673                 *
674                 * @param pEngineChannel - engine channel on which this event happened
675                 * @param pNoteOnEvent - event which caused this
676                 * @returns new note's unique ID (or zero on error)
677                 */
678                note_id_t LaunchNewNote(LinuxSampler::EngineChannel* pEngineChannel, Event* pNoteOnEvent) OVERRIDE {
679                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
680                    Pool< Note<V> >* pNotePool = GetNotePool();
681    
682                    if (pNotePool->poolIsEmpty()) {
683                        dmsg(1,("Engine: Could not launch new note; Note pool empty!\n"));
684                        return 0; // error
685                    }
686    
687                    // create a new note (for new voices to be assigned to)
688                    //NoteIterator itNewNote = pKey->pActiveNotes->allocAppend();
689                    NoteIterator itNewNote = pNotePool->allocAppend();
690                    const note_id_t newNoteID = pNotePool->getID(itNewNote);
691    
692                    // usually the new note (and its subsequent voices) will be
693                    // allocated on the key provided by the event's note number,
694                    // however if this new note is requested not to be a regular
695                    // note, but rather a child note, then this new note will be
696                    // allocated on the parent note's key instead in order to
697                    // release the child note simultaniously with its parent note
698                    itNewNote->hostKey = pNoteOnEvent->Param.Note.Key;
699    
700                    // in case this new note was requested to be a child note,
701                    // then retrieve its parent note and link them with each other
702                    const note_id_t parentNoteID = pNoteOnEvent->Param.Note.ParentNoteID;
703                    if (parentNoteID) {
704                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
705                        if (itParentNote) {
706                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
707                            if (itChildNoteID) {
708                                // link parent and child note with each other
709                                *itChildNoteID = newNoteID;
710                                itNewNote->parentNoteID = parentNoteID;
711                                itNewNote->hostKey = itParentNote->hostKey;
712                            } else {    
713                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
714                                pNotePool->free(itNewNote);
715                                return 0; // error
716                            }
717                        } else {
718                            // the parent note was apparently released already, so
719                            // free the new note again and inform caller that it
720                            // should drop the event
721                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
722                            pNotePool->free(itNewNote);
723                            return 0; // error
724                        }
725                    }
726    
727                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
728    
729                    // copy event which caused this note
730                    itNewNote->cause = *pNoteOnEvent;
731                    itNewNote->eventID = pEventPool->getID(pNoteOnEvent);
732    
733                    // move new note to its host key
734                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
735                    itNewNote.moveToEndOf(pKey->pActiveNotes);
736    
737                    // assign unique note ID of this new note to the original note on event
738                    pNoteOnEvent->Param.Note.ID = newNoteID;
739    
740                    return newNoteID; // success
741                }
742    
743              /**              /**
744               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
745               * engine channel.               * engine channel.
# Line 648  namespace LinuxSampler { Line 771  namespace LinuxSampler {
771                      //                      //
772                      // FIXME: it would probably be better to just schedule newly spawned script executions here and then execute them altogether with already suspended ones all at once in order of all their scheduled timing                      // FIXME: it would probably be better to just schedule newly spawned script executions here and then execute them altogether with already suspended ones all at once in order of all their scheduled timing
773                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
774                          end = pChannel->pEvents->end(); itEvent != end; ++itEvent)                          end = pChannel->pEvents->end(); itEvent != end; )
775                      {                      {
776                            //HACK: avoids iterator invalidation which might happen below since an instrument script might drop an event by direct raw pointer access (it would be considerable to extend the Iterator class to detect and circumvent this case by checking the "reincarnation" member variable).
777                            RTList<Event>::Iterator itNext = itEvent;
778                            ++itNext;
779    
780                          switch (itEvent->Type) {                          switch (itEvent->Type) {
781                              case Event::type_note_on:                              case Event::type_note_on:
782                                  if (pChannel->pScript->handlerNote)                                  if (pChannel->pScript->handlerNote)
# Line 669  namespace LinuxSampler { Line 796  namespace LinuxSampler {
796                                  //TODO: ...                                  //TODO: ...
797                                  break;                                  break;
798                          }                          }
799    
800                            // see HACK comment above
801                            itEvent = itNext;
802                      }                      }
803    
804                      // this has to be run again, since the newly spawned scripts                      // this has to be run again, since the newly spawned scripts
# Line 750  namespace LinuxSampler { Line 880  namespace LinuxSampler {
880                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
881                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
882                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
883                    itLastStolenNote          = NoteIterator();
884                    itLastStolenNoteGlobally  = NoteIterator();
885                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
886                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
887                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
# Line 841  namespace LinuxSampler { Line 973  namespace LinuxSampler {
973    
974                  // initialize/reset other members                  // initialize/reset other members
975                  itScriptEvent->cause = *itEvent;                  itScriptEvent->cause = *itEvent;
                 itScriptEvent->id = pEventPool->getID(itEvent);  
976                  itScriptEvent->currentHandler = 0;                  itScriptEvent->currentHandler = 0;
977                  itScriptEvent->executionSlices = 0;                  itScriptEvent->executionSlices = 0;
978                    // this is the native representation of the $EVENT_ID script variable
979                    itScriptEvent->id =
980                        (itEvent->Type == Event::type_note_on)
981                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
982                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
983    
984                  // run script handler(s)                  // run script handler(s)
985                  VMExecStatus_t res = pScriptVM->exec(                  VMExecStatus_t res = pScriptVM->exec(
# Line 886  namespace LinuxSampler { Line 1022  namespace LinuxSampler {
1022              /** @brief Resume execution of instrument script.              /** @brief Resume execution of instrument script.
1023               *               *
1024               * Will be called to resume execution of a real-time instrument               * Will be called to resume execution of a real-time instrument
1025               * script event which has been suspended in a previous audio               * script event which has been suspended previously.
              * fragment cycle.  
1026               *               *
1027               * Script execution might be suspended for various reasons. Usually               * Script execution might be suspended for various reasons. Usually
1028               * a script will be suspended if the script called the built-in               * a script will be suspended if the script called the built-in
# Line 951  namespace LinuxSampler { Line 1086  namespace LinuxSampler {
1086               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1087               *  @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing               *  @returns 0 on success, a value < 0 if no active voice could be picked for voice stealing
1088               */               */
1089              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1090                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1091                      dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));                      dmsg(1,("Max. voice thefts per audio fragment reached (you may raise CONFIG_MAX_VOICES).\n"));
1092                      return -1;                      return -1;
# Line 959  namespace LinuxSampler { Line 1094  namespace LinuxSampler {
1094    
1095                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1096    
1097                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1098                        dmsg(1,("Event pool emtpy!\n"));
1099                        return -1;
1100                    }
1101    
1102                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1103                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1104                          return 0;                      return 0;
1105                      }                  }
1106    
1107                      // if we couldn't steal a voice from the same engine channel then                  // if we couldn't steal a voice from the same engine channel then
1108                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1109                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1110                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1111                      int                       iChannelIndex;                  int                          iChannelIndex;
1112                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1113    
1114                      // select engine channel                  // select engine channel
1115                      if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1116                          pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
1117                          iChannelIndex    = pSelectedChannel->iEngineIndexSelf;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1118                      } else { // pick the engine channel followed by this engine channel                  } else { // pick the engine channel followed by this engine channel
1119                          iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1120                          pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1121                      }                  }
1122    
1123                      // if we already stole in this fragment, try to proceed on same key                  // if we already stole in this fragment, try to proceed on same note
1124                      if (this->itLastStolenVoiceGlobally) {                  if (this->itLastStolenVoiceGlobally) {
1125                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1126                          do {                      do {
1127                              ++itSelectedVoice;                          ++itSelectedVoice;
1128                          } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle                      } while (itSelectedVoice && !itSelectedVoice->IsStealable()); // proceed iterating if voice was created in this fragment cycle
1129                    }
1130                    // did we find a 'stealable' voice?
1131                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1132                        // remember which voice we stole, so we can simply proceed on next voice stealing
1133                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1134                        // done
1135                        goto stealable_voice_found;
1136                    }
1137    
1138                    // get (next) oldest note
1139                    if (this->itLastStolenNoteGlobally) {
1140                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1141                             itNote; ++itNote)
1142                        {
1143                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1144                                // proceed iterating if voice was created in this audio fragment cycle
1145                                if (itSelectedVoice->IsStealable()) {
1146                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1147                                    this->itLastStolenNoteGlobally  = itNote;
1148                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1149                                    goto stealable_voice_found; // selection succeeded
1150                                }
1151                            }
1152                      }                      }
1153                    }
1154    
1155                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1156                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1157                      #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1158    
1159                      // did we find a 'stealable' voice?                  while (true) { // iterate through engine channels                        
1160                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                      // get (next) oldest key
1161                          // remember which voice we stole, so we can simply proceed on next voice stealing                      RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();
1162                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1163                      } else while (true) { // iterate through engine channels                      while (iuiSelectedKey) {
1164                          // get (next) oldest key                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1165                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();  
1166                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                          for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1167                          while (iuiSelectedKey) {                               itNotesEnd = pSelectedKey->pActiveNotes->end();
1168                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                               itNote != itNotesEnd; ++itNote)
1169                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                          {
1170                                itSelectedVoice = itNote->pActiveVoices->first();
1171                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1172                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1173                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1174                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1175                                  // remember which voice on which key on which engine channel we stole, so we can simply proceed on next voice stealing                                  // remember which voice of which note on which key on which engine channel we stole, so we can simply proceed on next voice stealing
1176                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1177                                    this->itLastStolenNoteGlobally  = itNote;
1178                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1179                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1180                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1181                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
                         }  
                         // get next engine channel  
                         iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();  
                         pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);  
   
                         #if CONFIG_DEVMODE  
                         if (pSelectedChannel == pBegin) {  
                             dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));  
                             dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));  
                             dmsg(1,("Exiting.\n"));  
                             exit(-1);  
1182                          }                          }
1183                          #endif // CONFIG_DEVMODE                          ++iuiSelectedKey; // get next key on current engine channel
1184                      }                      }
1185                        // get next engine channel
1186                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1187                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1188    
1189                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1190                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1191                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1192                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1193                            dmsg(1,("Exiting.\n"));
1194                            exit(-1);
1195                      }                      }
1196                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1197                    }
1198    
1199                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1200                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
   
                     --VoiceSpawnsLeft;  
1201    
1202                      return 0; // success                  #if CONFIG_DEVMODE
1203                  }                  if (!itSelectedVoice->IsActive()) {
1204                  else {                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                     dmsg(1,("Event pool emtpy!\n"));  
1205                      return -1;                      return -1;
1206                  }                  }
1207                    #endif // CONFIG_DEVMODE
1208    
1209                    // now kill the selected voice
1210                    itSelectedVoice->Kill(itNoteOnEvent);
1211    
1212                    --VoiceSpawnsLeft;
1213    
1214                    return 0; // success
1215              }              }
1216    
1217              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 1145  namespace LinuxSampler { Line 1305  namespace LinuxSampler {
1305                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1306                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1307                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1308                        
1309                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1310                          LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);                          LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
1311                      if (itNewVoice) {                      if (itNewVoice) {
1312                            // usually there should already be a new Note object
1313                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1314                            if (!itNote) { // should not happen, but just to be sure ...
1315                                const note_id_t noteID = LaunchNewNote(pEngineChannel, &*itVoiceStealEvent);
1316                                if (!noteID) {
1317                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1318                                    continue;
1319                                }
1320                                itNote = GetNotePool()->fromID(noteID);
1321                            }
1322                            // move voice from whereever it was, to the new note's list of active voices
1323                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1324                            // render audio of this new voice for the first time
1325                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1326                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1327                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 1419  namespace LinuxSampler { Line 1593  namespace LinuxSampler {
1593                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1594                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1595    
                 //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing  
                 int k = itNoteOnEvent->Param.Note.Key + pChannel->GlobalTranspose;  
                 if (k < 0 || k > 127) return; //ignore keys outside the key range  
   
                 itNoteOnEvent->Param.Note.Key += pChannel->GlobalTranspose;  
                 int vel = itNoteOnEvent->Param.Note.Velocity;  
   
1596                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1597                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1598                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1599    
1600                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1601    
1602                  pChannel->listeners.PreProcessNoteOn(key, vel);                  pChannel->listeners.PreProcessNoteOn(key, vel);
# Line 1454  namespace LinuxSampler { Line 1624  namespace LinuxSampler {
1624                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1625                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1626                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1627                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1628                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1629                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1630                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1631                                    }
1632                              }                              }
1633                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1634                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1635                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1636                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1637                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1638                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1639                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1640                                    }
1641                              }                              }
1642                          }                          }
1643                      }                      }
# Line 1530  namespace LinuxSampler { Line 1705  namespace LinuxSampler {
1705              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1706                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1707    
                 int k = itNoteOffEvent->Param.Note.Key + pChannel->GlobalTranspose;  
                 if (k < 0 || k > 127) return; //ignore keys outside the key range  
   
                 //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing  
                 itNoteOffEvent->Param.Note.Key += pChannel->GlobalTranspose;  
                 int vel = itNoteOffEvent->Param.Note.Velocity;  
   
1708                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1709                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1710                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1711    
1712                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1713    
1714                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  pChannel->listeners.PreProcessNoteOff(iKey, vel);
# Line 1571  namespace LinuxSampler { Line 1742  namespace LinuxSampler {
1742                                  pChannel->SoloKey = i;                                  pChannel->SoloKey = i;
1743                                  // get final portamento position of currently active voice                                  // get final portamento position of currently active voice
1744                                  if (pChannel->PortamentoMode) {                                  if (pChannel->PortamentoMode) {
1745                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                      NoteIterator itNote = pKey->pActiveNotes->first();
1746                                        VoiceIterator itVoice = itNote->pActiveVoices->first();
1747                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1748                                  }                                  }
1749                                  // create a pseudo note on event                                  // create a pseudo note on event
# Line 1583  namespace LinuxSampler { Line 1755  namespace LinuxSampler {
1755                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;
1756                                      itPseudoNoteOnEvent->Param.Note.Key      = i;                                      itPseudoNoteOnEvent->Param.Note.Key      = i;
1757                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1758                                      // allocate and trigger new voice(s) for the other key                                      // assign a new note to this note-on event
1759                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                      if (LaunchNewNote(pChannel, &*itPseudoNoteOnEvent)) {
1760                                            // allocate and trigger new voice(s) for the other key
1761                                            TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1762                                        }
1763                                      // if neither a voice was spawned or postponed then remove note on event from key again                                      // if neither a voice was spawned or postponed then remove note on event from key again
1764                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1765                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);
# Line 1597  namespace LinuxSampler { Line 1772  namespace LinuxSampler {
1772                      if (bOtherKeysPressed) {                      if (bOtherKeysPressed) {
1773                          if (pKey->Active) { // kill all voices on this key                          if (pKey->Active) { // kill all voices on this key
1774                              bShouldRelease = false; // no need to release, as we kill it here                              bShouldRelease = false; // no need to release, as we kill it here
1775                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                              for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1776                              VoiceIterator end               = pKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1777                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1778                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1779                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1780                                            itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1781                                    }
1782                              }                              }
1783                          }                          }
1784                      } else pChannel->PortamentoPos = -1.0f;                      } else pChannel->PortamentoPos = -1.0f;
# Line 1610  namespace LinuxSampler { Line 1787  namespace LinuxSampler {
1787                  // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed                  // if no solo mode (the usual case) or if solo mode and no other key pressed, then release voices on this key if needed
1788                  if (bShouldRelease) {                  if (bShouldRelease) {
1789                      itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type                      itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type
   
1790                      // spawn release triggered voice(s) if needed                      // spawn release triggered voice(s) if needed
1791                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
                         TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);  
                         pKey->ReleaseTrigger = false;  
                     }  
1792                  }                  }
1793    
1794                  // if neither a voice was spawned or postponed on this key then remove note off event from key again                  // if neither a voice was spawned or postponed on this key then remove note off event from key again
# Line 1626  namespace LinuxSampler { Line 1799  namespace LinuxSampler {
1799              }              }
1800    
1801              /**              /**
1802                 * Called on sustain pedal up events to check and if required,
1803                 * launch release trigger voices on the respective active key.
1804                 *
1805                 * @param pEngineChannel - engine channel on which this event occurred on
1806                 * @param itEvent - release trigger event (contains note number)
1807                 */
1808                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1809                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1810    
1811                    const int iKey = itEvent->Param.Note.Key;
1812                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1813    
1814                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1815    
1816                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1817                }
1818    
1819                /**
1820                 * Called on note-off and sustain pedal up events to check and if
1821                 * required, launch release trigger voices on the respective active
1822                 * key.
1823                 *
1824                 * @param pEngineChannel - engine channel on which this event occurred on
1825                 * @param itEvent - note off event / release trigger event
1826                 * @param pKey - key on which the release trigger voices shall be spawned
1827                 */
1828                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1829                    // spawn release triggered voice(s) if needed
1830                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1831                        // assign a new note to this release event
1832                        if (LaunchNewNote(pChannel, &*itEvent)) {
1833                            // allocate and trigger new release voice(s)
1834                            TriggerReleaseVoices(pChannel, itEvent);
1835                        }
1836                        pKey->ReleaseTrigger = false;
1837                    }
1838                }
1839    
1840                /**
1841               *  Reset all voices and disk thread and clear input event queue and all               *  Reset all voices and disk thread and clear input event queue and all
1842               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
1843               */               */
# Line 1642  namespace LinuxSampler { Line 1854  namespace LinuxSampler {
1854                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
1855                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
1856                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
1857                    itLastStolenNote           = NoteIterator();
1858                    itLastStolenNoteGlobally   = NoteIterator();
1859                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
1860                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
1861                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
1862    
1863                    // reset all notes
1864                    pNotePool->clear();
1865                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
1866                         itNote = pNotePool->allocAppend())
1867                    {
1868                        itNote->reset();
1869                    }
1870                    pNotePool->clear();
1871    
1872                  // reset all voices                  // reset all voices
1873                    pVoicePool->clear();
1874                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1875                      iterVoice->Reset();                      iterVoice->Reset();
1876                  }                  }
# Line 1730  namespace LinuxSampler { Line 1954  namespace LinuxSampler {
1954                      // launch the new voice                      // launch the new voice
1955                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
1956                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
1957                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
1958                      }                      }
1959                      else { // on success                      else { // on success
1960                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
# Line 1779  namespace LinuxSampler { Line 2003  namespace LinuxSampler {
2003              }              }
2004    
2005          private:          private:
2006                Pool< Note<V> >* pNotePool;
2007                Pool<note_id_t> noteIDPool;
2008              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2009              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2010              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

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

  ViewVC Help
Powered by ViewVC