/[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 2618 by schoenebeck, Wed Jun 11 11:39:44 2014 UTC revision 3018 by schoenebeck, Wed Oct 19 17:22:28 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 101  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 129  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;
# Line 376  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;
             memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes  
386              event.pEngineChannel      = this;              event.pEngineChannel      = this;
387              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
388              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 418  namespace LinuxSampler { Line 424  namespace LinuxSampler {
424              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
425              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
426              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
             memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes  
427              event.pEngineChannel      = this;              event.pEngineChannel      = this;
428              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
429              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 455  namespace LinuxSampler { Line 460  namespace LinuxSampler {
460              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
461              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
462              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
             memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes  
463              event.pEngineChannel      = this;              event.pEngineChannel      = this;
464              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
465              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 497  namespace LinuxSampler { Line 501  namespace LinuxSampler {
501              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
502              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
503              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
             memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes  
504              event.pEngineChannel      = this;              event.pEngineChannel      = this;
505              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
506              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 532  namespace LinuxSampler { Line 535  namespace LinuxSampler {
535              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
536              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
537              event.Param.Pitch.Channel = MidiChannel;              event.Param.Pitch.Channel = MidiChannel;
             memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes  
538              event.pEngineChannel    = this;              event.pEngineChannel    = this;
539              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
540              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 562  namespace LinuxSampler { Line 564  namespace LinuxSampler {
564              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
565              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
566              event.Param.Pitch.Channel = MidiChannel;              event.Param.Pitch.Channel = MidiChannel;
             memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes  
567              event.pEngineChannel    = this;              event.pEngineChannel    = this;
568              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
569              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 589  namespace LinuxSampler { Line 590  namespace LinuxSampler {
590              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
591              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
592              event.Param.CC.Channel    = MidiChannel;              event.Param.CC.Channel    = MidiChannel;
             memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes  
593              event.pEngineChannel      = this;              event.pEngineChannel      = this;
594              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
595              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 621  namespace LinuxSampler { Line 621  namespace LinuxSampler {
621              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
622              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
623              event.Param.CC.Channel    = MidiChannel;              event.Param.CC.Channel    = MidiChannel;
             memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes  
624              event.pEngineChannel      = this;              event.pEngineChannel      = this;
625              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
626              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 639  namespace LinuxSampler { Line 638  namespace LinuxSampler {
638              event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts              event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
639              event.Param.ChannelPressure.Value   = Value;              event.Param.ChannelPressure.Value   = Value;
640              event.Param.ChannelPressure.Channel = MidiChannel;              event.Param.ChannelPressure.Channel = MidiChannel;
             memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes  
641              event.pEngineChannel                = this;              event.pEngineChannel                = this;
642              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
643              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 657  namespace LinuxSampler { Line 655  namespace LinuxSampler {
655              event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts              event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
656              event.Param.ChannelPressure.Value   = Value;              event.Param.ChannelPressure.Value   = Value;
657              event.Param.ChannelPressure.Channel = MidiChannel;              event.Param.ChannelPressure.Channel = MidiChannel;
             memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes  
658              event.pEngineChannel                = this;              event.pEngineChannel                = this;
659              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
660              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 675  namespace LinuxSampler { Line 672  namespace LinuxSampler {
672              event.Param.NotePressure.Key     = Key;              event.Param.NotePressure.Key     = Key;
673              event.Param.NotePressure.Value   = Value;              event.Param.NotePressure.Value   = Value;
674              event.Param.NotePressure.Channel = MidiChannel;              event.Param.NotePressure.Channel = MidiChannel;
             memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes  
675              event.pEngineChannel             = this;              event.pEngineChannel             = this;
676              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
677              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 693  namespace LinuxSampler { Line 689  namespace LinuxSampler {
689              event.Param.NotePressure.Key     = Key;              event.Param.NotePressure.Key     = Key;
690              event.Param.NotePressure.Value   = Value;              event.Param.NotePressure.Value   = Value;
691              event.Param.NotePressure.Channel = MidiChannel;              event.Param.NotePressure.Channel = MidiChannel;
             memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes  
692              event.pEngineChannel             = this;              event.pEngineChannel             = this;
693              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
694              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
695          }          }
696      }      }
697    
698        bool AbstractEngineChannel::applyTranspose(Event* event) {
699            if (event->Type != Event::type_note_on && event->Type != Event::type_note_off)
700                return true; // event OK (not a note event, nothing to do with it here)
701    
702            //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
703            const int k = event->Param.Note.Key + GlobalTranspose;
704            if (k < 0 || k > 127)
705                return false; // bad event, drop it
706    
707            event->Param.Note.Key = k;
708    
709            return true; // event OK
710        }
711    
712      /**      /**
713       * Copy all events from the engine channel's input event queue buffer to       * Copy all events from the engine channel's input event queue buffer to
714       * the internal event list. This will be done at the beginning of each       * the internal event list. This will be done at the beginning of each
# Line 736  namespace LinuxSampler { Line 745  namespace LinuxSampler {
745                              event.Param.Note.Key      = devEvent.Arg1;                              event.Param.Note.Key      = devEvent.Arg1;
746                              event.Param.Note.Velocity = devEvent.Arg2;                              event.Param.Note.Velocity = devEvent.Arg2;
747                              event.Param.Note.Channel  = channel;                              event.Param.Note.Channel  = channel;
748                                // apply transpose setting to (note on/off) event
749                                if (!applyTranspose(&event))
750                                    continue; // note value is out of range, so drop this event
751                                // assign a new note to this note-on event
752                                if (!pEngine->LaunchNewNote(this, &event))
753                                    continue; // failed launching new note, so drop this event
754                              break;                              break;
755                          case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:                          case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
756                              event.Type = Event::type_note_off;                              event.Type = Event::type_note_off;
757                              event.Param.Note.Key      = devEvent.Arg1;                              event.Param.Note.Key      = devEvent.Arg1;
758                              event.Param.Note.Velocity = devEvent.Arg2;                              event.Param.Note.Velocity = devEvent.Arg2;
759                              event.Param.Note.Channel  = channel;                              event.Param.Note.Channel  = channel;
760                                if (!applyTranspose(&event))
761                                    continue; // note value is out of range, so drop this event
762                              break;                              break;
763                          case VirtualMidiDevice::EVENT_TYPE_CC:                          case VirtualMidiDevice::EVENT_TYPE_CC:
764                              switch (devEvent.Arg1) {                              switch (devEvent.Arg1) {
# Line 766  namespace LinuxSampler { Line 783  namespace LinuxSampler {
783                          case VirtualMidiDevice::EVENT_TYPE_PROGRAM:                          case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
784                              SendProgramChange(devEvent.Arg1);                              SendProgramChange(devEvent.Arg1);
785                              continue; // don't push this event into FIFO                              continue; // don't push this event into FIFO
786                            case VirtualMidiDevice::EVENT_TYPE_CHPRESSURE:
787                                event.Type = Event::type_channel_pressure;
788                                event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH;
789                                event.Param.ChannelPressure.Value   = devEvent.Arg2;
790                                event.Param.ChannelPressure.Channel = channel;
791                                break;
792                          default:                          default:
793                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
794                                        << devEvent.Type << "). This is a bug!";                                        << devEvent.Type << "). This is a bug!";
# Line 797  namespace LinuxSampler { Line 820  namespace LinuxSampler {
820                  pEvent->ResetFragmentPos();                  pEvent->ResetFragmentPos();
821                  break;                  break;
822              }              }
             // copy event to internal event list  
823              if (pEvents->poolIsEmpty()) {              if (pEvents->poolIsEmpty()) {
824                  dmsg(1,("Event pool emtpy!\n"));                  dmsg(1,("Event pool emtpy!\n"));
825                  break;                  break;
826              }              }
827                // apply transpose setting to (note on/off) event
828                if (!applyTranspose(pEvent))
829                    continue; // it's a note event which has a note value out of range, so drop this event
830                // assign a new note to this event (if its a note-on event)
831                if (pEvent->Type == Event::type_note_on)
832                    if (!pEngine->LaunchNewNote(this, pEvent))
833                        continue; // failed launching new note, so drop this event
834                // copy event to internal event list
835              *pEvents->allocAppend() = *pEvent;              *pEvents->allocAppend() = *pEvent;
836          }          }
837          eventQueueReader.free(); // free all copied events from input queue          eventQueueReader.free(); // free all copied events from input queue
# Line 809  namespace LinuxSampler { Line 839  namespace LinuxSampler {
839    
840      /**      /**
841       * Called by real-time instrument script functions to schedule a new event       * Called by real-time instrument script functions to schedule a new event
842       * somewhere in future.       * @a delay microseconds in future.
843       *       *
844       * @returns unique event ID of scheduled new event       * @b IMPORTANT: for the supplied @a delay to be scheduled correctly, the
845         * passed @a pEvent must be assigned a valid fragment time within the
846         * current audio fragment boundaries. That fragment time will be used by
847         * this method as basis for interpreting what "now" acutally is, and thus
848         * it will be used as basis for calculating the precise scheduling time
849         * for @a delay. The easiest way to achieve this is by copying a recent
850         * event which happened within the current audio fragment cycle: i.e. the
851         * original event which caused calling this method here.
852         *
853         * @param pEvent - event to be scheduled in future (event data will be copied)
854         * @param delay - amount of microseconds in future (from now) when event shall be processed
855         * @returns unique event ID of scheduled new event, or NULL on error
856       */       */
857      int AbstractEngineChannel::ScheduleEvent(const Event* pEvent, int delay) { //TODO: delay not implemented yet      event_id_t AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int delay) {
858          // 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  
859          RTList<Event>::Iterator itEvent = pEvents->allocAppend();          RTList<Event>::Iterator itEvent = pEvents->allocAppend();
860          if (itEvent) *itEvent = *pEvent; // copy event          if (!itEvent) {
861                dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n"));
862                return 0;
863            }
864            RTList<ScheduledEvent>::Iterator itNode = delayedEvents.schedulerNodes.allocAppend();
865            if (!itNode) { // scheduler node pool empty ...
866                dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): ScheduledEvent pool empty!\n"));
867                pEvents->free(itEvent);
868                return 0;
869            }
870            // copy passed event
871            *itEvent = *pEvent;
872            // move copied event to list of delayed events
873            itEvent = itEvent.moveToEndOf(delayedEvents.pList);
874            // connect scheduler node with the copied event
875            itNode->itEvent = itEvent;
876            // add entry to time sorted scheduler queue for copied event
877            pEngine->pEventGenerator->scheduleAheadMicroSec(
878                delayedEvents.queue, *itNode, itEvent->FragmentPos(), delay
879            );
880            //dmsg(5,("ScheduledEvent queue size: %d\n", delayedEvents.queue.size()));
881          return pEvents->getID(itEvent);          return pEvents->getID(itEvent);
882      }      }
883    
# Line 826  namespace LinuxSampler { Line 886  namespace LinuxSampler {
886       * reflected by given event ID. The event will be freed immediately to its       * reflected by given event ID. The event will be freed immediately to its
887       * pool and cannot be dereferenced by its old ID anymore. Even if its       * pool and cannot be dereferenced by its old ID anymore. Even if its
888       * allocated back from the Pool later on, it will have a different ID.       * allocated back from the Pool later on, it will have a different ID.
889         *
890         * @param id - unique ID of event to be dropped
891       */       */
892      void AbstractEngineChannel::IgnoreEvent(int id) {      void AbstractEngineChannel::IgnoreEvent(event_id_t id) {
893          RTList<Event>::Iterator it = pEvents->fromID(id);          RTList<Event>::Iterator it = pEvents->fromID(id);
894          if (it) pEvents->free(it);          if (it) pEvents->free(it);
895      }      }
896    
897        /** @brief Drop the requested event.
898         *
899         * Called by real-time instrument script functions to ignore the event
900         * reflected by the given event @a id. This method detects whether the
901         * passed ID is actually a @c Note ID or a regular @c Event ID and act
902         * accordingly.
903         *
904         * @param id - event id (from script scope)
905         * @see ScriptID
906         */
907        void AbstractEngineChannel::IgnoreEventByScriptID(const ScriptID& id) {
908            switch (id.type()) {
909                case ScriptID::EVENT:
910                    IgnoreEvent( id.eventID() );
911                    break;
912                case ScriptID::NOTE:
913                    IgnoreNote( id.noteID() );
914                    break;
915            }
916        }
917    
918        /** @brief Order resuming of script execution instance "now".
919         *
920         * Called by real-time instrument script function stop_wait() to resume a
921         * script callback currently being suspended (i.e. due to a wait() script
922         * function call).
923         *
924         * @param itCallback - suspended script callback to be resumed
925         * @param now - current scheduler time to be "now"
926         * @param forever - whether this particulare script callback should ignore
927         *                  all subsequent wait*() script function calls
928         */
929        void AbstractEngineChannel::ScheduleResumeOfScriptCallback(RTList<ScriptEvent>::Iterator& itCallback, sched_time_t now, bool forever) {
930            // ignore if invalid iterator was passed
931            if (!itCallback) return;
932    
933            ScriptEvent* pCallback = &*itCallback;
934    
935            // mark this callback to ignore all subsequent built-in wait*() script function calls
936            if (forever) pCallback->ignoreAllWaitCalls = true;
937    
938            // ignore if callback is not in the scheduler queue
939            if (pCallback->currentSchedulerQueue() != &pScript->suspendedEvents) return;
940    
941            // ignore if callback is already scheduled to be resumed "now"
942            if (pCallback->scheduleTime <= now) return;
943    
944            // take it out from the scheduler queue and re-insert callback
945            // to schedule the script callback for resuming execution "now"
946            pScript->suspendedEvents.erase(*pCallback);
947            pCallback->scheduleTime = now + 1;
948            pScript->suspendedEvents.insert(*pCallback);
949        }
950    
951      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
952          if (pEngine) pEngine->DisableAndLock();          if (pEngine) pEngine->DisableAndLock();
953          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);

Legend:
Removed from v.2618  
changed lines
  Added in v.3018

  ViewVC Help
Powered by ViewVC