/[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 2596 by schoenebeck, Thu Jun 5 19:39:12 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 471  namespace LinuxSampler { Line 383  namespace LinuxSampler {
383              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
384              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
385              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
386                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
387              event.pEngineChannel      = this;              event.pEngineChannel      = this;
388              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
389              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 512  namespace LinuxSampler { Line 425  namespace LinuxSampler {
425              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
426              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
427              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
428                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
429              event.pEngineChannel      = this;              event.pEngineChannel      = this;
430              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
431              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 548  namespace LinuxSampler { Line 462  namespace LinuxSampler {
462              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
463              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
464              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
465                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
466              event.pEngineChannel      = this;              event.pEngineChannel      = this;
467              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
468              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 589  namespace LinuxSampler { Line 504  namespace LinuxSampler {
504              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
505              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
506              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
507                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
508              event.pEngineChannel      = this;              event.pEngineChannel      = this;
509              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
510              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 623  namespace LinuxSampler { Line 539  namespace LinuxSampler {
539              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
540              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
541              event.Param.Pitch.Channel = MidiChannel;              event.Param.Pitch.Channel = MidiChannel;
542                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
543              event.pEngineChannel    = this;              event.pEngineChannel    = this;
544              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
545              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 652  namespace LinuxSampler { Line 569  namespace LinuxSampler {
569              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
570              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
571              event.Param.Pitch.Channel = MidiChannel;              event.Param.Pitch.Channel = MidiChannel;
572                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
573              event.pEngineChannel    = this;              event.pEngineChannel    = this;
574              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
575              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 678  namespace LinuxSampler { Line 596  namespace LinuxSampler {
596              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
597              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
598              event.Param.CC.Channel    = MidiChannel;              event.Param.CC.Channel    = MidiChannel;
599                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
600              event.pEngineChannel      = this;              event.pEngineChannel      = this;
601              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
602              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 709  namespace LinuxSampler { Line 628  namespace LinuxSampler {
628              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
629              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
630              event.Param.CC.Channel    = MidiChannel;              event.Param.CC.Channel    = MidiChannel;
631                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
632              event.pEngineChannel      = this;              event.pEngineChannel      = this;
633              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
634              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 723  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
650              event.pEngineChannel                = this;              event.pEngineChannel                = this;
651              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
652              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 739  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
668              event.pEngineChannel                = this;              event.pEngineChannel                = this;
669              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
670              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 758  namespace LinuxSampler { Line 682  namespace LinuxSampler {
682              event.Param.NotePressure.Key     = Key;              event.Param.NotePressure.Key     = Key;
683              event.Param.NotePressure.Value   = Value;              event.Param.NotePressure.Value   = Value;
684              event.Param.NotePressure.Channel = MidiChannel;              event.Param.NotePressure.Channel = MidiChannel;
685                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
686              event.pEngineChannel             = this;              event.pEngineChannel             = this;
687              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
688              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 775  namespace LinuxSampler { Line 700  namespace LinuxSampler {
700              event.Param.NotePressure.Key     = Key;              event.Param.NotePressure.Key     = Key;
701              event.Param.NotePressure.Value   = Value;              event.Param.NotePressure.Value   = Value;
702              event.Param.NotePressure.Channel = MidiChannel;              event.Param.NotePressure.Channel = MidiChannel;
703                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
704              event.pEngineChannel             = this;              event.pEngineChannel             = this;
705              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
706              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 852  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 887  namespace LinuxSampler { Line 814  namespace LinuxSampler {
814          }          }
815          eventQueueReader.free(); // free all copied events from input queue          eventQueueReader.free(); // free all copied events from input queue
816      }      }
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         * @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      void 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);
860        }
861    
862        /**
863         * Called by real-time instrument script functions to ignore the event
864         * reflected by given event ID. The event will be freed immediately to its
865         * pool and cannot be dereferenced by its old ID anymore. Even if its
866         * allocated back from the Pool later on, it will have a different ID.
867         */
868        void AbstractEngineChannel::IgnoreEvent(int id) {
869            RTList<Event>::Iterator it = pEvents->fromID(id);
870            if (it) pEvents->free(it);
871      }      }
872    
873      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {

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

  ViewVC Help
Powered by ViewVC