/[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 2879 by schoenebeck, Tue Apr 19 14:07:53 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; ++itEvent)
775                        {
776                            switch (itEvent->Type) {
777                                case Event::type_note_on:
778                                    if (pChannel->pScript->handlerNote)
779                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerNote);
780                                    break;
781                                case Event::type_note_off:
782                                    if (pChannel->pScript->handlerRelease)
783                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerRelease);
784                                    break;
785                                case Event::type_control_change:
786                                case Event::type_channel_pressure:
787                                case Event::type_pitchbend:
788                                    if (pChannel->pScript->handlerController)
789                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerController);                            
790                                    break;
791                                case Event::type_note_pressure:
792                                    //TODO: ...
793                                    break;
794                            }
795                        }
796    
797                        // this has to be run again, since the newly spawned scripts
798                        // above may have cause suspended scripts that must be
799                        // resumed within this same audio fragment cycle
800                        //
801                        // FIXME: see FIXME comment above
802                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
803                    }
804    
805                    // if there are any delayed events scheduled for the current
806                    // audio fragment cycle, then move and sort them into the main
807                    // event list
808                    if (!pChannel->delayedEvents.queue.isEmpty()) {
809                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
810                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
811                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
812                        while (true) {
813                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
814                                pEventGenerator->popNextScheduledEvent(
815                                    pChannel->delayedEvents.queue,
816                                    pChannel->delayedEvents.schedulerNodes,
817                                    fragmentEndTime
818                                );
819                            if (!itDelayedEventNode) break;
820                            // get the actual delayed event object and free the used scheduler node
821                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
822                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
823                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
824                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
825                                continue;
826                            }
827                            // skip all events on main event list which have a time
828                            // before (or equal to) the delayed event to be inserted
829                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
830                                 ++itEvent);
831                            // now move delayed event from delayedEvents.pList to
832                            // the current position on the main event list
833                            itEvent = itDelayedEvent.moveBefore(itEvent);
834                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
835                        }
836                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
837                    }
838    
839                    // now process all events regularly
840                  {                  {
841                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
842                      RTList<Event>::Iterator end     = pChannel->pEvents->end();                      RTList<Event>::Iterator end     = pChannel->pEvents->end();
# Line 668  namespace LinuxSampler { Line 873  namespace LinuxSampler {
873                  // reset voice stealing for the next engine channel (or next audio fragment)                  // reset voice stealing for the next engine channel (or next audio fragment)
874                  itLastStolenVoice         = VoiceIterator();                  itLastStolenVoice         = VoiceIterator();
875                  itLastStolenVoiceGlobally = VoiceIterator();                  itLastStolenVoiceGlobally = VoiceIterator();
876                    itLastStolenNote          = NoteIterator();
877                    itLastStolenNoteGlobally  = NoteIterator();
878                  iuiLastStolenKey          = RTList<uint>::Iterator();                  iuiLastStolenKey          = RTList<uint>::Iterator();
879                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally  = RTList<uint>::Iterator();
880                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
881              }              }
882    
883              /**              /**
884                 * Run all suspended script execution instances which are scheduled
885                 * to be resumed for the current audio fragment cycle.
886                 *
887                 * @param pChannel - engine channel on which suspended events occurred
888                 */
889                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
890                    while (true) {
891                        RTList<ScriptEvent>::Iterator itEvent =
892                            pEventGenerator->popNextScheduledScriptEvent(
893                                pChannel->pScript->suspendedEvents,
894                                *pChannel->pScript->pEvents, fragmentEndTime
895                            );
896                        if (!itEvent) break;
897                        ResumeScriptEvent(pChannel, itEvent);
898                    }
899                }
900    
901                /** @brief Call instrument script's event handler for this event.
902                 *
903                 * Causes a new execution instance of the currently loaded real-time
904                 * instrument script's event handler (callback) to be spawned for
905                 * the given MIDI event.
906                 *
907                 * @param pChannel - engine channel on which the MIDI event occurred
908                 * @param itEvent - MIDI event that causes this new script execution
909                 * @param pEventHandler - script's event handler to be executed
910                 */
911                void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
912                    const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
913                    // check if polyphonic data is passed from "note" to "release"
914                    // script event handlers
915                    if (pEventHandler == pChannel->pScript->handlerRelease &&
916                        pChannel->pScript->handlerNote &&
917                        pChannel->pScript->handlerNote->isPolyphonic() &&
918                        pChannel->pScript->handlerRelease->isPolyphonic() &&
919                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
920                    {
921                        // polyphonic variable data is used/passed from "note" to
922                        // "release" script callback, so we have to recycle the
923                        // original "note on" script event(s)
924                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
925                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
926                        for (; it != end; ++it) {
927                            ProcessScriptEvent(
928                                pChannel, itEvent, pEventHandler, it
929                            );
930                        }
931                    } else {
932                        // no polyphonic data is used/passed from "note" to
933                        // "release" script callback, so just use a new fresh
934                        // script event object
935                        RTList<ScriptEvent>::Iterator itScriptEvent =
936                            pChannel->pScript->pEvents->allocAppend();
937                        ProcessScriptEvent(
938                            pChannel, itEvent, pEventHandler, itScriptEvent
939                        );
940                    }
941                }
942    
943                /** @brief Spawn new execution instance of an instrument script handler.
944                 *
945                 * Will be called to initiate a new execution of a real-time
946                 * instrument script event right from the start of the script's
947                 * respective handler. If script execution did not complete after
948                 * calling this method, the respective script exeuction is then
949                 * suspended and a call to ResumeScriptEvent() will be used next
950                 * time to continue its execution.
951                 *
952                 * @param pChannel - engine channel this script is running for
953                 * @param itEvent - event which caused execution of this script
954                 *                  event handler
955                 * @param pEventHandler - VM representation of event handler to be
956                 *                        executed
957                 * @param itScriptEvent - script event that shall be processed
958                 */
959                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
960                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
961    
962                    // fill the list of script handlers to be executed by this event
963                    int i = 0;
964                    itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
965                    itScriptEvent->handlers[i] = NULL; // NULL termination of list
966    
967                    // initialize/reset other members
968                    itScriptEvent->cause = *itEvent;
969                    itScriptEvent->currentHandler = 0;
970                    itScriptEvent->executionSlices = 0;
971                    // this is the native representation of the $EVENT_ID script variable
972                    itScriptEvent->id =
973                        (itEvent->Type == Event::type_note_on)
974                            ? ScriptID::fromNoteID( itEvent->Param.Note.ID )
975                            : ScriptID::fromEventID( pEventPool->getID(itEvent) );
976    
977                    // run script handler(s)
978                    VMExecStatus_t res = pScriptVM->exec(
979                        pChannel->pScript->parserContext, &*itScriptEvent
980                    );
981    
982                    // was the script suspended?
983                    if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
984                        // in case the script was suspended, keep it on the allocated
985                        // ScriptEvent list to be resume at the scheduled time in future,
986                        // additionally insert it into a sorted time queue
987                        pEventGenerator->scheduleAheadMicroSec(
988                            pChannel->pScript->suspendedEvents, // scheduler queue
989                            *itScriptEvent, // script event
990                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
991                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
992                        );
993                    } else { // script execution has finished without 'suspended' status ...
994                        // if "polyphonic" variable data is passed from script's
995                        // "note" event handler to its "release" event handler, then
996                        // the script event must be kept and recycled for the later
997                        // occuring "release" script event ...
998                        if (pEventHandler == pChannel->pScript->handlerNote &&
999                            pChannel->pScript->handlerRelease &&
1000                            pChannel->pScript->handlerNote->isPolyphonic() &&
1001                            pChannel->pScript->handlerRelease->isPolyphonic())
1002                        {
1003                            const int key = itEvent->Param.Note.Key;
1004                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1005                        } else {
1006                            // ... otherwise if no polyphonic data is passed and
1007                            // script's execution has finished without suspension
1008                            // status, then free the script event for a new future
1009                            // script event to be triggered from start
1010                            pChannel->pScript->pEvents->free(itScriptEvent);
1011                        }
1012                    }
1013                }
1014    
1015                /** @brief Resume execution of instrument script.
1016                 *
1017                 * Will be called to resume execution of a real-time instrument
1018                 * script event which has been suspended previously.
1019                 *
1020                 * Script execution might be suspended for various reasons. Usually
1021                 * a script will be suspended if the script called the built-in
1022                 * "wait()" function, but it might also be suspended automatically
1023                 * if the script took too much execution time in an audio fragment
1024                 * cycle. So in the latter case automatic suspension is performed in
1025                 * order to avoid harm for the sampler's overall real-time
1026                 * requirements.
1027                 *
1028                 * @param pChannel - engine channel this script is running for
1029                 * @param itScriptEvent - script execution that shall be resumed
1030                 */
1031                void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
1032                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
1033    
1034                    // run script
1035                    VMExecStatus_t res = pScriptVM->exec(
1036                        pChannel->pScript->parserContext, &*itScriptEvent
1037                    );
1038    
1039                    // was the script suspended?
1040                    if (res & VM_EXEC_SUSPENDED) {
1041                        // in case the script was suspended, keep it on the allocated
1042                        // ScriptEvent list to be resume at the scheduled time in future,
1043                        // additionally insert it into a sorted time queue
1044                        pEventGenerator->scheduleAheadMicroSec(
1045                            pChannel->pScript->suspendedEvents, // scheduler queue
1046                            *itScriptEvent, // script event
1047                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1048                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
1049                        );
1050                    } else { // script execution has finished without 'suspended' status ...
1051                        // if "polyphonic" variable data is passed from script's
1052                        // "note" event handler to its "release" event handler, then
1053                        // the script event must be kept and recycled for the later
1054                        // occuring "release" script event ...
1055                        if (handler && handler == pChannel->pScript->handlerNote &&
1056                            pChannel->pScript->handlerRelease &&
1057                            pChannel->pScript->handlerNote->isPolyphonic() &&
1058                            pChannel->pScript->handlerRelease->isPolyphonic())
1059                        {
1060                            const int key = itScriptEvent->cause.Param.Note.Key;
1061                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
1062                        } else {
1063                            // ... otherwise if no polyphonic data is passed and
1064                            // script's execution has finished without suspension
1065                            // status, then free the script event for a new future
1066                            // script event to be triggered from start
1067                            pChannel->pScript->pEvents->free(itScriptEvent);
1068                        }
1069                    }
1070                }
1071    
1072                /**
1073               *  Will be called by LaunchVoice() method in case there are no free               *  Will be called by LaunchVoice() method in case there are no free
1074               *  voices left. This method will select and kill one old voice for               *  voices left. This method will select and kill one old voice for
1075               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
1076               *  voice actually died.               *  voice actually died.
1077               *               *
1078               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1079               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1080               *  @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
1081               */               */
1082              int  StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              int StealVoice(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1083                  if (VoiceSpawnsLeft <= 0) {                  if (VoiceSpawnsLeft <= 0) {
1084                      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"));
1085                      return -1;                      return -1;
# Line 691  namespace LinuxSampler { Line 1087  namespace LinuxSampler {
1087    
1088                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pEngineChn = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1089    
1090                  if (!pEventPool->poolIsEmpty()) {                  if (pEventPool->poolIsEmpty()) {
1091                        dmsg(1,("Event pool emtpy!\n"));
1092                        return -1;
1093                    }
1094    
1095                      if(!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &iuiLastStolenKey)) {                  if (!pEngineChn->StealVoice(itNoteOnEvent, &itLastStolenVoice, &itLastStolenNote, &iuiLastStolenKey)) {
1096                          --VoiceSpawnsLeft;                      --VoiceSpawnsLeft;
1097                          return 0;                      return 0;
1098                      }                  }
1099    
1100                      // 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
1101                      // steal oldest voice on the oldest key from any other engine channel                  // steal oldest voice on the oldest key from any other engine channel
1102                      // (the smaller engine channel number, the higher priority)                  // (the smaller engine channel number, the higher priority)
1103                      EngineChannelBase<V, R, I>*  pSelectedChannel;                  EngineChannelBase<V, R, I>*  pSelectedChannel;
1104                      int                       iChannelIndex;                  int                          iChannelIndex;
1105                      VoiceIterator             itSelectedVoice;                  VoiceIterator                itSelectedVoice;
1106    
1107                      // select engine channel                  // select engine channel
1108                      if (pLastStolenChannel) {                  if (pLastStolenChannel) {
1109                          pSelectedChannel = pLastStolenChannel;                      pSelectedChannel = pLastStolenChannel;
1110                          iChannelIndex    = pSelectedChannel->iEngineIndexSelf;                      iChannelIndex    = pSelectedChannel->iEngineIndexSelf;
1111                      } else { // pick the engine channel followed by this engine channel                  } else { // pick the engine channel followed by this engine channel
1112                          iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();                      iChannelIndex    = (pEngineChn->iEngineIndexSelf + 1) % engineChannels.size();
1113                          pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1114                      }                  }
1115    
1116                      // 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
1117                      if (this->itLastStolenVoiceGlobally) {                  if (this->itLastStolenVoiceGlobally) {
1118                          itSelectedVoice = this->itLastStolenVoiceGlobally;                      itSelectedVoice = this->itLastStolenVoiceGlobally;
1119                          do {                      do {
1120                              ++itSelectedVoice;                          ++itSelectedVoice;
1121                          } 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
1122                    }
1123                    // did we find a 'stealable' voice?
1124                    if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1125                        // remember which voice we stole, so we can simply proceed on next voice stealing
1126                        this->itLastStolenVoiceGlobally = itSelectedVoice;
1127                        // done
1128                        goto stealable_voice_found;
1129                    }
1130    
1131                    // get (next) oldest note
1132                    if (this->itLastStolenNoteGlobally) {
1133                        for (NoteIterator itNote = ++this->itLastStolenNoteGlobally;
1134                             itNote; ++itNote)
1135                        {
1136                            for (itSelectedVoice = itNote->pActiveVoices->first(); itSelectedVoice; ++itSelectedVoice) {
1137                                // proceed iterating if voice was created in this audio fragment cycle
1138                                if (itSelectedVoice->IsStealable()) {
1139                                    // remember which voice of which note we stole, so we can simply proceed on next voice stealing
1140                                    this->itLastStolenNoteGlobally  = itNote;
1141                                    this->itLastStolenVoiceGlobally = itSelectedVoice;
1142                                    goto stealable_voice_found; // selection succeeded
1143                                }
1144                            }
1145                      }                      }
1146                    }
1147    
1148                      #if CONFIG_DEVMODE                  #if CONFIG_DEVMODE
1149                      EngineChannel* pBegin = pSelectedChannel; // to detect endless loop                  EngineChannel* pBegin = pSelectedChannel; // to detect endless loop
1150                      #endif // CONFIG_DEVMODE                  #endif // CONFIG_DEVMODE
1151    
1152                      // did we find a 'stealable' voice?                  while (true) { // iterate through engine channels                        
1153                      if (itSelectedVoice && itSelectedVoice->IsStealable()) {                      // get (next) oldest key
1154                          // 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();
1155                          this->itLastStolenVoiceGlobally = itSelectedVoice;                      this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)
1156                      } else while (true) { // iterate through engine channels                      while (iuiSelectedKey) {
1157                          // get (next) oldest key                          MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];
1158                          RTList<uint>::Iterator iuiSelectedKey = (this->iuiLastStolenKeyGlobally) ? ++this->iuiLastStolenKeyGlobally : pSelectedChannel->pActiveKeys->first();  
1159                          this->iuiLastStolenKeyGlobally = RTList<uint>::Iterator(); // to prevent endless loop (see line above)                          for (NoteIterator itNote = pSelectedKey->pActiveNotes->first(),
1160                          while (iuiSelectedKey) {                               itNotesEnd = pSelectedKey->pActiveNotes->end();
1161                              MidiKey* pSelectedKey = &pSelectedChannel->pMIDIKeyInfo[*iuiSelectedKey];                               itNote != itNotesEnd; ++itNote)
1162                              itSelectedVoice = pSelectedKey->pActiveVoices->first();                          {
1163                                itSelectedVoice = itNote->pActiveVoices->first();
1164                              // proceed iterating if voice was created in this fragment cycle                              // proceed iterating if voice was created in this fragment cycle
1165                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;                              while (itSelectedVoice && !itSelectedVoice->IsStealable()) ++itSelectedVoice;
1166                              // found a "stealable" voice ?                              // found a "stealable" voice ?
1167                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {                              if (itSelectedVoice && itSelectedVoice->IsStealable()) {
1168                                  // 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
1169                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;                                  this->iuiLastStolenKeyGlobally  = iuiSelectedKey;
1170                                    this->itLastStolenNoteGlobally  = itNote;
1171                                  this->itLastStolenVoiceGlobally = itSelectedVoice;                                  this->itLastStolenVoiceGlobally = itSelectedVoice;
1172                                  this->pLastStolenChannel        = pSelectedChannel;                                  this->pLastStolenChannel        = pSelectedChannel;
1173                                  goto stealable_voice_found; // selection succeeded                                  goto stealable_voice_found; // selection succeeded
1174                              }                              }
                             ++iuiSelectedKey; // get next key on current engine channel  
                         }  
                         // get next engine channel  
                         iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();  
                         pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);  
   
                         #if CONFIG_DEVMODE  
                         if (pSelectedChannel == pBegin) {  
                             dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));  
                             dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));  
                             dmsg(1,("Exiting.\n"));  
                             exit(-1);  
1175                          }                          }
1176                          #endif // CONFIG_DEVMODE                          ++iuiSelectedKey; // get next key on current engine channel
1177                      }                      }
1178                        // get next engine channel
1179                      // jump point if a 'stealable' voice was found                      iChannelIndex    = (iChannelIndex + 1) % engineChannels.size();
1180                      stealable_voice_found:                      pSelectedChannel = static_cast<EngineChannelBase<V, R, I>*>(engineChannels[iChannelIndex]);
1181    
1182                      #if CONFIG_DEVMODE                      #if CONFIG_DEVMODE
1183                      if (!itSelectedVoice->IsActive()) {                      if (pSelectedChannel == pBegin) {
1184                          dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));                          dmsg(1,("FATAL ERROR: voice stealing endless loop!\n"));
1185                          return -1;                          dmsg(1,("VoiceSpawnsLeft=%d.\n", VoiceSpawnsLeft));
1186                            dmsg(1,("Exiting.\n"));
1187                            exit(-1);
1188                      }                      }
1189                      #endif // CONFIG_DEVMODE                      #endif // CONFIG_DEVMODE
1190                    }
1191    
1192                      // now kill the selected voice                  // jump point if a 'stealable' voice was found
1193                      itSelectedVoice->Kill(itNoteOnEvent);                  stealable_voice_found:
1194    
1195                      --VoiceSpawnsLeft;                  #if CONFIG_DEVMODE
1196                    if (!itSelectedVoice->IsActive()) {
1197                      return 0; // success                      dmsg(1,("EngineBase: ERROR, tried to steal a voice which was not active !!!\n"));
                 }  
                 else {  
                     dmsg(1,("Event pool emtpy!\n"));  
1198                      return -1;                      return -1;
1199                  }                  }
1200                    #endif // CONFIG_DEVMODE
1201    
1202                    // now kill the selected voice
1203                    itSelectedVoice->Kill(itNoteOnEvent);
1204    
1205                    --VoiceSpawnsLeft;
1206    
1207                    return 0; // success
1208              }              }
1209    
1210              void HandleInstrumentChanges() {              void HandleInstrumentChanges() {
# Line 805  namespace LinuxSampler { Line 1226  namespace LinuxSampler {
1226                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
1227                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
1228                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
1229                            pEngineChannel->pScript =
1230                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
1231                          instrumentChanged = true;                          instrumentChanged = true;
1232    
1233                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
1234    
1235                            // the script's "init" event handler is only executed
1236                            // once (when the script is loaded or reloaded)
1237                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
1238                                RTList<ScriptEvent>::Iterator itScriptEvent =
1239                                    pEngineChannel->pScript->pEvents->allocAppend();
1240    
1241                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
1242                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
1243                                itScriptEvent->handlers[1] = NULL;
1244    
1245                                VMExecStatus_t res = pScriptVM->exec(
1246                                    pEngineChannel->pScript->parserContext, &*itScriptEvent
1247                                );
1248    
1249                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
1250                            }
1251                      }                      }
1252                  }                  }
1253    
# Line 858  namespace LinuxSampler { Line 1298  namespace LinuxSampler {
1298                      EngineChannelBase<V, R, I>* pEngineChannel =                      EngineChannelBase<V, R, I>* pEngineChannel =
1299                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;                          static_cast<EngineChannelBase<V, R, I>*>(itVoiceStealEvent->pEngineChannel);;
1300                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded                      if (!pEngineChannel->pInstrument) continue; // ignore if no instrument loaded
1301                        
1302                      PoolVoiceIterator itNewVoice =                      PoolVoiceIterator itNewVoice =
1303                          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);
1304                      if (itNewVoice) {                      if (itNewVoice) {
1305                            // usually there should already be a new Note object
1306                            NoteIterator itNote = GetNotePool()->fromID(itVoiceStealEvent->Param.Note.ID);
1307                            if (!itNote) { // should not happen, but just to be sure ...
1308                                const note_id_t noteID = LaunchNewNote(pEngineChannel, &*itVoiceStealEvent);
1309                                if (!noteID) {
1310                                    dmsg(1,("Engine: Voice stealing failed; No Note object and Note pool empty!\n"));
1311                                    continue;
1312                                }
1313                                itNote = GetNotePool()->fromID(noteID);
1314                            }
1315                            // move voice from whereever it was, to the new note's list of active voices
1316                            itNewVoice = itNewVoice.moveToEndOf(itNote->pActiveVoices);
1317                            // render audio of this new voice for the first time
1318                          itNewVoice->Render(Samples);                          itNewVoice->Render(Samples);
1319                          if (itNewVoice->IsActive()) { // still active                          if (itNewVoice->IsActive()) { // still active
1320                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();                              *(pEngineChannel->pRegionsInUse->allocAppend()) = itNewVoice->GetRegion();
# Line 898  namespace LinuxSampler { Line 1352  namespace LinuxSampler {
1352                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKyes();
1353    
1354                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1355                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1356                    pChannel->ClearEventListsOfCurrentFragment();
1357              }              }
1358    
1359              /**              /**
# Line 963  namespace LinuxSampler { Line 1418  namespace LinuxSampler {
1418                                  case 0x1d: { // reverb send of note (Roland GS NRPN)                                  case 0x1d: { // reverb send of note (Roland GS NRPN)
1419                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1420                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1421                                      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));
1422                                      if (note < 128)                                      if (note < 128)
1423                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1424                                      break;                                      break;
# Line 971  namespace LinuxSampler { Line 1426  namespace LinuxSampler {
1426                                  case 0x1e: { // chorus send of note (Roland GS NRPN)                                  case 0x1e: { // chorus send of note (Roland GS NRPN)
1427                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1428                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1429                                      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));
1430                                      if (note < 128)                                      if (note < 128)
1431                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1432                                      break;                                      break;
# Line 1124  namespace LinuxSampler { Line 1579  namespace LinuxSampler {
1579              /**              /**
1580               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1581               *               *
1582               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1583               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1584               */               */
1585              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
1586                  EngineChannelBase<V, R, I>* pChannel =                  EngineChannelBase<V, R, I>* pChannel =
1587                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                          static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1588    
                 //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;  
   
1589                  const int key = itNoteOnEvent->Param.Note.Key;                  const int key = itNoteOnEvent->Param.Note.Key;
1590                    const int vel = itNoteOnEvent->Param.Note.Velocity;
1591                    if (key < 0 || key > 127) return; // ignore event, key outside allowed key range
1592    
1593                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[key];
1594    
1595                  pChannel->listeners.PreProcessNoteOn(key, vel);                  pChannel->listeners.PreProcessNoteOn(key, vel);
# Line 1166  namespace LinuxSampler { Line 1617  namespace LinuxSampler {
1617                          if (pOtherKey->Active) {                          if (pOtherKey->Active) {
1618                              // get final portamento position of currently active voice                              // get final portamento position of currently active voice
1619                              if (pChannel->PortamentoMode) {                              if (pChannel->PortamentoMode) {
1620                                  VoiceIterator itVoice = pOtherKey->pActiveVoices->last();                                  NoteIterator itNote = pOtherKey->pActiveNotes->last();
1621                                  if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);                                  if (itNote) {
1622                                        VoiceIterator itVoice = itNote->pActiveVoices->last();
1623                                        if (itVoice) itVoice->UpdatePortamentoPos(itNoteOnEventOnKeyList);
1624                                    }
1625                              }                              }
1626                              // kill all voices on the (other) key                              // kill all voices on the (other) key
1627                              VoiceIterator itVoiceToBeKilled = pOtherKey->pActiveVoices->first();                              for (NoteIterator itNote = pOtherKey->pActiveNotes->first(); itNote; ++itNote) {
1628                              VoiceIterator end               = pOtherKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1629                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1630                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1631                                      itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1632                                            itVoiceToBeKilled->Kill(itNoteOnEventOnKeyList);
1633                                    }
1634                              }                              }
1635                          }                          }
1636                      }                      }
# Line 1185  namespace LinuxSampler { Line 1641  namespace LinuxSampler {
1641                  pChannel->ProcessKeySwitchChange(key);                  pChannel->ProcessKeySwitchChange(key);
1642    
1643                  pKey->KeyPressed = true; // the MIDI key was now pressed down                  pKey->KeyPressed = true; // the MIDI key was now pressed down
1644                    pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1645                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1646                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1647    
# Line 1235  namespace LinuxSampler { Line 1692  namespace LinuxSampler {
1692               *  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.
1693               *  due to completion of sample playback).               *  due to completion of sample playback).
1694               *               *
1695               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1696               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1697               */               */
1698              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
1699                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);                  EngineChannelBase<V, R, I>* pChannel = static_cast<EngineChannelBase<V, R, I>*>(pEngineChannel);
1700    
                 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;  
   
1701                  const int iKey = itNoteOffEvent->Param.Note.Key;                  const int iKey = itNoteOffEvent->Param.Note.Key;
1702                    const int vel  = itNoteOffEvent->Param.Note.Velocity;
1703                    if (iKey < 0 || iKey > 127) return; // ignore event, key outside allowed key range
1704    
1705                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];                  MidiKey* pKey = &pChannel->pMIDIKeyInfo[iKey];
1706    
1707                  pChannel->listeners.PreProcessNoteOff(iKey, vel);                  pChannel->listeners.PreProcessNoteOff(iKey, vel);
# Line 1261  namespace LinuxSampler { Line 1714  namespace LinuxSampler {
1714                  #endif                  #endif
1715    
1716                  pKey->KeyPressed = false; // the MIDI key was now released                  pKey->KeyPressed = false; // the MIDI key was now released
1717                    pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1718    
1719                  // move event to the key's own event list                  // move event to the key's own event list
1720                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
# Line 1281  namespace LinuxSampler { Line 1735  namespace LinuxSampler {
1735                                  pChannel->SoloKey = i;                                  pChannel->SoloKey = i;
1736                                  // get final portamento position of currently active voice                                  // get final portamento position of currently active voice
1737                                  if (pChannel->PortamentoMode) {                                  if (pChannel->PortamentoMode) {
1738                                      VoiceIterator itVoice = pKey->pActiveVoices->first();                                      NoteIterator itNote = pKey->pActiveNotes->first();
1739                                        VoiceIterator itVoice = itNote->pActiveVoices->first();
1740                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);                                      if (itVoice) itVoice->UpdatePortamentoPos(itNoteOffEventOnKeyList);
1741                                  }                                  }
1742                                  // create a pseudo note on event                                  // create a pseudo note on event
# Line 1293  namespace LinuxSampler { Line 1748  namespace LinuxSampler {
1748                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;                                      itPseudoNoteOnEvent->Type                = Event::type_note_on;
1749                                      itPseudoNoteOnEvent->Param.Note.Key      = i;                                      itPseudoNoteOnEvent->Param.Note.Key      = i;
1750                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;                                      itPseudoNoteOnEvent->Param.Note.Velocity = pOtherKey->Velocity;
1751                                      // allocate and trigger new voice(s) for the other key                                      // assign a new note to this note-on event
1752                                      TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);                                      if (LaunchNewNote(pChannel, &*itPseudoNoteOnEvent)) {
1753                                            // allocate and trigger new voice(s) for the other key
1754                                            TriggerNewVoices(pChannel, itPseudoNoteOnEvent, false);
1755                                        }
1756                                      // if neither a voice was spawned or postponed then remove note on event from key again                                      // if neither a voice was spawned or postponed then remove note on event from key again
1757                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)                                      if (!pOtherKey->Active && !pOtherKey->VoiceTheftsQueued)
1758                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);                                          pOtherKey->pEvents->free(itPseudoNoteOnEvent);
# Line 1307  namespace LinuxSampler { Line 1765  namespace LinuxSampler {
1765                      if (bOtherKeysPressed) {                      if (bOtherKeysPressed) {
1766                          if (pKey->Active) { // kill all voices on this key                          if (pKey->Active) { // kill all voices on this key
1767                              bShouldRelease = false; // no need to release, as we kill it here                              bShouldRelease = false; // no need to release, as we kill it here
1768                              VoiceIterator itVoiceToBeKilled = pKey->pActiveVoices->first();                              for (NoteIterator itNote = pKey->pActiveNotes->first(); itNote; ++itNote) {
1769                              VoiceIterator end               = pKey->pActiveVoices->end();                                  VoiceIterator itVoiceToBeKilled = itNote->pActiveVoices->first();
1770                              for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {                                  VoiceIterator end               = itNote->pActiveVoices->end();
1771                                  if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))                                  for (; itVoiceToBeKilled != end; ++itVoiceToBeKilled) {
1772                                      itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);                                      if (!(itVoiceToBeKilled->Type & Voice::type_release_trigger))
1773                                            itVoiceToBeKilled->Kill(itNoteOffEventOnKeyList);
1774                                    }
1775                              }                              }
1776                          }                          }
1777                      } else pChannel->PortamentoPos = -1.0f;                      } else pChannel->PortamentoPos = -1.0f;
# Line 1323  namespace LinuxSampler { Line 1783  namespace LinuxSampler {
1783    
1784                      // spawn release triggered voice(s) if needed                      // spawn release triggered voice(s) if needed
1785                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {                      if (pKey->ReleaseTrigger && pChannel->pInstrument) {
1786                          TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);                          // assign a new note to this release event
1787                            if (LaunchNewNote(pChannel, &*itNoteOffEventOnKeyList)) {
1788                                // allocate and trigger new release voice(s)
1789                                TriggerReleaseVoices(pChannel, itNoteOffEventOnKeyList);
1790                            }
1791                          pKey->ReleaseTrigger = false;                          pKey->ReleaseTrigger = false;
1792                      }                      }
1793                  }                  }
# Line 1352  namespace LinuxSampler { Line 1816  namespace LinuxSampler {
1816                  pVoiceStealingQueue->clear();                  pVoiceStealingQueue->clear();
1817                  itLastStolenVoice          = VoiceIterator();                  itLastStolenVoice          = VoiceIterator();
1818                  itLastStolenVoiceGlobally  = VoiceIterator();                  itLastStolenVoiceGlobally  = VoiceIterator();
1819                    itLastStolenNote           = NoteIterator();
1820                    itLastStolenNoteGlobally   = NoteIterator();
1821                  iuiLastStolenKey           = RTList<uint>::Iterator();                  iuiLastStolenKey           = RTList<uint>::Iterator();
1822                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();                  iuiLastStolenKeyGlobally   = RTList<uint>::Iterator();
1823                  pLastStolenChannel         = NULL;                  pLastStolenChannel         = NULL;
1824    
1825                    // reset all notes
1826                    pNotePool->clear();
1827                    for (NoteIterator itNote = pNotePool->allocAppend(); itNote;
1828                         itNote = pNotePool->allocAppend())
1829                    {
1830                        itNote->reset();
1831                    }
1832                    pNotePool->clear();
1833    
1834                  // reset all voices                  // reset all voices
1835                    pVoicePool->clear();
1836                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
1837                      iterVoice->Reset();                      iterVoice->Reset();
1838                  }                  }
1839                  pVoicePool->clear();                  pVoicePool->clear();
1840    
1841                    // reset all engine channels
1842                    for (int i = 0; i < engineChannels.size(); i++) {
1843                        AbstractEngineChannel* pEngineChannel =
1844                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
1845                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
1846                    }
1847    
1848                  // reset disk thread                  // reset disk thread
1849                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
1850    
# Line 1390  namespace LinuxSampler { Line 1873  namespace LinuxSampler {
1873               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
1874               *  (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).
1875               *               *
1876               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
1877               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
1878               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
1879               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)
# Line 1433  namespace LinuxSampler { Line 1916  namespace LinuxSampler {
1916                      // launch the new voice                      // launch the new voice
1917                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {                      if (itNewVoice->Trigger(pChannel, itNoteOnEvent, pChannel->Pitch, pRegion, VoiceType, iKeyGroup) < 0) {
1918                          dmsg(4,("Voice not triggered\n"));                          dmsg(4,("Voice not triggered\n"));
1919                          pKey->pActiveVoices->free(itNewVoice);                          GetVoicePool()->free(itNewVoice);
1920                      }                      }
1921                      else { // on success                      else { // on success
1922                          --VoiceSpawnsLeft;                          --VoiceSpawnsLeft;
# Line 1482  namespace LinuxSampler { Line 1965  namespace LinuxSampler {
1965              }              }
1966    
1967          private:          private:
1968                Pool< Note<V> >* pNotePool;
1969                Pool<note_id_t> noteIDPool;
1970              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.
1971              Pool<RR*>   SuspendedRegions;              Pool<RR*>   SuspendedRegions;
1972              Mutex       SuspendedRegionsMutex;              Mutex       SuspendedRegionsMutex;

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

  ViewVC Help
Powered by ViewVC