/[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 2837 by persson, Sun Aug 23 06:14:00 2015 UTC revision 2871 by schoenebeck, Sun Apr 10 18:22:23 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-2015 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 635  namespace LinuxSampler { Line 636  namespace LinuxSampler {
636                  // the event list by running the script now, since the script                  // the event list by running the script now, since the script
637                  // might filter events or add new ones for this cycle                  // might filter events or add new ones for this cycle
638                  if (pChannel->pScript) {                  if (pChannel->pScript) {
639                      // resume any suspended script executions still hanging                      const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
640                      // around of previous audio fragment cycles  
641                      for (RTList<ScriptEvent>::Iterator itEvent = pChannel->pScript->pEvents->first(),                      // resume suspended script executions been scheduled for
642                          end = pChannel->pScript->pEvents->end(); itEvent != end; ++itEvent)                      // this audio fragment cycle (which were suspended in a
643                      {                      // previous audio fragment cycle)
644                          ResumeScriptEvent(pChannel, itEvent); //TODO: implement support for actual suspension time (i.e. passed to a script's wait() function call)                      ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
                     }  
645    
646                      // spawn new script executions for the new MIDI events of                      // spawn new script executions for the new MIDI events of
647                      // this audio fragment cycle                      // this audio fragment cycle
648                        //
649                        // 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
650                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),                      for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
651                          end = pChannel->pEvents->end(); itEvent != end; ++itEvent)                          end = pChannel->pEvents->end(); itEvent != end; ++itEvent)
652                      {                      {
# Line 668  namespace LinuxSampler { Line 670  namespace LinuxSampler {
670                                  break;                                  break;
671                          }                          }
672                      }                      }
673    
674                        // this has to be run again, since the newly spawned scripts
675                        // above may have cause suspended scripts that must be
676                        // resumed within this same audio fragment cycle
677                        //
678                        // FIXME: see FIXME comment above
679                        ProcessSuspendedScriptEvents(pChannel, fragmentEndTime);
680                    }
681    
682                    // if there are any delayed events scheduled for the current
683                    // audio fragment cycle, then move and sort them into the main
684                    // event list
685                    if (!pChannel->delayedEvents.queue.isEmpty()) {
686                        dmsg(5,("Engine: There are delayed MIDI events (total queue size: %d) ...\n", pChannel->delayedEvents.queue.size()));
687                        const sched_time_t fragmentEndTime = pEventGenerator->schedTimeAtCurrentFragmentEnd();
688                        RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
689                        while (true) {
690                            RTList<ScheduledEvent>::Iterator itDelayedEventNode =
691                                pEventGenerator->popNextScheduledEvent(
692                                    pChannel->delayedEvents.queue,
693                                    pChannel->delayedEvents.schedulerNodes,
694                                    fragmentEndTime
695                                );
696                            if (!itDelayedEventNode) break;
697                            // get the actual delayed event object and free the used scheduler node
698                            RTList<Event>::Iterator itDelayedEvent = itDelayedEventNode->itEvent;
699                            pChannel->delayedEvents.schedulerNodes.free(itDelayedEventNode);
700                            if (!itDelayedEvent) { // should never happen, but just to be sure ...
701                                dmsg(1,("Engine: Oops, invalid delayed event!\n"));
702                                continue;
703                            }
704                            // skip all events on main event list which have a time
705                            // before (or equal to) the delayed event to be inserted
706                            for (; itEvent && itEvent->FragmentPos() <= itDelayedEvent->FragmentPos();
707                                 ++itEvent);
708                            // now move delayed event from delayedEvents.pList to
709                            // the current position on the main event list
710                            itEvent = itDelayedEvent.moveBefore(itEvent);
711                            dmsg(5,("Engine: Inserted event of type %d into main event list (queue size: %d).\n", itEvent->Type, pChannel->delayedEvents.queue.size()));
712                        }
713                        dmsg(5,("Engine: End of delayed events (total queue size: %d).\n", pChannel->delayedEvents.queue.size()));
714                  }                  }
715    
716                  // now process all events regularly                  // now process all events regularly
# Line 712  namespace LinuxSampler { Line 755  namespace LinuxSampler {
755                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
756              }              }
757    
758                /**
759                 * Run all suspended script execution instances which are scheduled
760                 * to be resumed for the current audio fragment cycle.
761                 *
762                 * @param pChannel - engine channel on which suspended events occurred
763                 */
764                void ProcessSuspendedScriptEvents(AbstractEngineChannel* pChannel, const sched_time_t fragmentEndTime) {
765                    while (true) {
766                        RTList<ScriptEvent>::Iterator itEvent =
767                            pEventGenerator->popNextScheduledScriptEvent(
768                                pChannel->pScript->suspendedEvents,
769                                *pChannel->pScript->pEvents, fragmentEndTime
770                            );
771                        if (!itEvent) break;
772                        ResumeScriptEvent(pChannel, itEvent);
773                    }
774                }
775    
776              /** @brief Call instrument script's event handler for this event.              /** @brief Call instrument script's event handler for this event.
777               *               *
778               * Causes a new execution instance of the currently loaded real-time               * Causes a new execution instance of the currently loaded real-time
779               * instrument script's event handler (callback) to be spawned for               * instrument script's event handler (callback) to be spawned for
780               * the given MIDI event.               * the given MIDI event.
781               *               *
782               * @param pChannel - engine channel on which the MIDI event occured               * @param pChannel - engine channel on which the MIDI event occurred
783               * @param itEvent - MIDI event that causes this new script execution               * @param itEvent - MIDI event that causes this new script execution
784               * @param pEventHandler - script's event handler to be executed               * @param pEventHandler - script's event handler to be executed
785               */               */
# Line 754  namespace LinuxSampler { Line 815  namespace LinuxSampler {
815                  }                  }
816              }              }
817    
818                /** @brief Spawn new execution instance of an instrument script handler.
819                 *
820                 * Will be called to initiate a new execution of a real-time
821                 * instrument script event right from the start of the script's
822                 * respective handler. If script execution did not complete after
823                 * calling this method, the respective script exeuction is then
824                 * suspended and a call to ResumeScriptEvent() will be used next
825                 * time to continue its execution.
826                 *
827                 * @param pChannel - engine channel this script is running for
828                 * @param itEvent - event which caused execution of this script
829                 *                  event handler
830                 * @param pEventHandler - VM representation of event handler to be
831                 *                        executed
832                 * @param itScriptEvent - script event that shall be processed
833                 */
834              void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {              void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
835                  if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)                  if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
836    
# Line 773  namespace LinuxSampler { Line 850  namespace LinuxSampler {
850                      pChannel->pScript->parserContext, &*itScriptEvent                      pChannel->pScript->parserContext, &*itScriptEvent
851                  );                  );
852    
853                  // in case the script was suspended, keep it on the allocated                  // was the script suspended?
854                  // ScriptEvent list to be continued on the next audio cycle                  if (res & VM_EXEC_SUSPENDED) { // script was suspended ...
855                  if (!(res & VM_EXEC_SUSPENDED)) { // script execution has finished without 'suspended' status ...                      // in case the script was suspended, keep it on the allocated
856                        // ScriptEvent list to be resume at the scheduled time in future,
857                        // additionally insert it into a sorted time queue
858                        pEventGenerator->scheduleAheadMicroSec(
859                            pChannel->pScript->suspendedEvents, // scheduler queue
860                            *itScriptEvent, // script event
861                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
862                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
863                        );
864                    } else { // script execution has finished without 'suspended' status ...
865                      // if "polyphonic" variable data is passed from script's                      // if "polyphonic" variable data is passed from script's
866                      // "note" event handler to its "release" event handler, then                      // "note" event handler to its "release" event handler, then
867                      // the script event must be kept and recycled for the later                      // the script event must be kept and recycled for the later
# Line 822  namespace LinuxSampler { Line 908  namespace LinuxSampler {
908                      pChannel->pScript->parserContext, &*itScriptEvent                      pChannel->pScript->parserContext, &*itScriptEvent
909                  );                  );
910    
911                  // in case the script was suspended, keep it on the allocated                  // was the script suspended?
912                  // ScriptEvent list to be continued on the next audio cycle                  if (res & VM_EXEC_SUSPENDED) {
913                  if (!(res & VM_EXEC_SUSPENDED)) { // script execution has finished without 'suspended' status ...                      // in case the script was suspended, keep it on the allocated
914                        // ScriptEvent list to be resume at the scheduled time in future,
915                        // additionally insert it into a sorted time queue
916                        pEventGenerator->scheduleAheadMicroSec(
917                            pChannel->pScript->suspendedEvents, // scheduler queue
918                            *itScriptEvent, // script event
919                            itScriptEvent->cause.FragmentPos(), // current time of script event (basis for its next execution)
920                            itScriptEvent->execCtx->suspensionTimeMicroseconds() // how long shall it be suspended
921                        );
922                    } else { // script execution has finished without 'suspended' status ...
923                      // if "polyphonic" variable data is passed from script's                      // if "polyphonic" variable data is passed from script's
924                      // "note" event handler to its "release" event handler, then                      // "note" event handler to its "release" event handler, then
925                      // the script event must be kept and recycled for the later                      // the script event must be kept and recycled for the later
# Line 852  namespace LinuxSampler { Line 947  namespace LinuxSampler {
947               *  voice stealing and postpone the note-on event until the selected               *  voice stealing and postpone the note-on event until the selected
948               *  voice actually died.               *  voice actually died.
949               *               *
950               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
951               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
952               *  @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
953               */               */
# Line 1090  namespace LinuxSampler { Line 1185  namespace LinuxSampler {
1185                   pChannel->FreeAllInactiveKyes();                   pChannel->FreeAllInactiveKyes();
1186    
1187                  // empty the engine channel's own event lists                  // empty the engine channel's own event lists
1188                  pChannel->ClearEventLists();                  // (only events of the current audio fragment cycle)
1189                    pChannel->ClearEventListsOfCurrentFragment();
1190              }              }
1191    
1192              /**              /**
# Line 1316  namespace LinuxSampler { Line 1412  namespace LinuxSampler {
1412              /**              /**
1413               *  Assigns and triggers a new voice for the respective MIDI key.               *  Assigns and triggers a new voice for the respective MIDI key.
1414               *               *
1415               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1416               *  @param itNoteOnEvent - key, velocity and time stamp of the event               *  @param itNoteOnEvent - key, velocity and time stamp of the event
1417               */               */
1418              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {              virtual void ProcessNoteOn(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOnEvent) {
# Line 1428  namespace LinuxSampler { Line 1524  namespace LinuxSampler {
1524               *  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.
1525               *  due to completion of sample playback).               *  due to completion of sample playback).
1526               *               *
1527               *  @param pEngineChannel - engine channel on which this event occured on               *  @param pEngineChannel - engine channel on which this event occurred on
1528               *  @param itNoteOffEvent - key, velocity and time stamp of the event               *  @param itNoteOffEvent - key, velocity and time stamp of the event
1529               */               */
1530              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {              virtual void ProcessNoteOff(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itNoteOffEvent) {
# Line 1556  namespace LinuxSampler { Line 1652  namespace LinuxSampler {
1652                  }                  }
1653                  pVoicePool->clear();                  pVoicePool->clear();
1654    
1655                    // reset all engine channels
1656                    for (int i = 0; i < engineChannels.size(); i++) {
1657                        AbstractEngineChannel* pEngineChannel =
1658                            static_cast<AbstractEngineChannel*>(engineChannels[i]);
1659                        pEngineChannel->ResetInternal(false/*don't reset engine*/);
1660                    }
1661    
1662                  // reset disk thread                  // reset disk thread
1663                  if (pDiskThread) pDiskThread->Reset();                  if (pDiskThread) pDiskThread->Reset();
1664    
# Line 1584  namespace LinuxSampler { Line 1687  namespace LinuxSampler {
1687               *  called by the ProcessNoteOn() method and by the voices itself               *  called by the ProcessNoteOn() method and by the voices itself
1688               *  (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).
1689               *               *
1690               *  @param pEngineChannel      - engine channel on which this event occured on               *  @param pEngineChannel      - engine channel on which this event occurred on
1691               *  @param itNoteOnEvent       - key, velocity and time stamp of the event               *  @param itNoteOnEvent       - key, velocity and time stamp of the event
1692               *  @param iLayer              - layer index for the new voice (optional - only               *  @param iLayer              - layer index for the new voice (optional - only
1693               *                               in case of layered sounds of course)               *                               in case of layered sounds of course)

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

  ViewVC Help
Powered by ViewVC