/[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 2611 by schoenebeck, Mon Jun 9 19:20:37 2014 UTC revision 3293 by schoenebeck, Tue Jun 27 22:19:19 2017 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-2017 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 50  namespace LinuxSampler { Line 51  namespace LinuxSampler {
51      }      }
52    
53      AbstractEngineChannel::~AbstractEngineChannel() {      AbstractEngineChannel::~AbstractEngineChannel() {
         if (pScript) pScript->reset(); // unloads script (in case one is loaded)  
54          delete pEventQueue;          delete pEventQueue;
55          DeleteGroupEventLists();          DeleteGroupEventLists();
56          RemoveAllFxSends();          RemoveAllFxSends();
# Line 102  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 130  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 377  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 419  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 456  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 498  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 533  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 563  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 590  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 622  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 640  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 658  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 676  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 694  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 720  namespace LinuxSampler { Line 728  namespace LinuxSampler {
728          {          {
729              const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();              const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
730              const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices              const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices
731              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);              const Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
732              VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device              VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
733              // as we're going to (carefully) write some status to the              // as we're going to (carefully) write some status to the
734              // synchronized struct, we cast away the const              // synchronized struct, we cast away the const
# Line 731  namespace LinuxSampler { Line 739  namespace LinuxSampler {
739                  VirtualMidiDevice* pDev = devices[i];                  VirtualMidiDevice* pDev = devices[i];
740                  // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)                  // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
741                  while (pDev->GetMidiEventFromDevice(devEvent)) {                  while (pDev->GetMidiEventFromDevice(devEvent)) {
742                        if (pEvents->poolIsEmpty()) {
743                            dmsg(1,("Event pool emtpy!\n"));
744                            goto exitVirtualDevicesLoop;
745                        }
746    
747                        // copy event to internal event list (this is already
748                        // required here, because the LaunchNewNote() call below
749                        // requires the event to be from the internal event pool for
750                        // being able to generate a valid event ID)
751                        RTList<Event>::Iterator itEvent = pEvents->allocAppend();
752                        *itEvent = event;
753    
754                        itEvent->pEngineChannel = this;
755    
756                      switch (devEvent.Type) {                      switch (devEvent.Type) {
757                          case VirtualMidiDevice::EVENT_TYPE_NOTEON:                          case VirtualMidiDevice::EVENT_TYPE_NOTEON:
758                              event.Type = Event::type_note_on;                              itEvent->Type = Event::type_note_on;
759                              event.Param.Note.Key      = devEvent.Arg1;                              itEvent->Param.Note.Key      = devEvent.Arg1;
760                              event.Param.Note.Velocity = devEvent.Arg2;                              itEvent->Param.Note.Velocity = devEvent.Arg2;
761                              event.Param.Note.Channel  = channel;                              itEvent->Param.Note.Channel  = channel;
762                                // apply transpose setting to (note on/off) event
763                                if (!applyTranspose(&*itEvent)) {
764                                    // note value is out of range, so drop this event
765                                    pEvents->free(itEvent);
766                                    continue;
767                                }
768                                // assign a new note to this note-on event
769                                if (!pEngine->LaunchNewNote(this, itEvent)) {
770                                    // failed launching new note, so drop this event
771                                    pEvents->free(itEvent);
772                                    continue;
773                                }
774                              break;                              break;
775                          case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:                          case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
776                              event.Type = Event::type_note_off;                              itEvent->Type = Event::type_note_off;
777                              event.Param.Note.Key      = devEvent.Arg1;                              itEvent->Param.Note.Key      = devEvent.Arg1;
778                              event.Param.Note.Velocity = devEvent.Arg2;                              itEvent->Param.Note.Velocity = devEvent.Arg2;
779                              event.Param.Note.Channel  = channel;                              itEvent->Param.Note.Channel  = channel;
780                                if (!applyTranspose(&*itEvent)) {
781                                    // note value is out of range, so drop this event
782                                    pEvents->free(itEvent);
783                                    continue;
784                                }
785                              break;                              break;
786                          case VirtualMidiDevice::EVENT_TYPE_CC:                          case VirtualMidiDevice::EVENT_TYPE_CC:
787                              switch (devEvent.Arg1) {                              switch (devEvent.Arg1) {
788                                  case 0: // bank select MSB ...                                  case 0: // bank select MSB ...
789                                      SetMidiBankMsb(devEvent.Arg2);                                      SetMidiBankMsb(devEvent.Arg2);
790                                      continue; // don't push this event into FIFO                                      // don't push this event into FIFO
791                                        pEvents->free(itEvent);
792                                        continue;
793                                  case 32: // bank select LSB ...                                  case 32: // bank select LSB ...
794                                      SetMidiBankLsb(devEvent.Arg2);                                      SetMidiBankLsb(devEvent.Arg2);
795                                      continue; // don't push this event into FIFO                                      // don't push this event into FIFO
796                                        pEvents->free(itEvent);
797                                        continue;
798                                  default: // regular MIDI CC ...                                  default: // regular MIDI CC ...
799                                      event.Type = Event::type_control_change;                                      itEvent->Type = Event::type_control_change;
800                                      event.Param.CC.Controller = devEvent.Arg1;                                      itEvent->Param.CC.Controller = devEvent.Arg1;
801                                      event.Param.CC.Value      = devEvent.Arg2;                                      itEvent->Param.CC.Value      = devEvent.Arg2;
802                                      event.Param.CC.Channel    = channel;                                      itEvent->Param.CC.Channel    = channel;
803                              }                              }
804                              break;                              break;
805                          case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:                          case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
806                              event.Type = Event::type_pitchbend;                              itEvent->Type = Event::type_pitchbend;
807                              event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;                              itEvent->Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
808                              event.Param.Pitch.Channel = channel;                              itEvent->Param.Pitch.Channel = channel;
809                              break;                              break;
810                          case VirtualMidiDevice::EVENT_TYPE_PROGRAM:                          case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
811                              SendProgramChange(devEvent.Arg1);                              SendProgramChange(devEvent.Arg1);
812                              continue; // don't push this event into FIFO                              // don't push this event into FIFO
813                                pEvents->free(itEvent);
814                                continue;
815                            case VirtualMidiDevice::EVENT_TYPE_CHPRESSURE:
816                                itEvent->Type = Event::type_channel_pressure;
817                                itEvent->Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH;
818                                itEvent->Param.ChannelPressure.Value   = devEvent.Arg2;
819                                itEvent->Param.ChannelPressure.Channel = channel;
820                                break;
821                          default:                          default:
822                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
823                                        << devEvent.Type << "). This is a bug!";                                        << devEvent.Type << "). This is a bug!";
824                                pEvents->free(itEvent); // drop event
825                              continue;                              continue;
826                      }                      }
                     event.pEngineChannel = this;  
                     // copy event to internal event list  
                     if (pEvents->poolIsEmpty()) {  
                         dmsg(1,("Event pool emtpy!\n"));  
                         goto exitVirtualDevicesLoop;  
                     }  
                     *pEvents->allocAppend() = event;  
827                  }                  }
828              }              }
829          }          }
# Line 798  namespace LinuxSampler { Line 843  namespace LinuxSampler {
843                  pEvent->ResetFragmentPos();                  pEvent->ResetFragmentPos();
844                  break;                  break;
845              }              }
             // copy event to internal event list  
846              if (pEvents->poolIsEmpty()) {              if (pEvents->poolIsEmpty()) {
847                  dmsg(1,("Event pool emtpy!\n"));                  dmsg(1,("Event pool emtpy!\n"));
848                  break;                  break;
849              }              }
850              *pEvents->allocAppend() = *pEvent;  
851                // copy event to internal event list
852                // (required already because LaunchNewNote() relies on it, see
853                // comment about it above)
854                RTList<Event>::Iterator itEvent = pEvents->allocAppend();
855                *itEvent = *pEvent;
856    
857                // apply transpose setting to (note on/off) event
858                if (!applyTranspose(&*itEvent)) {
859                    // it's a note event which has a note value out of range, so drop this event
860                    pEvents->free(itEvent);
861                    continue;
862                }
863                // assign a new note to this event (if its a note-on event)
864                if (itEvent->Type == Event::type_note_on) {
865                    if (!pEngine->LaunchNewNote(this, itEvent)) {
866                        // failed launching new note, so drop this event
867                        pEvents->free(itEvent);
868                        continue;
869                    }
870                }
871    
872          }          }
873          eventQueueReader.free(); // free all copied events from input queue          eventQueueReader.free(); // free all copied events from input queue
874      }      }
875    
876      /**      /**
877       * Called by real-time instrument script functions to schedule a new event       * Called by real-time instrument script functions to schedule a new event
878       * somewhere in future.       * @a delay microseconds in future.
879         *
880         * @b IMPORTANT: for the supplied @a delay to be scheduled correctly, the
881         * passed @a pEvent must be assigned a valid fragment time within the
882         * current audio fragment boundaries. That fragment time will be used by
883         * this method as basis for interpreting what "now" acutally is, and thus
884         * it will be used as basis for calculating the precise scheduling time
885         * for @a delay. The easiest way to achieve this is by copying a recent
886         * event which happened within the current audio fragment cycle: i.e. the
887         * original event which caused calling this method here.
888       *       *
889       * @returns unique event ID of scheduled new event       * @param pEvent - event to be scheduled in future (event data will be copied)
890         * @param delay - amount of microseconds in future (from now) when event shall be processed
891         * @returns unique event ID of scheduled new event, or NULL on error
892       */       */
893      int AbstractEngineChannel::ScheduleEvent(const Event* pEvent, int delay) { //TODO: delay not implemented yet      event_id_t AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int delay) {
894          // 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  
895          RTList<Event>::Iterator itEvent = pEvents->allocAppend();          RTList<Event>::Iterator itEvent = pEvents->allocAppend();
896          if (itEvent) *itEvent = *pEvent; // copy event          if (!itEvent) {
897                dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n"));
898                return 0;
899            }
900            RTList<ScheduledEvent>::Iterator itNode = delayedEvents.schedulerNodes.allocAppend();
901            if (!itNode) { // scheduler node pool empty ...
902                dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): ScheduledEvent pool empty!\n"));
903                pEvents->free(itEvent);
904                return 0;
905            }
906            // copy passed event
907            *itEvent = *pEvent;
908            // move copied event to list of delayed events
909            itEvent = itEvent.moveToEndOf(delayedEvents.pList);
910            // connect scheduler node with the copied event
911            itNode->itEvent = itEvent;
912            // add entry to time sorted scheduler queue for copied event
913            pEngine->pEventGenerator->scheduleAheadMicroSec(
914                delayedEvents.queue, *itNode, itEvent->FragmentPos(), delay
915            );
916            //dmsg(5,("ScheduledEvent queue size: %d\n", delayedEvents.queue.size()));
917          return pEvents->getID(itEvent);          return pEvents->getID(itEvent);
918      }      }
919    
# Line 827  namespace LinuxSampler { Line 922  namespace LinuxSampler {
922       * 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
923       * 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
924       * 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.
925         *
926         * @param id - unique ID of event to be dropped
927       */       */
928      void AbstractEngineChannel::IgnoreEvent(int id) {      void AbstractEngineChannel::IgnoreEvent(event_id_t id) {
929          RTList<Event>::Iterator it = pEvents->fromID(id);          RTList<Event>::Iterator it = pEvents->fromID(id);
930          if (it) pEvents->free(it);          if (it) pEvents->free(it);
931      }      }
932    
933        /** @brief Drop the requested event.
934         *
935         * Called by real-time instrument script functions to ignore the event
936         * reflected by the given event @a id. This method detects whether the
937         * passed ID is actually a @c Note ID or a regular @c Event ID and act
938         * accordingly.
939         *
940         * @param id - event id (from script scope)
941         * @see ScriptID
942         */
943        void AbstractEngineChannel::IgnoreEventByScriptID(const ScriptID& id) {
944            switch (id.type()) {
945                case ScriptID::EVENT:
946                    IgnoreEvent( id.eventID() );
947                    break;
948                case ScriptID::NOTE:
949                    IgnoreNote( id.noteID() );
950                    break;
951            }
952        }
953    
954        /** @brief Order resuming of script execution instance "now".
955         *
956         * Called by real-time instrument script function stop_wait() to resume a
957         * script callback currently being suspended (i.e. due to a wait() script
958         * function call).
959         *
960         * @param itCallback - suspended script callback to be resumed
961         * @param now - current scheduler time to be "now"
962         * @param forever - whether this particulare script callback should ignore
963         *                  all subsequent wait*() script function calls
964         */
965        void AbstractEngineChannel::ScheduleResumeOfScriptCallback(RTList<ScriptEvent>::Iterator& itCallback, sched_time_t now, bool forever) {
966            // ignore if invalid iterator was passed
967            if (!itCallback) return;
968    
969            ScriptEvent* pCallback = &*itCallback;
970    
971            // mark this callback to ignore all subsequent built-in wait*() script function calls
972            if (forever) pCallback->ignoreAllWaitCalls = true;
973    
974            // ignore if callback is not in the scheduler queue
975            if (pCallback->currentSchedulerQueue() != &pScript->suspendedEvents) return;
976    
977            // ignore if callback is already scheduled to be resumed "now"
978            if (pCallback->scheduleTime <= now) return;
979    
980            // take it out from the scheduler queue and re-insert callback
981            // to schedule the script callback for resuming execution "now"
982            pScript->suspendedEvents.erase(*pCallback);
983            pCallback->scheduleTime = now + 1;
984            pScript->suspendedEvents.insert(*pCallback);
985        }
986    
987        /** @brief Fork the given script execution instance.
988         *
989         * Called by real-time instrument script function fork() to create a new
990         * script execution instance (child) of the script execution instance
991         * (parent) that was calling fork(). This is essentially like creating a
992         * new thread for a script handler being executing. The entire execution
993         * state of parent is copied to the "forked" child.
994         *
995         * @param parent - original active script callback instance from which the
996         *                 new child shall be forked from
997         * @param bAutoAbort - whether the forked child shall automatically be
998         *                     terminated as soon as parent terminates
999         * @returns forked new child execution instance
1000         */
1001        RTList<ScriptEvent>::Iterator AbstractEngineChannel::forkScriptCallback(ScriptEvent* parent, bool bAutoAbort) {
1002            // check if the max. amount of child forks for this parent event handler
1003            // instance have not been exceeded yet
1004            if (parent->countChildHandlers() >= MAX_FORK_PER_SCRIPT_HANDLER)
1005                return RTList<ScriptEvent>::Iterator();
1006    
1007            // allocate a new script callback instance for child to be forked
1008            RTList<ScriptEvent>::Iterator itChild = pScript->pEvents->allocAppend();
1009            if (!itChild) return itChild;
1010    
1011            // copy entire script handler state from parent to forked child
1012            parent->forkTo(&*itChild, bAutoAbort);
1013    
1014            // stick the parent ID and child ID respectively to each other
1015            itChild->parentHandlerID = GetScriptCallbackID(parent);
1016            parent->addChildHandlerID( GetScriptCallbackID(&*itChild) );
1017    
1018            // insert newly created (forked) child event handler instance to the
1019            // scheduler queue for being executed soon
1020            pEngine->pEventGenerator->scheduleAheadMicroSec(
1021                pScript->suspendedEvents, // scheduler queue
1022                *itChild, // script event
1023                parent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1024                0 // "resume" new child script callback instance ASAP
1025            );
1026    
1027            return itChild;
1028        }
1029    
1030      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
1031          if (pEngine) pEngine->DisableAndLock();          if (pEngine) pEngine->DisableAndLock();
1032          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
# Line 860  namespace LinuxSampler { Line 1054  namespace LinuxSampler {
1054      }      }
1055    
1056      uint AbstractEngineChannel::GetFxSendCount() {      uint AbstractEngineChannel::GetFxSendCount() {
1057          return fxSends.size();          return (uint)fxSends.size();
1058      }      }
1059    
1060      void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {      void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {

Legend:
Removed from v.2611  
changed lines
  Added in v.3293

  ViewVC Help
Powered by ViewVC