/[svn]/linuxsampler/trunk/src/engines/AbstractEngineChannel.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/AbstractEngineChannel.cpp

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

revision 2606 by persson, Sun Jun 8 05:42:56 2014 UTC revision 2871 by schoenebeck, Sun Apr 10 18:22:23 2016 UTC
# Line 5  Line 5 
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-2012 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8   *   Copyright (C) 2013-2014 Christian Schoenebeck and Andreas Persson     *   *   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 35  namespace LinuxSampler { Line 35  namespace LinuxSampler {
35      {      {
36          pEngine      = NULL;          pEngine      = NULL;
37          pEvents      = NULL; // we allocate when we retrieve the right Engine object          pEvents      = NULL; // we allocate when we retrieve the right Engine object
38            delayedEvents.pList = NULL;
39          pEventQueue  = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue  = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
40          InstrumentIdx  = -1;          InstrumentIdx  = -1;
41          InstrumentStat = -1;          InstrumentStat = -1;
# Line 46  namespace LinuxSampler { Line 47  namespace LinuxSampler {
47          ResetControllers();          ResetControllers();
48          PortamentoMode = false;          PortamentoMode = false;
49          PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;          PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;
50          pScriptEvents = NULL;          pScript = NULL;
51      }      }
52    
53      AbstractEngineChannel::~AbstractEngineChannel() {      AbstractEngineChannel::~AbstractEngineChannel() {
         unloadCurrentInstrumentScript();  
         if (pScriptEvents) delete pScriptEvents;  
54          delete pEventQueue;          delete pEventQueue;
55          DeleteGroupEventLists();          DeleteGroupEventLists();
56          RemoveAllFxSends();          RemoveAllFxSends();
# Line 103  namespace LinuxSampler { Line 102  namespace LinuxSampler {
102    
103      void AbstractEngineChannel::Reset() {      void AbstractEngineChannel::Reset() {
104          if (pEngine) pEngine->DisableAndLock();          if (pEngine) pEngine->DisableAndLock();
105          ResetInternal();          ResetInternal(false/*don't reset engine*/);
106          ResetControllers();          ResetControllers();
107          if (pEngine) {          if (pEngine) {
108              pEngine->Enable();              pEngine->Enable();
# Line 131  namespace LinuxSampler { Line 130  namespace LinuxSampler {
130      /**      /**
131       * This method is not thread safe!       * This method is not thread safe!
132       */       */
133      void AbstractEngineChannel::ResetInternal() {      void AbstractEngineChannel::ResetInternal(bool bResetEngine) {
134          CurrentKeyDimension = 0;          CurrentKeyDimension = 0;
135          PortamentoPos = -1.0f; // no portamento active yet          PortamentoPos = -1.0f; // no portamento active yet
136    
137            // delete all active instrument script events
138            if (pScript) pScript->resetEvents();
139    
140            // free all delayed MIDI events
141            delayedEvents.clear();
142    
143          // delete all input events          // delete all input events
144          pEventQueue->init();          pEventQueue->init();
145    
146          if (pEngine) pEngine->ResetInternal();          if (bResetEngine && pEngine) pEngine->ResetInternal();
147    
148          // status of engine channel has changed, so set notify flag          // status of engine channel has changed, so set notify flag
149          bStatusChanged = true;          bStatusChanged = true;
150      }      }
151    
152      /**      /**
      * Loads the real-time instrument script given by @a text on this engine  
      * channel. A resource manager is used to allocate and share equivalent  
      * scripts on multiple engine channels.  
      *  
      * @param text - source code of script  
      */  
     void AbstractEngineChannel::loadInstrumentScript(const String& text) {  
         dmsg(1,("Loading real-time instrument script ... "));  
   
         // hand back old script reference and VM execution contexts  
         // (if not done already)  
         unloadCurrentInstrumentScript();  
   
         // get new script reference  
         script.parserContext = pEngine->scripts.Borrow(text, this);  
         if (!script.parserContext->errors().empty()) {  
             std::vector<ParserIssue> errors = script.parserContext->errors();  
             std::cerr << "[ScriptVM] Could not load instrument script, there were "  
                       << errors.size() << " parser errors:\n";  
             for (int i = 0; i < errors.size(); ++i)  
                 errors[i].dump();  
             return; // stop here if there were any parser errors  
         }  
   
         script.handlerInit = script.parserContext->eventHandlerByName("init");  
         script.handlerNote = script.parserContext->eventHandlerByName("note");  
         script.handlerRelease = script.parserContext->eventHandlerByName("release");  
         script.handlerController = script.parserContext->eventHandlerByName("controller");  
         script.bHasValidScript =  
             script.handlerInit || script.handlerNote || script.handlerRelease ||  
             script.handlerController;  
   
         // amount of script handlers each script event has to execute  
         int handlerExecCount = 0;  
         if (script.handlerInit) handlerExecCount++; // "init" handler is always executed before the actual event handler  
         if (script.handlerNote || script.handlerRelease || script.handlerController) // only one of these are executed after "init" handler  
             handlerExecCount++;  
   
         // create script event pool (if it doesn't exist already)  
         if (!pScriptEvents)  
             pScriptEvents = new Pool<ScriptEvent>(CONFIG_MAX_EVENTS_PER_FRAGMENT);  
   
         // create new VM execution contexts for new script  
         while (!pScriptEvents->poolIsEmpty()) {  
             RTList<ScriptEvent>::Iterator it = pScriptEvents->allocAppend();  
             it->execCtx = pEngine->pScriptVM->createExecContext(  
                 script.parserContext  
             );  
             it->handlers = new VMEventHandler*[handlerExecCount+1];  
         }  
         pScriptEvents->clear();  
   
         dmsg(1,("Done\n"));  
     }  
   
     /**  
      * Unloads the currently used real-time instrument script on this sampler  
      * channel. A resource manager is used to share equivalent scripts among  
      * multiple sampler channels, and to deallocate the parsed script once not  
      * used on any engine channel anymore.  
      */  
     void AbstractEngineChannel::unloadCurrentInstrumentScript() {  
         if (script.parserContext)  
             dmsg(1,("Unloading current instrument script."));  
   
         // free allocated VM execution contexts  
         if (pScriptEvents) {  
             pScriptEvents->clear();  
             while (!pScriptEvents->poolIsEmpty()) {  
                 RTList<ScriptEvent>::Iterator it = pScriptEvents->allocAppend();  
                 if (it->execCtx) {  
                     // free VM execution context object  
                     delete it->execCtx;  
                     it->execCtx = NULL;  
                     // free C array of handler pointers  
                     delete [] it->handlers;  
                 }  
             }  
             pScriptEvents->clear();  
         }  
         // hand back VM representation of script  
         if (script.parserContext) {  
             pEngine->scripts.HandBack(script.parserContext, this);  
             script.parserContext = NULL;  
             script.handlerInit = NULL;  
             script.handlerNote = NULL;  
             script.handlerRelease = NULL;  
             script.handlerController = NULL;  
         }  
         script.bHasValidScript = false;  
     }  
   
     /**  
153       * Implementation of virtual method from abstract EngineChannel interface.       * Implementation of virtual method from abstract EngineChannel interface.
154       * This method will periodically be polled (e.g. by the LSCP server) to       * This method will periodically be polled (e.g. by the LSCP server) to
155       * check if some engine channel parameter has changed since the last       * check if some engine channel parameter has changed since the last
# Line 731  namespace LinuxSampler { Line 643  namespace LinuxSampler {
643    
644              Event event = pEngine->pEventGenerator->CreateEvent();              Event event = pEngine->pEventGenerator->CreateEvent();
645              event.Type                          = Event::type_channel_pressure;              event.Type                          = Event::type_channel_pressure;
646                event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
647              event.Param.ChannelPressure.Value   = Value;              event.Param.ChannelPressure.Value   = Value;
648              event.Param.ChannelPressure.Channel = MidiChannel;              event.Param.ChannelPressure.Channel = MidiChannel;
649              memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes              memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
# Line 748  namespace LinuxSampler { Line 661  namespace LinuxSampler {
661    
662              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
663              event.Type                          = Event::type_channel_pressure;              event.Type                          = Event::type_channel_pressure;
664                event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
665              event.Param.ChannelPressure.Value   = Value;              event.Param.ChannelPressure.Value   = Value;
666              event.Param.ChannelPressure.Channel = MidiChannel;              event.Param.ChannelPressure.Channel = MidiChannel;
667              memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes              memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
# Line 864  namespace LinuxSampler { Line 778  namespace LinuxSampler {
778                                        << devEvent.Type << "). This is a bug!";                                        << devEvent.Type << "). This is a bug!";
779                              continue;                              continue;
780                      }                      }
781                        memset(&event.Format, 0, sizeof(event.Format)); // init format specific stuff with zeroes
782                      event.pEngineChannel = this;                      event.pEngineChannel = this;
783                      // copy event to internal event list                      // copy event to internal event list
784                      if (pEvents->poolIsEmpty()) {                      if (pEvents->poolIsEmpty()) {
# Line 902  namespace LinuxSampler { Line 817  namespace LinuxSampler {
817    
818      /**      /**
819       * Called by real-time instrument script functions to schedule a new event       * Called by real-time instrument script functions to schedule a new event
820       * somewhere in future.       * @a delay microseconds in future.
821       *       *
822       * @returns unique event ID of scheduled new event       * @b IMPORTANT: for the supplied @a delay to be scheduled correctly, the
823         * passed @a pEvent must be assigned a valid fragment time within the
824         * current audio fragment boundaries. That fragment time will be used by
825         * this method as basis for interpreting what "now" acutally is, and thus
826         * it will be used as basis for calculating the precise scheduling time
827         * for @a delay. The easiest way to achieve this is by copying a recent
828         * event which happened within the current audio fragment cycle: i.e. the
829         * original event which caused calling this method here.
830         *
831         * @param pEvent - event to be scheduled in future (event data will be copied)
832         * @param delay - amount of microseconds in future (from now) when event shall be processed
833         * @returns unique event ID of scheduled new event, or a negative number on error
834       */       */
835      int AbstractEngineChannel::ScheduleEvent(const Event* pEvent, int delay) { //TODO: delay not implemented yet      int AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int delay) {
836          // since delay is not implemented yet, we simply add the new event          dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%d)\n", pEvent->Type, delay));
         // to the event list of the current audio fragmet cycle for now  
837          RTList<Event>::Iterator itEvent = pEvents->allocAppend();          RTList<Event>::Iterator itEvent = pEvents->allocAppend();
838          if (itEvent) *itEvent = *pEvent; // copy event          if (!itEvent) {
839                dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n"));
840                return -1;
841            }
842            RTList<ScheduledEvent>::Iterator itNode = delayedEvents.schedulerNodes.allocAppend();
843            if (!itNode) { // scheduler node pool empty ...
844                dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): ScheduledEvent pool empty!\n"));
845                pEvents->free(itEvent);
846                return -1;
847            }
848            // copy passed event
849            *itEvent = *pEvent;
850            // move copied event to list of delayed events
851            itEvent = itEvent.moveToEndOf(delayedEvents.pList);
852            // connect scheduler node with the copied event
853            itNode->itEvent = itEvent;
854            // add entry to time sorted scheduler queue for copied event
855            pEngine->pEventGenerator->scheduleAheadMicroSec(
856                delayedEvents.queue, *itNode, itEvent->FragmentPos(), delay
857            );
858            //dmsg(5,("ScheduledEvent queue size: %d\n", delayedEvents.queue.size()));
859          return pEvents->getID(itEvent);          return pEvents->getID(itEvent);
860      }      }
861    

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

  ViewVC Help
Powered by ViewVC