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

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

  ViewVC Help
Powered by ViewVC