/[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 2559 by schoenebeck, Sun May 18 17:38:25 2014 UTC revision 2972 by schoenebeck, Fri Jul 22 14:37:34 2016 UTC
# Line 4  Line 4 
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2013 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8     *   Copyright (C) 2012-2016 Christian Schoenebeck and Andreas Persson     *
9   *                                                                         *   *                                                                         *
10   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
11   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 32  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 45  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 79  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 235  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 315  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 335  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 432  namespace LinuxSampler { Line 469  namespace LinuxSampler {
469               * @param pRegion - region the engine shall stop using               * @param pRegion - region the engine shall stop using
470               */               */
471              virtual void Suspend(RR* pRegion) {              virtual void Suspend(RR* pRegion) {
472                  dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Suspending Region %p ...\n",(void*)pRegion));
473                  {                  {
474                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
475                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
476                      pPendingRegionSuspension = pRegion;                      pPendingRegionSuspension = pRegion;
477                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
478                  }                  }
479                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
480              }              }
481    
482              /**              /**
# Line 449  namespace LinuxSampler { Line 486  namespace LinuxSampler {
486               * @param pRegion - region the engine shall be allowed to use again               * @param pRegion - region the engine shall be allowed to use again
487               */               */
488              virtual void Resume(RR* pRegion) {              virtual void Resume(RR* pRegion) {
489                  dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Resuming Region %p ...\n",(void*)pRegion));
490                  {                  {
491                      LockGuard lock(SuspendedRegionsMutex);                      LockGuard lock(SuspendedRegionsMutex);
492                      SuspensionChangeOngoing.Set(true);                      SuspensionChangeOngoing.Set(true);
493                      pPendingRegionResumption = pRegion;                      pPendingRegionResumption = pRegion;
494                      SuspensionChangeOngoing.WaitAndUnlockIf(true);                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
495                  }                  }
496                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
497              }              }
498    
499              virtual void ResetSuspendedRegions() {              virtual void ResetSuspendedRegions() {
# Line 564  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 585  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 608  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                    // remember the engine's time when this note was triggered exactly
693                    itNewNote->triggerSchedTime = pNoteOnEvent->SchedTime();
694    
695                    // usually the new note (and its subsequent voices) will be
696                    // allocated on the key provided by the event's note number,
697                    // however if this new note is requested not to be a regular
698                    // note, but rather a child note, then this new note will be
699                    // allocated on the parent note's key instead in order to
700                    // release the child note simultaniously with its parent note
701                    itNewNote->hostKey = pNoteOnEvent->Param.Note.Key;
702    
703                    // in case this new note was requested to be a child note,
704                    // then retrieve its parent note and link them with each other
705                    const note_id_t parentNoteID = pNoteOnEvent->Param.Note.ParentNoteID;
706                    if (parentNoteID) {
707                        NoteIterator itParentNote = pNotePool->fromID(parentNoteID);                        
708                        if (itParentNote) {
709                            RTList<note_id_t>::Iterator itChildNoteID = itParentNote->pChildNotes->allocAppend();
710                            if (itChildNoteID) {
711                                // link parent and child note with each other
712                                *itChildNoteID = newNoteID;
713                                itNewNote->parentNoteID = parentNoteID;
714                                itNewNote->hostKey = itParentNote->hostKey;
715                            } else {    
716                                dmsg(1,("Engine: Could not assign new note as child note; Note ID pool empty!\n"));
717                                pNotePool->free(itNewNote);
718                                return 0; // error
719                            }
720                        } else {
721                            // the parent note was apparently released already, so
722                            // free the new note again and inform caller that it
723                            // should drop the event
724                            dmsg(3,("Engine: Could not assign new note as child note; Parent note is gone!\n"));
725                            pNotePool->free(itNewNote);
726                            return 0; // error
727                        }
728                    }
729    
730                    dmsg(2,("Launched new note on host key %d\n", itNewNote->hostKey));
731    
732                    // copy event which caused this note
733                    itNewNote->cause = *pNoteOnEvent;
734                    itNewNote->eventID = pEventPool->getID(pNoteOnEvent);
735    
736                    // move new note to its host key
737                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[itNewNote->hostKey];
738                    itNewNote.moveToEndOf(pKey->pActiveNotes);
739    
740                    // assign unique note ID of this new note to the original note on event
741                    pNoteOnEvent->Param.Note.ID = newNoteID;
742    
743                    return newNoteID; // success
744                }
745    
746              /**              /**
747               * Dispatch and handle all events in this audio fragment for the given               * Dispatch and handle all events in this audio fragment for the given
748               * engine channel.               * engine channel.
# Line 631  namespace LinuxSampler { Line 758  namespace LinuxSampler {
758                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
759                  pChannel->ImportEvents(Samples);                  pChannel->ImportEvents(Samples);
760    
761                  // process events                  // if a valid real-time instrument script is loaded, pre-process
762                    // the event list by running the script now, since the script
763                    // might filter events or add new ones for this cycle
764                    if (pChannel->pScript) {
765                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
766    
767                        // resume suspended script executions been scheduled for
768                        // this audio fragment cycle (which were suspended in a
769                        // previous audio fragment cycle)
770                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
771    
772                        // spawn new script executions for the new MIDI events of
773                        // this audio fragment cycle
774                        //
775                        // 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
776                        for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
777                            end = pChannel->pEvents->end(); itEvent != end; )
778                        {
779                            //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).
780                            RTList<Event>::Iterator itNext = itEvent;
781                            ++itNext;
782    
783                            switch (itEvent->Type) {
784                                case Event::type_note_on:
785                                    if (pChannel->pScript->handlerNote)
786                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerNote);
787                                    break;
788                                case Event::type_note_off:
789                                    if (pChannel->pScript->handlerRelease)
790                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerRelease);
791                                    break;
792                                case Event::type_control_change:
793                                case Event::type_channel_pressure:
794                                case Event::type_pitchbend:
795                                    if (pChannel->pScript->handlerController)
796                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerController);                            
797                                    break;
798                                case Event::type_note_pressure:
799                                    //TODO: ...
800                                    break;
801                            }
802    
803                            // see HACK comment above
804                            itEvent = itNext;
805                        }
806    
807                        // this has to be run again, since the newly spawned scripts
808                        // above may have cause suspended scripts that must be
809                        // resumed within this same audio fragment cycle
810                        //
811                        // FIXME: see FIXME comment above
812                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
813                    }
814    
815                    // if there are any delayed events scheduled for the current
816                    // audio fragment cycle, then move and sort them into the main
817                    // event list
818                    if (!pChannel->delayedEvents.queue.isEmpty()) {
819                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
820                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
821                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
822                        while (true) {
823                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
824                                pEventGenerator->popNextScheduledEvent(
825                                    pChannel->delayedEvents.queue,
826                                    pChannel->delayedEvents.schedulerNodes,
827                                    fragmentEndTime
828                                );
829                            if (!itDelayedEventNode) break;
830                            // get the actual delayed event object and free the used scheduler node
831                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
832                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
833                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
834                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
835                                continue;
836                            }
837                            // skip all events on main event list which have a time
838                            // before (or equal to) the delayed event to be inserted
839                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
840                                 ++itEvent);
841                            // now move delayed event from delayedEvents.pList to
842                            // the current position on the main event list
843                            itEvent = itDelayedEvent.moveBefore(itEvent);
844                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
845                        }
846                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
847                    }
848    
849                    // now process all events regularly
850                  {                  {
851                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
852                      RTList<Event>::Iterator end     = pChannel->pEvents->end();                      RTList<Event>::Iterator end     = pChannel->pEvents->end();
# Line 641  namespace LinuxSampler { Line 856  namespace LinuxSampler {
856                                  dmsg(5,("Engine: Note on received\n"));                                  dmsg(5,("Engine: Note on received\n"));
857                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
858                                  break;                                  break;
859                                case Event::type_play_note:
860                                    dmsg(5,("Engine: Play Note received\n"));
861                                    ProcessNoteOn((EngineChannel*)itEvent->pEngineChannel, itEvent);
862                                    break;
863                              case Event::type_note_off:                              case Event::type_note_off:
864                                  dmsg(5,("Engine: Note off received\n"));                                  dmsg(5,("Engine: Note off received\n"));
865                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
866                                  break;                                  break;
867                                case Event::type_stop_note:
868                                    dmsg(5,("Engine: Stop Note received\n"));
869                                    ProcessNoteOff((EngineChannel*)itEvent->pEngineChannel, itEvent);
870                                    break;
871                              case Event::type_control_change:                              case Event::type_control_change:
872                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
873                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
# Line 661  namespace LinuxSampler { Line 884  namespace LinuxSampler {
884                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
885                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
886                                  break;                                  break;
887                                case Event::type_note_synth_param:
888                                    dmsg(5,("Engine: Note Synth Param received\n"));
889                                    ProcessNoteSynthParam(itEvent->pEngineChannel, itEvent);
890                                    break;
891                          }                          }
892                      }                      }
893                  }                  }
# Line 668  namespace LinuxSampler { Line 895  namespace LinuxSampler {
895                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
896                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
897                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
898                    itLastStolenNote          = NoteIterator();
899                    itLastStolenNoteGlobally  = NoteIterator();
900                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
901                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
902                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
903              }              }
904    
905              /**              /**
906                 * Run all suspended script execution instances which are scheduled
907                 * to be resumed for the current audio fragment cycle.
908                 *
909                 * @param pChannel - engine channel on which suspended events occurred
910                 */
911                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
912                    while (true) {
913                        RTList<ScriptEvent>::Iterator itEvent =
914                            pEventGenerator->popNextScheduledScriptEvent(
915                                pChannel->pScript->suspendedEvents,
916                                *pChannel->pScript->pEvents, fragmentEndTime
917                            );
918                        if (!itEvent) break;
919                        ResumeScriptEvent(pChannel, itEvent);
920                    }
921                }
922    
923                /** @brief Call instrument script's event handler for this event.
924                 *
925                 * Causes a new execution instance of the currently loaded real-time
926                 * instrument script's event handler (callback) to be spawned for
927                 * the given MIDI event.
928                 *
929                 * @param pChannel - engine channel on which the MIDI event occurred
930                 * @param itEvent - MIDI event that causes this new script execution
931                 * @param pEventHandler - script's event handler to be executed
932                 */
933                void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
934                    const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
935                    // check if polyphonic data is passed from "note" to "release"
936                    // script event handlers
937                    if (pEventHandler == pChannel->pScript->handlerRelease &&
938                        pChannel->pScript->handlerNote &&
939                        pChannel->pScript->handlerNote->isPolyphonic() &&
940                        pChannel->pScript->handlerRelease->isPolyphonic() &&
941                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
942                    {
943                        // polyphonic variable data is used/passed from "note" to
944                        // "release" script callback, so we have to recycle the
945                        // original "note on" script event(s)
946                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
947                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
948                        for (; it != end; ++it) {
949                            ProcessScriptEvent(
950                                pChannel, itEvent, pEventHandler, it
951                            );
952                        }
953                    } else {
954                        // no polyphonic data is used/passed from "note" to
955                        // "release" script callback, so just use a new fresh
956                        // script event object
957                        RTList<ScriptEvent>::Iterator itScriptEvent =
958                            pChannel->pScript->pEvents->allocAppend();
959                        ProcessScriptEvent(
960                            pChannel, itEvent, pEventHandler, itScriptEvent
961                        );
962                    }
963                }
964    
965                /** @brief Spawn new execution instance of an instrument script handler.
966                 *
967                 * Will be called to initiate a new execution of a real-time
968                 * instrument script event right from the start of the script's
969                 * respective handler. If script execution did not complete after
970                 * calling this method, the respective script exeuction is then
971                 * suspended and a call to ResumeScriptEvent() will be used next
972                 * time to continue its execution.
973                 *
974                 * @param pChannel - engine channel this script is running for
975                 * @param itEvent - event which caused execution of this script
976                 *                  event handler
977                 * @param pEventHandler - VM representation of event handler to be
978                 *                        executed
979                 * @param itScriptEvent - script event that shall be processed
980                 */
981                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
982                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
983    
984                    // fill the list of script handlers to be executed by this event
985                    int i = 0;
986                    itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
987                    itScriptEvent->handlers[i] = NULL; // NULL termination of list
988    
989                    // initialize/reset other members
990                    itScriptEvent->cause = *itEvent;
991                    itScriptEvent->currentHandler = 0;
992                    itScriptEvent->executionSlices = 0;
993                    itScriptEvent->ignoreAllWaitCalls = false;
994                    itScriptEvent->handlerType = pEventHandler->eventHandlerType();
995                    // this is the native representation of the $EVENT_ID script variable
996                    itScriptEvent->id =
997                        (itEvent->Type == Event::type_note_on)
998                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
999                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
1000    
1001                    // run script handler(s)
1002                    VMExecStatus_t res = pScriptVM->exec(
1003                        pChannel->pScript->parserContext, &*itScriptEvent
1004                    );
1005    
1006                    // was the script suspended?
1007                    if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
1008                        // in case the script was suspended, keep it on the allocated
1009                        // ScriptEvent list to be resume at the scheduled time in future,
1010                        // additionally insert it into a sorted time queue
1011                        pEventGenerator->scheduleAheadMicroSec(
1012                            pChannel->pScript->suspendedEvents, // scheduler queue
1013                            *itScriptEvent, // script event
1014                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1015                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1016                        );
1017                    } else { // script execution has finished without 'suspended' status ...
1018                        // if "polyphonic" variable data is passed from script's
1019                        // "note" event handler to its "release" event handler, then
1020                        // the script event must be kept and recycled for the later
1021                        // occuring "release" script event ...
1022                        if (pEventHandler == pChannel->pScript->handlerNote &&
1023                            pChannel->pScript->handlerRelease &&
1024                            pChannel->pScript->handlerNote->isPolyphonic() &&
1025                            pChannel->pScript->handlerRelease->isPolyphonic())
1026                        {
1027                            const int key = itEvent->Param.Note.Key;
1028                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1029                        } else {
1030                            // ... otherwise if no polyphonic data is passed and
1031                            // script's execution has finished without suspension
1032                            // status, then free the script event for a new future
1033                            // script event to be triggered from start
1034                            pChannel->pScript->pEvents->free(itScriptEvent);
1035                        }
1036                    }
1037                }
1038    
1039                /** @brief Resume execution of instrument script.
1040                 *
1041                 * Will be called to resume execution of a real-time instrument
1042                 * script event which has been suspended previously.
1043                 *
1044                 * Script execution might be suspended for various reasons. Usually
1045                 * a script will be suspended if the script called the built-in
1046                 * "wait()" function, but it might also be suspended automatically
1047                 * if the script took too much execution time in an audio fragment
1048                 * cycle. So in the latter case automatic suspension is performed in
1049                 * order to avoid harm for the sampler's overall real-time
1050                 * requirements.
1051                 *
1052                 * @param pChannel - engine channel this script is running for
1053                 * @param itScriptEvent - script execution that shall be resumed
1054                 */
1055                void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1056                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1057    
1058                    // run script
1059                    VMExecStatus_t res = pScriptVM->exec(
1060                        pChannel->pScript->parserContext, &*itScriptEvent
1061                    );
1062    
1063                    // was the script suspended?
1064                    if (res & VM_EXEC_SUSPENDED) {
1065                        // in case the script was suspended, keep it on the allocated
1066                        // ScriptEvent list to be resume at the scheduled time in future,
1067                        // additionally insert it into a sorted time queue
1068                        pEventGenerator->scheduleAheadMicroSec(
1069                            pChannel->pScript->suspendedEvents, // scheduler queue
1070                            *itScriptEvent, // script event
1071                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1072                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1073                        );
1074                    } else { // script execution has finished without 'suspended' status ...
1075                        // if "polyphonic" variable data is passed from script's
1076                        // "note" event handler to its "release" event handler, then
1077                        // the script event must be kept and recycled for the later
1078                        // occuring "release" script event ...
1079                        if (handler && handler == pChannel->pScript->handlerNote &&
1080                            pChannel->pScript->handlerRelease &&
1081                            pChannel->pScript->handlerNote->isPolyphonic() &&
1082                            pChannel->pScript->handlerRelease->isPolyphonic())
1083                        {
1084                            const int key = itScriptEvent->cause.Param.Note.Key;
1085                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1086                        } else {
1087                            // ... otherwise if no polyphonic data is passed and
1088                            // script's execution has finished without suspension
1089                            // status, then free the script event for a new future
1090                            // script event to be triggered from start
1091                            pChannel->pScript->pEvents->free(itScriptEvent);
1092                        }
1093                    }
1094                }
1095    
1096                /**
1097               *  Will be called by LaunchVoice() method in case there are no free               *  Will be called by LaunchVoice() method in case there are no free
1098               *  voices left. This method will select and kill one old voice for               *  voices left. This method will select and kill one old voice for
1099               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1100               *  voice actually died.               *  voice actually died.
1101               *               *
1102               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1103               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1104               *  @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
1105               */               */
1106              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1107                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1108                      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"));
1109                      return -1;                      return -1;
# Line 691  namespace LinuxSampler { Line 1111  namespace LinuxSampler {
1111    
1112                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1113    
1114                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1115                        dmsg(1,("Event pool emtpy!\n"));
1116                        return -1;
1117                    }
1118    
1119                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1120                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1121                          return 0;                      return 0;
1122                      }                  }
1123    
1124                      // 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
1125                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1126                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1127                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1128                      int                       iChannelIndex;                  int                          iChannelIndex;
1129                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1130    
1131                      // select engine channel                  // select engine channel
1132                      if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1133                          pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
1134                          iChannelIndex    = pSelectedChannel->iEngineIndexSelf;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1135                      } else { // pick the engine channel followed by this engine channel                  } else { // pick the engine channel followed by this engine channel
1136                          iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1137                          pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1138                      }                  }
1139    
1140                      // 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
1141                      if (this->itLastStolenVoiceGlobally) {                  if (this->itLastStolenVoiceGlobally) {
1142                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1143                          do {                      do {
1144                              ++itSelectedVoice;                          ++itSelectedVoice;
1145                          } 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
1146                    }
1147                    // did we find a 'stealable' voice?
1148                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1149                        // remember which voice we stole, so we can simply proceed on next voice stealing
1150                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1151                        // done
1152                        goto stealable_voice_found;
1153                    }
1154    
1155                    // get (next) oldest note
1156                    if (this->itLastStolenNoteGlobally) {
1157                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1158                             itNote; ++itNote)
1159                        {
1160                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1161                                // proceed iterating if voice was created in this audio fragment cycle
1162                                if (itSelectedVoice->IsStealable()) {
1163                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1164                                    this->itLastStolenNoteGlobally  = itNote;
1165                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1166                                    goto stealable_voice_found; // selection succeeded
1167                                }
1168                            }
1169                      }                      }
1170                    }
1171    
1172                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1173                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1174                      #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1175    
1176                      // did we find a 'stealable' voice?                  while (true) { // iterate through engine channels                        
1177                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                      // get (next) oldest key
1178                          // 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();
1179                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1180                      } else while (true) { // iterate through engine channels                      while (iuiSelectedKey) {
1181                          // get (next) oldest key                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1182                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();  
1183                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                          for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1184                          while (iuiSelectedKey) {                               itNotesEnd = pSelectedKey->pActiveNotes->end();
1185                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                               itNote != itNotesEnd; ++itNote)
1186                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                          {
1187                                itSelectedVoice = itNote->pActiveVoices->first();
1188                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1189                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1190                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1191                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1192                                  // 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
1193                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1194                                    this->itLastStolenNoteGlobally  = itNote;
1195                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1196                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1197                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1198                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
1199                          }                          }
1200                          // get next engine channel                          ++iuiSelectedKey; // get next key on current 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);  
                         }  
                         #endif // CONFIG_DEVMODE  
1201                      }                      }
1202                        // get next engine channel
1203                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1204                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1205    
1206                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1207                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1208                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1209                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1210                            dmsg(1,("Exiting.\n"));
1211                            exit(-1);
1212                      }                      }
1213                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1214                    }
1215    
1216                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1217                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
   
                     --VoiceSpawnsLeft;  
1218    
1219                      return 0; // success                  #if CONFIG_DEVMODE
1220                  }                  if (!itSelectedVoice->IsActive()) {
1221                  else {                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                     dmsg(1,("Event pool emtpy!\n"));  
1222                      return -1;                      return -1;
1223                  }                  }
1224                    #endif // CONFIG_DEVMODE
1225    
1226                    // now kill the selected voice
1227                    itSelectedVoice->Kill(itNoteOnEvent);
1228    
1229                    --VoiceSpawnsLeft;
1230    
1231                    return 0; // success
1232              }              }
1233    
1234              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 805  namespace LinuxSampler { Line 1250  namespace LinuxSampler {
1250                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1251                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1252                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1253                            pEngineChannel->pScript =
1254                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1255                          instrumentChanged = true;                          instrumentChanged = true;
1256    
1257                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
1258    
1259                            // the script's "init" event handler is only executed
1260                            // once (when the script is loaded or reloaded)
1261                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1262                                dmsg(5,("Engine: exec handlerInit %p\n", pEngineChannel->pScript->handlerInit));
1263                                RTList<ScriptEvent>::Iterator itScriptEvent =
1264                                    pEngineChannel->pScript->pEvents->allocAppend();
1265    
1266                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
1267                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1268                                itScriptEvent->handlers[1] = NULL;
1269                                itScriptEvent->currentHandler = 0;
1270                                itScriptEvent->executionSlices = 0;
1271                                itScriptEvent->ignoreAllWaitCalls = false;
1272                                itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT;
1273    
1274                                VMExecStatus_t res = pScriptVM->exec(
1275                                    pEngineChannel->pScript->parserContext, &*itScriptEvent
1276                                );
1277    
1278                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
1279                            }
1280                      }                      }
1281                  }                  }
1282    
# Line 858  namespace LinuxSampler { Line 1327  namespace LinuxSampler {
1327                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1328                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1329                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1330                        
1331                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1332                          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);
1333                      if (itNewVoice) {                      if (itNewVoice) {
1334                            // usually there should already be a new Note object
1335                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1336                            if (!itNote) { // should not happen, but just to be sure ...
1337                                const note_id_t noteID = LaunchNewNote(pEngineChannel, &*itVoiceStealEvent);
1338                                if (!noteID) {
1339                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1340                                    continue;
1341                                }
1342                                itNote = GetNotePool()->fromID(noteID);
1343                            }
1344                            // move voice from whereever it was, to the new note's list of active voices
1345                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1346                            // render audio of this new voice for the first time
1347                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1348                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1349                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 898  namespace LinuxSampler { Line 1381  namespace LinuxSampler {
1381                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKyes();
1382    
1383                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1384                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1385                    pChannel->ClearEventListsOfCurrentFragment();
1386              }              }
1387    
1388              /**              /**
# Line 963  namespace LinuxSampler { Line 1447  namespace LinuxSampler {
1447                                  case 0x1d: { // reverb send of note (Roland GS NRPN)                                  case 0x1d: { // reverb send of note (Roland GS NRPN)
1448                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1449                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1450                                      dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));                                      dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
1451                                      if (note < 128)                                      if (note < 128)
1452                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1453                                      break;                                      break;
# Line 971  namespace LinuxSampler { Line 1455  namespace LinuxSampler {
1455                                  case 0x1e: { // chorus send of note (Roland GS NRPN)                                  case 0x1e: { // chorus send of note (Roland GS NRPN)
1456                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1457                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1458                                      dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));                                      dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
1459                                      if (note < 128)                                      if (note < 128)
1460                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1461                                      break;                                      break;
# Line 1124  namespace LinuxSampler { Line 1608  namespace LinuxSampler {
1608              /**              /**
1609               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1610               *               *
1611               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1612               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1613               */               */
1614              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1615                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1616                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1617    
                 //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;  
   
1618                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1619                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1620                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1621    
1622                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1623    
1624                  pChannel->listeners.PreProcessNoteOn(key, vel);                  // There are real MIDI note-on events (Event::type_note_on) and
1625                    // programmatically spawned notes (Event::type_play_note). We have
1626                    // to distinguish between them, since certain processing below
1627                    // must only be done on real MIDI note-on events (i.e. for
1628                    // correctly updating which MIDI keys are currently pressed down).
1629                    const bool isRealMIDINoteOnEvent = itNoteOnEvent->Type == Event::type_note_on;
1630    
1631                    if (isRealMIDINoteOnEvent)
1632                        pChannel->listeners.PreProcessNoteOn(key, vel);
1633    
1634                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1635                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1636                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1637                            pChannel->listeners.PostProcessNoteOn(key, vel);
1638                      return;                      return;
1639                  }                  }
1640                  #endif                  #endif
1641    
1642                  if (!pChannel->pInstrument) {                  if (!pChannel->pInstrument) {
1643                      pChannel->listeners.PostProcessNoteOn(key, vel);                      if (isRealMIDINoteOnEvent)
1644                            pChannel->listeners.PostProcessNoteOn(key, vel);
1645                      return; // ignore if no instrument loaded                      return; // ignore if no instrument loaded
1646                  }                  }
1647    
# Line 1158  namespace LinuxSampler { Line 1649  namespace LinuxSampler {
1649                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOnEventOnKeyList = itNoteOnEvent.moveToEndOf(pKey->pEvents);
1650    
1651                  // if Solo Mode then kill all already active voices                  // if Solo Mode then kill all already active voices
1652                  if (pChannel->SoloMode) {                  if (pChannel->SoloMode && isRealMIDINoteOnEvent) {
1653                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();                      Pool<uint>::Iterator itYoungestKey = pChannel->pActiveKeys->last();
1654                      if (itYoungestKey) {                      if (itYoungestKey) {
1655                          const int iYoungestKey = *itYoungestKey;                          const int iYoungestKey = *itYoungestKey;
# Line 1166  namespace LinuxSampler { Line 1657  namespace LinuxSampler {
1657                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1658                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1659                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1660                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1661                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1662                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1663                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1664                                    }
1665                              }                              }
1666                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1667                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1668                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1669                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1670                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1671                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1672                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1673                                    }
1674                              }                              }
1675                          }                          }
1676                      }                      }
# Line 1182  namespace LinuxSampler { Line 1678  namespace LinuxSampler {
1678                      pChannel->SoloKey = key;                      pChannel->SoloKey = key;
1679                  }                  }
1680    
1681                  pChannel->ProcessKeySwitchChange(key);                  if (isRealMIDINoteOnEvent) {
1682                        pChannel->ProcessKeySwitchChange(key);
1683    
1684                  pKey->KeyPressed = true; // the MIDI key was now pressed down                      pKey->KeyPressed = true; // the MIDI key was now pressed down
1685                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                      pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1686                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                      pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1687                        pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1688                    }
1689    
1690                  // cancel release process of voices on this key if needed                  // cancel release process of voices on this key if needed
1691                  if (pKey->Active && !pChannel->SustainPedal) {                  if (pKey->Active && !pChannel->SustainPedal && isRealMIDINoteOnEvent) {
1692                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();                      RTList<Event>::Iterator itCancelReleaseEvent = pKey->pEvents->allocAppend();
1693                      if (itCancelReleaseEvent) {                      if (itCancelReleaseEvent) {
1694                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event                          *itCancelReleaseEvent = *itNoteOnEventOnKeyList;         // copy event
1695                          itCancelReleaseEvent->Type = Event::type_cancel_release; // transform event type                          itCancelReleaseEvent->Type = Event::type_cancel_release_key; // transform event type
1696                      }                      }
1697                      else dmsg(1,("Event pool emtpy!\n"));                      else dmsg(1,("Event pool emtpy!\n"));
1698                  }                  }
# Line 1204  namespace LinuxSampler { Line 1703  namespace LinuxSampler {
1703                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1704                      pKey->pEvents->free(itNoteOnEventOnKeyList);                      pKey->pEvents->free(itNoteOnEventOnKeyList);
1705    
1706                  if (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f) pChannel->PortamentoPos = (float) key;                  if (isRealMIDINoteOnEvent && (!pChannel->SoloMode || pChannel->PortamentoPos < 0.0f))
1707                        pChannel->PortamentoPos = (float) key;
1708    
1709                    //NOTE: Hmm, I guess its a matter of taste whether round robin should be advanced only on real MIDI note-on events, isn't it?
1710                  if (pKey->pRoundRobinIndex) {                  if (pKey->pRoundRobinIndex) {
1711                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region                      (*pKey->pRoundRobinIndex)++; // counter specific for the key or region
1712                      pChannel->RoundRobinIndex++; // common counter for the channel                      pChannel->RoundRobinIndex++; // common counter for the channel
1713                  }                  }
1714                  pChannel->listeners.PostProcessNoteOn(key, vel);  
1715                    if (isRealMIDINoteOnEvent)
1716                        pChannel->listeners.PostProcessNoteOn(key, vel);
1717              }              }
1718    
1719              /**              /**
# Line 1235  namespace LinuxSampler { Line 1739  namespace LinuxSampler {
1739               *  sustain pedal will be released or voice turned inactive by itself (e.g.               *  sustain pedal will be released or voice turned inactive by itself (e.g.
1740               *  due to completion of sample playback).               *  due to completion of sample playback).
1741               *               *
1742               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1743               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1744               */               */
1745              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1746                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1747    
                 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;  
   
1748                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1749                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1750                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1751    
1752                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1753    
1754                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  // There are real MIDI note-off events (Event::type_note_off) and
1755                    // programmatically spawned notes (Event::type_stop_note). We have
1756                    // to distinguish between them, since certain processing below
1757                    // must only be done on real MIDI note-off events (i.e. for
1758                    // correctly updating which MIDI keys are currently pressed down),
1759                    // plus a stop-note event just releases voices of one particular
1760                    // note, whereas a note-off event releases all voices on a
1761                    // particular MIDI key instead.
1762                    const bool isRealMIDINoteOffEvent = itNoteOffEvent->Type == Event::type_note_off;
1763    
1764                    if (isRealMIDINoteOffEvent)
1765                        pChannel->listeners.PreProcessNoteOff(iKey, vel);
1766    
1767                  #if !CONFIG_PROCESS_MUTED_CHANNELS                  #if !CONFIG_PROCESS_MUTED_CHANNELS
1768                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted                  if (pEngineChannel->GetMute()) { // skip if sampler channel is muted
1769                      pChannel->listeners.PostProcessNoteOff(iKey, vel);                      if (isRealMIDINoteOffEvent)
1770                            pChannel->listeners.PostProcessNoteOff(iKey, vel);
1771                      return;                      return;
1772                  }                  }
1773                  #endif                  #endif
1774    
1775                  pKey->KeyPressed = false; // the MIDI key was now released                  if (isRealMIDINoteOffEvent) {
1776                        pKey->KeyPressed = false; // the MIDI key was now released
1777                        pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1778                    }
1779    
1780                  // move event to the key's own event list                  // move event to the key's own event list
1781                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
1782    
1783                  bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);                  if (isRealMIDINoteOffEvent) {
1784                        bool bShouldRelease = pKey->Active && pChannel->ShouldReleaseVoice(itNoteOffEventOnKeyList->Param.Note.Key);
1785    
1786                  // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)                      // in case Solo Mode is enabled, kill all voices on this key and respawn a voice on the highest pressed key (if any)
1787                  if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P                      if (pChannel->SoloMode && pChannel->pInstrument) { //TODO: this feels like too much code just for handling solo mode :P
1788                      bool bOtherKeysPressed = false;                          bool bOtherKeysPressed = false;
1789                      if (iKey == pChannel->SoloKey) {                          if (iKey == pChannel->SoloKey) {
1790                          pChannel->SoloKey = -1;                              pChannel->SoloKey = -1;
1791                          // if there's still a key pressed down, respawn a voice (group) on the highest key                              // if there's still a key pressed down, respawn a voice (group) on the highest key
1792                          for (int i = 127; i > 0; i--) {                              for (int i = 127; i > 0; i--) {
1793                              MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];                                  MidiKey* pOtherKey = &pChannel->pMIDIKeyInfo[i];
1794                              if (pOtherKey->KeyPressed) {                                  if (pOtherKey->KeyPressed) {
1795                                  bOtherKeysPressed = true;                                      bOtherKeysPressed = true;
1796                                  // make the other key the new 'currently active solo key'                                      // make the other key the new 'currently active solo key'
1797                                  pChannel->SoloKey = i;                                      pChannel->SoloKey = i;
1798                                  // get final portamento position of currently active voice                                      // get final portamento position of currently active voice
1799                                  if (pChannel->PortamentoMode) {                                      if (pChannel->PortamentoMode) {
1800                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                          NoteIterator itNote = pKey->pActiveNotes->first();
1801                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                          VoiceIterator itVoice = itNote->pActiveVoices->first();
1802                                  }                                          if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1803                                  // create a pseudo note on event                                      }
1804                                  RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();                                      // create a pseudo note on event
1805                                  if (itPseudoNoteOnEvent) {                                      RTList<Event>::Iterator itPseudoNoteOnEvent = pOtherKey->pEvents->allocAppend();
1806                                      // copy event                                      if (itPseudoNoteOnEvent) {
1807                                      *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;                                          // copy event
1808                                      // transform event to a note on event                                          *itPseudoNoteOnEvent = *itNoteOffEventOnKeyList;
1809                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                          // transform event to a note on event
1810                                      itPseudoNoteOnEvent->Param.Note.Key      = i;                                          itPseudoNoteOnEvent->Type                = Event::type_note_on; //FIXME: should probably use Event::type_play_note instead (to avoid i.e. hanging notes)
1811                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                          itPseudoNoteOnEvent->Param.Note.Key      = i;
1812                                      // allocate and trigger new voice(s) for the other key                                          itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1813                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                          // assign a new note to this note-on event
1814                                      // if neither a voice was spawned or postponed then remove note on event from key again                                          if (LaunchNewNote(pChannel, &*itPseudoNoteOnEvent)) {
1815                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                              // allocate and trigger new voice(s) for the other key
1816                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                              TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1817                                            }
1818                                            // if neither a voice was spawned or postponed then remove note on event from key again
1819                                            if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1820                                                pOtherKey->pEvents->free(itPseudoNoteOnEvent);
1821    
1822                                  } else dmsg(1,("Could not respawn voice, no free event left\n"));                                      } else dmsg(1,("Could not respawn voice, no free event left\n"));
1823                                  break; // done                                      break; // done
1824                                    }
1825                              }                              }
1826                          }                          }
1827                      }                          if (bOtherKeysPressed) {
1828                      if (bOtherKeysPressed) {                              if (pKey->Active) { // kill all voices on this key
1829                          if (pKey->Active) { // kill all voices on this key                                  bShouldRelease = false; // no need to release, as we kill it here
1830                              bShouldRelease = false; // no need to release, as we kill it here                                  for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1831                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                                      VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1832                              VoiceIterator end               = pKey->pActiveVoices->end();                                      VoiceIterator end               = itNote->pActiveVoices->end();
1833                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                      for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1834                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                          if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1835                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                              itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1836                                        }
1837                                    }
1838                              }                              }
1839                          }                          } else pChannel->PortamentoPos = -1.0f;
1840                      } else pChannel->PortamentoPos = -1.0f;                      }
                 }  
   
                 // 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 (bShouldRelease) {  
                     itNoteOffEventOnKeyList->Type = Event::type_release; // transform event type  
1841    
1842                      // spawn release triggered voice(s) 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
1843                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (bShouldRelease) {
1844                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          itNoteOffEventOnKeyList->Type = Event::type_release_key; // transform event type
1845                          pKey->ReleaseTrigger = false;                          // spawn release triggered voice(s) if needed
1846                            ProcessReleaseTrigger(pChannel, itNoteOffEventOnKeyList, pKey);
1847                        }
1848                    } else if (itNoteOffEventOnKeyList->Type == Event::type_stop_note) {
1849                        // This programmatically caused event is caused by a call to
1850                        // the built-in instrument script function note_off(). In
1851                        // contrast to a real MIDI note-off event the stop-note
1852                        // event just intends to release voices of one particular note.
1853                        NoteBase* pNote = pChannel->pEngine->NoteByID( itNoteOffEventOnKeyList->Param.Note.ID );
1854                        if (pNote) { // the requested note is still alive ...
1855                            itNoteOffEventOnKeyList->Type = Event::type_release_note; // transform event type
1856                        } else { // note is dead and gone ..
1857                            pKey->pEvents->free(itNoteOffEventOnKeyList); // remove stop-note event from key again
1858                            return; // prevent event to be removed a 2nd time below
1859                      }                      }
1860                  }                  }
1861    
# Line 1332  namespace LinuxSampler { Line 1863  namespace LinuxSampler {
1863                  if (!pKey->Active && !pKey->VoiceTheftsQueued)                  if (!pKey->Active && !pKey->VoiceTheftsQueued)
1864                      pKey->pEvents->free(itNoteOffEventOnKeyList);                      pKey->pEvents->free(itNoteOffEventOnKeyList);
1865    
1866                  pChannel->listeners.PostProcessNoteOff(iKey, vel);                  if (isRealMIDINoteOffEvent)
1867                        pChannel->listeners.PostProcessNoteOff(iKey, vel);
1868                }
1869    
1870                /**
1871                 * Called on sustain pedal up events to check and if required,
1872                 * launch release trigger voices on the respective active key.
1873                 *
1874                 * @param pEngineChannel - engine channel on which this event occurred on
1875                 * @param itEvent - release trigger event (contains note number)
1876                 */
1877                virtual void ProcessReleaseTrigger(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) OVERRIDE {
1878                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1879    
1880                    const int iKey = itEvent->Param.Note.Key;
1881                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1882    
1883                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1884    
1885                    ProcessReleaseTrigger(pChannel, itEvent, pKey);
1886                }
1887    
1888                /**
1889                 * Called on note-off and sustain pedal up events to check and if
1890                 * required, launch release trigger voices on the respective active
1891                 * key.
1892                 *
1893                 * @param pEngineChannel - engine channel on which this event occurred on
1894                 * @param itEvent - note off event / release trigger event
1895                 * @param pKey - key on which the release trigger voices shall be spawned
1896                 */
1897                inline void ProcessReleaseTrigger(EngineChannelBase<V, R, I>* pChannel, RTList<Event>::Iterator& itEvent, MidiKey* pKey) {
1898                    // spawn release triggered voice(s) if needed
1899                    if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1900                        // assign a new note to this release event
1901                        if (LaunchNewNote(pChannel, &*itEvent)) {
1902                            // allocate and trigger new release voice(s)
1903                            TriggerReleaseVoices(pChannel, itEvent);
1904                        }
1905                        pKey->ReleaseTrigger = false;
1906                    }
1907                }
1908    
1909                /**
1910                 * Called on note synthesis parameter change events. These are
1911                 * internal events caused by calling built-in real-time instrument
1912                 * script functions like change_vol(), change_pitch(), etc.
1913                 *
1914                 * This method performs two tasks:
1915                 *
1916                 * - It converts the event's relative values changes (Deltas) to
1917                 *   the respective final new synthesis parameter value (AbsValue),
1918                 *   for that particular moment of the event that is.
1919                 *
1920                 * - It moves the individual events to the Note's own event list
1921                 *   (or actually to the event list of the MIDI key), so that
1922                 *   voices can process those events sample accurately.
1923                 *
1924                 * @param pEngineChannel - engine channel on which this event occurred on
1925                 * @param itEvent - note synthesis parameter change event
1926                 */
1927                virtual void ProcessNoteSynthParam(EngineChannel* pEngineChannel, RTList<Event>::Iterator& itEvent) {
1928                    EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1929    
1930                    NoteBase* pNote = pChannel->pEngine->NoteByID( itEvent->Param.NoteSynthParam.NoteID );
1931                    if (!pNote || pNote->hostKey < 0 || pNote->hostKey >= 128) return;
1932    
1933                    const bool& relative = itEvent->Param.NoteSynthParam.Relative;
1934    
1935                    switch (itEvent->Param.NoteSynthParam.Type) {
1936                        case Event::synth_param_volume:
1937                            if (relative)
1938                                pNote->Override.Volume *= itEvent->Param.NoteSynthParam.Delta;
1939                            else
1940                                pNote->Override.Volume = itEvent->Param.NoteSynthParam.Delta;
1941                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Volume;
1942                            break;
1943                        case Event::synth_param_pitch:
1944                            if (relative)
1945                                pNote->Override.Pitch *= itEvent->Param.NoteSynthParam.Delta;
1946                            else
1947                                pNote->Override.Pitch = itEvent->Param.NoteSynthParam.Delta;
1948                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pitch;
1949                            break;
1950                        case Event::synth_param_pan:
1951                            if (relative) {
1952                                pNote->Override.Pan = RTMath::RelativeSummedAvg(pNote->Override.Pan, itEvent->Param.NoteSynthParam.Delta, ++pNote->Override.PanSources);
1953                            } else {
1954                                pNote->Override.Pan = itEvent->Param.NoteSynthParam.Delta;
1955                                pNote->Override.PanSources = 1; // only relevant on subsequent change_pan() instrument script calls on same note with 'relative' argument being set
1956                            }
1957                            itEvent->Param.NoteSynthParam.AbsValue = pNote->Override.Pan;
1958                            break;
1959                        case Event::synth_param_cutoff:
1960                            pNote->Override.Cutoff = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1961                            break;
1962                        case Event::synth_param_resonance:
1963                            pNote->Override.Resonance = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1964                            break;
1965                        case Event::synth_param_attack:
1966                            pNote->Override.Attack = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1967                            break;
1968                        case Event::synth_param_decay:
1969                            pNote->Override.Decay = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1970                            break;
1971                        case Event::synth_param_release:
1972                            pNote->Override.Release = itEvent->Param.NoteSynthParam.AbsValue = itEvent->Param.NoteSynthParam.Delta;
1973                            break;
1974                    }
1975    
1976                    // move note parameter event to its MIDI key
1977                    MidiKey* pKey = &pChannel->pMIDIKeyInfo[pNote->hostKey];
1978                    itEvent.moveToEndOf(pKey->pEvents);
1979              }              }
1980    
1981              /**              /**
# Line 1352  namespace LinuxSampler { Line 1995  namespace LinuxSampler {
1995                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
1996                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
1997                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
1998                    itLastStolenNote           = NoteIterator();
1999                    itLastStolenNoteGlobally   = NoteIterator();
2000                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
2001                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
2002                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
2003    
2004                    // reset all notes
2005                    pNotePool->clear();
2006                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
2007                         itNote = pNotePool->allocAppend())
2008                    {
2009                        itNote->reset();
2010                    }
2011                    pNotePool->clear();
2012    
2013                  // reset all voices                  // reset all voices
2014                    pVoicePool->clear();
2015                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
2016                      iterVoice->Reset();                      iterVoice->Reset();
2017                  }                  }
2018                  pVoicePool->clear();                  pVoicePool->clear();
2019    
2020                    // reset all engine channels
2021                    for (int i = 0; i < engineChannels.size(); i++) {
2022                        AbstractEngineChannel* pEngineChannel =
2023                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
2024                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
2025                    }
2026    
2027                  // reset disk thread                  // reset disk thread
2028                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
2029    
# Line 1390  namespace LinuxSampler { Line 2052  namespace LinuxSampler {
2052               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
2053               *  (e.g. to spawn further voices on the same key for layered sounds).               *  (e.g. to spawn further voices on the same key for layered sounds).
2054               *               *
2055               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
2056               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
2057               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
2058               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1433  namespace LinuxSampler { Line 2095  namespace LinuxSampler {
2095                      // launch the new voice                      // launch the new voice
2096                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
2097                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
2098                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
2099                      }                      }
2100                      else { // on success                      else { // on success
2101                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
# Line 1482  namespace LinuxSampler { Line 2144  namespace LinuxSampler {
2144              }              }
2145    
2146          private:          private:
2147                Pool< Note<V> >* pNotePool;
2148                Pool<note_id_t> noteIDPool;
2149              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
2150              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
2151              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

Legend:
Removed from v.2559  
changed lines
  Added in v.2972

  ViewVC Help
Powered by ViewVC