/[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 2879 by schoenebeck, Tue Apr 19 14:07:53 2016 UTC revision 3557 by schoenebeck, Sun Aug 18 00:06:04 2019 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) 2012-2016 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 728  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 739  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                              // apply transpose setting to (note on/off) event
763                              if (!applyTranspose(&event))                              if (!applyTranspose(&*itEvent)) {
764                                  continue; // note value is out of range, so drop this event                                  // 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                              // assign a new note to this note-on event
769                              if (!pEngine->LaunchNewNote(this, &event))                              if (!pEngine->LaunchNewNote(this, itEvent)) {
770                                  continue; // failed launching new note, so drop this event                                  // 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(&event))                              if (!applyTranspose(&*itEvent)) {
781                                  continue; // note value is out of range, so drop this event                                  // 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 818  namespace LinuxSampler { Line 847  namespace LinuxSampler {
847                  dmsg(1,("Event pool emtpy!\n"));                  dmsg(1,("Event pool emtpy!\n"));
848                  break;                  break;
849              }              }
850    
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              // apply transpose setting to (note on/off) event
858              if (!applyTranspose(pEvent))              if (!applyTranspose(&*itEvent)) {
859                  continue; // it's a note event which has a note value out of range, so drop this event                  // 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)              // assign a new note to this event (if its a note-on event)
864              if (pEvent->Type == Event::type_note_on)              if (itEvent->Type == Event::type_note_on) {
865                  if (!pEngine->LaunchNewNote(this, pEvent))                  if (!pEngine->LaunchNewNote(this, itEvent)) {
866                      continue; // failed launching new note, so drop this event                      // failed launching new note, so drop this event
867              // copy event to internal event list                      pEvents->free(itEvent);
868              *pEvents->allocAppend() = *pEvent;                      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      }      }
# Line 848  namespace LinuxSampler { Line 890  namespace LinuxSampler {
890       * @param delay - amount of microseconds in future (from now) when event shall be processed       * @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       * @returns unique event ID of scheduled new event, or NULL on error
892       */       */
893      event_id_t AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int delay) {      event_id_t AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int64_t delay) {
894          dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%d)\n", pEvent->Type, delay));          dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%lld)\n", pEvent->Type, delay));
895          RTList<Event>::Iterator itEvent = pEvents->allocAppend();          RTList<Event>::Iterator itEvent = pEvents->allocAppend();
896          if (!itEvent) {          if (!itEvent) {
897              dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n"));              dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n"));
# Line 888  namespace LinuxSampler { Line 930  namespace LinuxSampler {
930          if (it) pEvents->free(it);          if (it) pEvents->free(it);
931      }      }
932    
     /**  
      * Called by real-time instrument script functions to ignore the note  
      * reflected by given note ID. The note's event will be freed immediately  
      * to its event pool and this will prevent voices to be launched for the  
      * note.  
      *  
      * NOTE: preventing a note by calling this method works only if the note  
      * was launched within the current audio fragment cycle.  
      *  
      * @param id - unique ID of note to be dropped  
      */      
     void AbstractEngineChannel::IgnoreNote(note_id_t id) {  
         NoteBase* pNote = pEngine->NoteByID(id);  
         if (!pNote) return;  
         IgnoreEvent(pNote->eventID);  
     }  
   
933      /** @brief Drop the requested event.      /** @brief Drop the requested event.
934       *       *
935       * Called by real-time instrument script functions to ignore the event       * Called by real-time instrument script functions to ignore the event
# Line 926  namespace LinuxSampler { Line 951  namespace LinuxSampler {
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 953  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.2879  
changed lines
  Added in v.3557

  ViewVC Help
Powered by ViewVC