/[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 3018 by schoenebeck, Wed Oct 19 17:22:28 2016 UTC revision 3988 by schoenebeck, Wed Aug 4 18:23:05 2021 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
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-2021 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Grigor Iliev                                  *
8   *   Copyright (C) 2012-2016 Christian Schoenebeck and Andreas Persson     *   *   Copyright (C) 2012-2017 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 276  namespace LinuxSampler { Line 276  namespace LinuxSampler {
276    
277      uint AbstractEngineChannel::GetMidiInputPortCount() {      uint AbstractEngineChannel::GetMidiInputPortCount() {
278          Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();          Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
279          return connections->size();          return (uint) connections->size();
280      }      }
281    
282      MidiInputPort* AbstractEngineChannel::GetMidiInputPort(uint index) {      MidiInputPort* AbstractEngineChannel::GetMidiInputPort(uint index) {
# Line 593  namespace LinuxSampler { Line 593  namespace LinuxSampler {
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!"));
596                // inform connected virtual MIDI devices if any ...
597                // (e.g. slider / knob in instrument editor(s))
598                ArrayList<VirtualMidiDevice*>& devices =
599                    const_cast<ArrayList<VirtualMidiDevice*>&>(
600                        virtualMidiDevicesReader_MidiThread.Lock()
601                    );
602                for (int i = 0; i < devices.size(); i++) {
603                    devices[i]->SendCCToDevice(Controller, Value);
604                }
605                virtualMidiDevicesReader_MidiThread.Unlock();
606          }          }
607      }      }
608    
# Line 624  namespace LinuxSampler { Line 634  namespace LinuxSampler {
634              event.pEngineChannel      = this;              event.pEngineChannel      = this;
635              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
636              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
637                // inform connected virtual MIDI devices if any ...
638                // (e.g. slider / knob in instrument editor(s))
639                ArrayList<VirtualMidiDevice*>& devices =
640                    const_cast<ArrayList<VirtualMidiDevice*>&>(
641                        virtualMidiDevicesReader_MidiThread.Lock()
642                    );
643                for (int i = 0; i < devices.size(); i++) {
644                    devices[i]->SendCCToDevice(Controller, Value);
645                }
646                virtualMidiDevicesReader_MidiThread.Unlock();
647          }          }
648      }      }
649    
# Line 728  namespace LinuxSampler { Line 748  namespace LinuxSampler {
748          {          {
749              const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();              const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
750              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
751              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);              const Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
752              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
753              // as we're going to (carefully) write some status to the              // as we're going to (carefully) write some status to the
754              // synchronized struct, we cast away the const              // synchronized struct, we cast away the const
# Line 739  namespace LinuxSampler { Line 759  namespace LinuxSampler {
759                  VirtualMidiDevice* pDev = devices[i];                  VirtualMidiDevice* pDev = devices[i];
760                  // 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 ;-)
761                  while (pDev->GetMidiEventFromDevice(devEvent)) {                  while (pDev->GetMidiEventFromDevice(devEvent)) {
762                        if (pEvents->poolIsEmpty()) {
763                            dmsg(1,("Event pool emtpy!\n"));
764                            goto exitVirtualDevicesLoop;
765                        }
766    
767                        // copy event to internal event list (this is already
768                        // required here, because the LaunchNewNote() call below
769                        // requires the event to be from the internal event pool for
770                        // being able to generate a valid event ID)
771                        RTList<Event>::Iterator itEvent = pEvents->allocAppend();
772                        *itEvent = event;
773    
774                        itEvent->pEngineChannel = this;
775    
776                      switch (devEvent.Type) {                      switch (devEvent.Type) {
777                          case VirtualMidiDevice::EVENT_TYPE_NOTEON:                          case VirtualMidiDevice::EVENT_TYPE_NOTEON:
778                              event.Type = Event::type_note_on;                              itEvent->Type = Event::type_note_on;
779                              event.Param.Note.Key      = devEvent.Arg1;                              itEvent->Param.Note.Key      = devEvent.Arg1;
780                              event.Param.Note.Velocity = devEvent.Arg2;                              itEvent->Param.Note.Velocity = devEvent.Arg2;
781                              event.Param.Note.Channel  = channel;                              itEvent->Param.Note.Channel  = channel;
782                              // apply transpose setting to (note on/off) event                              // apply transpose setting to (note on/off) event
783                              if (!applyTranspose(&event))                              if (!applyTranspose(&*itEvent)) {
784                                  continue; // note value is out of range, so drop this event                                  // note value is out of range, so drop this event
785                                    pEvents->free(itEvent);
786                                    continue;
787                                }
788                              // assign a new note to this note-on event                              // assign a new note to this note-on event
789                              if (!pEngine->LaunchNewNote(this, &event))                              if (!pEngine->LaunchNewNote(this, itEvent)) {
790                                  continue; // failed launching new note, so drop this event                                  // failed launching new note, so drop this event
791                                    pEvents->free(itEvent);
792                                    continue;
793                                }
794                              break;                              break;
795                          case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:                          case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
796                              event.Type = Event::type_note_off;                              itEvent->Type = Event::type_note_off;
797                              event.Param.Note.Key      = devEvent.Arg1;                              itEvent->Param.Note.Key      = devEvent.Arg1;
798                              event.Param.Note.Velocity = devEvent.Arg2;                              itEvent->Param.Note.Velocity = devEvent.Arg2;
799                              event.Param.Note.Channel  = channel;                              itEvent->Param.Note.Channel  = channel;
800                              if (!applyTranspose(&event))                              if (!applyTranspose(&*itEvent)) {
801                                  continue; // note value is out of range, so drop this event                                  // note value is out of range, so drop this event
802                                    pEvents->free(itEvent);
803                                    continue;
804                                }
805                              break;                              break;
806                          case VirtualMidiDevice::EVENT_TYPE_CC:                          case VirtualMidiDevice::EVENT_TYPE_CC:
807                              switch (devEvent.Arg1) {                              switch (devEvent.Arg1) {
808                                  case 0: // bank select MSB ...                                  case 0: // bank select MSB ...
809                                      SetMidiBankMsb(devEvent.Arg2);                                      SetMidiBankMsb(devEvent.Arg2);
810                                      continue; // don't push this event into FIFO                                      // don't push this event into FIFO
811                                        pEvents->free(itEvent);
812                                        continue;
813                                  case 32: // bank select LSB ...                                  case 32: // bank select LSB ...
814                                      SetMidiBankLsb(devEvent.Arg2);                                      SetMidiBankLsb(devEvent.Arg2);
815                                      continue; // don't push this event into FIFO                                      // don't push this event into FIFO
816                                        pEvents->free(itEvent);
817                                        continue;
818                                  default: // regular MIDI CC ...                                  default: // regular MIDI CC ...
819                                      event.Type = Event::type_control_change;                                      itEvent->Type = Event::type_control_change;
820                                      event.Param.CC.Controller = devEvent.Arg1;                                      itEvent->Param.CC.Controller = devEvent.Arg1;
821                                      event.Param.CC.Value      = devEvent.Arg2;                                      itEvent->Param.CC.Value      = devEvent.Arg2;
822                                      event.Param.CC.Channel    = channel;                                      itEvent->Param.CC.Channel    = channel;
823                              }                              }
824                              break;                              break;
825                          case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:                          case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
826                              event.Type = Event::type_pitchbend;                              itEvent->Type = Event::type_pitchbend;
827                              event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;                              itEvent->Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
828                              event.Param.Pitch.Channel = channel;                              itEvent->Param.Pitch.Channel = channel;
829                              break;                              break;
830                          case VirtualMidiDevice::EVENT_TYPE_PROGRAM:                          case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
831                              SendProgramChange(devEvent.Arg1);                              SendProgramChange(devEvent.Arg1);
832                              continue; // don't push this event into FIFO                              // don't push this event into FIFO
833                                pEvents->free(itEvent);
834                                continue;
835                          case VirtualMidiDevice::EVENT_TYPE_CHPRESSURE:                          case VirtualMidiDevice::EVENT_TYPE_CHPRESSURE:
836                              event.Type = Event::type_channel_pressure;                              itEvent->Type = Event::type_channel_pressure;
837                              event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH;                              itEvent->Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH;
838                              event.Param.ChannelPressure.Value   = devEvent.Arg2;                              itEvent->Param.ChannelPressure.Value   = devEvent.Arg2;
839                              event.Param.ChannelPressure.Channel = channel;                              itEvent->Param.ChannelPressure.Channel = channel;
840                              break;                              break;
841                          default:                          default:
842                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
843                                        << devEvent.Type << "). This is a bug!";                                        << devEvent.Type << "). This is a bug!";
844                                pEvents->free(itEvent); // drop event
845                              continue;                              continue;
846                      }                      }
                     event.pEngineChannel = this;  
                     // copy event to internal event list  
                     if (pEvents->poolIsEmpty()) {  
                         dmsg(1,("Event pool emtpy!\n"));  
                         goto exitVirtualDevicesLoop;  
                     }  
                     *pEvents->allocAppend() = event;  
847                  }                  }
848              }              }
849          }          }
# Line 824  namespace LinuxSampler { Line 867  namespace LinuxSampler {
867                  dmsg(1,("Event pool emtpy!\n"));                  dmsg(1,("Event pool emtpy!\n"));
868                  break;                  break;
869              }              }
870    
871                // copy event to internal event list
872                // (required already because LaunchNewNote() relies on it, see
873                // comment about it above)
874                RTList<Event>::Iterator itEvent = pEvents->allocAppend();
875                *itEvent = *pEvent;
876    
877              // apply transpose setting to (note on/off) event              // apply transpose setting to (note on/off) event
878              if (!applyTranspose(pEvent))              if (!applyTranspose(&*itEvent)) {
879                  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
880                    pEvents->free(itEvent);
881                    continue;
882                }
883              // 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)
884              if (pEvent->Type == Event::type_note_on)              if (itEvent->Type == Event::type_note_on) {
885                  if (!pEngine->LaunchNewNote(this, pEvent))                  if (!pEngine->LaunchNewNote(this, itEvent)) {
886                      continue; // failed launching new note, so drop this event                      // failed launching new note, so drop this event
887              // copy event to internal event list                      pEvents->free(itEvent);
888              *pEvents->allocAppend() = *pEvent;                      continue;
889                    }
890                }
891    
892          }          }
893          eventQueueReader.free(); // free all copied events from input queue          eventQueueReader.free(); // free all copied events from input queue
894      }      }
# Line 854  namespace LinuxSampler { Line 910  namespace LinuxSampler {
910       * @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
911       * @returns unique event ID of scheduled new event, or NULL on error       * @returns unique event ID of scheduled new event, or NULL on error
912       */       */
913      event_id_t AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int delay) {      event_id_t AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int64_t delay) {
914          dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%d)\n", pEvent->Type, delay));          dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%" PRId64 ")\n", pEvent->Type, delay));
915          RTList<Event>::Iterator itEvent = pEvents->allocAppend();          RTList<Event>::Iterator itEvent = pEvents->allocAppend();
916          if (!itEvent) {          if (!itEvent) {
917              dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n"));              dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n"));
# Line 948  namespace LinuxSampler { Line 1004  namespace LinuxSampler {
1004          pScript->suspendedEvents.insert(*pCallback);          pScript->suspendedEvents.insert(*pCallback);
1005      }      }
1006    
1007        /** @brief Fork the given script execution instance.
1008         *
1009         * Called by real-time instrument script function fork() to create a new
1010         * script execution instance (child) of the script execution instance
1011         * (parent) that was calling fork(). This is essentially like creating a
1012         * new thread for a script handler being executing. The entire execution
1013         * state of parent is copied to the "forked" child.
1014         *
1015         * @param parent - original active script callback instance from which the
1016         *                 new child shall be forked from
1017         * @param bAutoAbort - whether the forked child shall automatically be
1018         *                     terminated as soon as parent terminates
1019         * @returns forked new child execution instance
1020         */
1021        RTList<ScriptEvent>::Iterator AbstractEngineChannel::forkScriptCallback(ScriptEvent* parent, bool bAutoAbort) {
1022            // check if the max. amount of child forks for this parent event handler
1023            // instance have not been exceeded yet
1024            if (parent->countChildHandlers() >= MAX_FORK_PER_SCRIPT_HANDLER)
1025                return RTList<ScriptEvent>::Iterator();
1026    
1027            // allocate a new script callback instance for child to be forked
1028            RTList<ScriptEvent>::Iterator itChild = pScript->pEvents->allocAppend();
1029            if (!itChild) return itChild;
1030    
1031            // copy entire script handler state from parent to forked child
1032            parent->forkTo(&*itChild, bAutoAbort);
1033    
1034            // stick the parent ID and child ID respectively to each other
1035            itChild->parentHandlerID = GetScriptCallbackID(parent);
1036            parent->addChildHandlerID( GetScriptCallbackID(&*itChild) );
1037    
1038            // insert newly created (forked) child event handler instance to the
1039            // scheduler queue for being executed soon
1040            pEngine->pEventGenerator->scheduleAheadMicroSec(
1041                pScript->suspendedEvents, // scheduler queue
1042                *itChild, // script event
1043                parent->cause.FragmentPos(), // current time of script event (basis for its next execution)
1044                0 // "resume" new child script callback instance ASAP
1045            );
1046    
1047            return itChild;
1048        }
1049    
1050      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
1051          if (pEngine) pEngine->DisableAndLock();          if (pEngine) pEngine->DisableAndLock();
1052          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
# Line 975  namespace LinuxSampler { Line 1074  namespace LinuxSampler {
1074      }      }
1075    
1076      uint AbstractEngineChannel::GetFxSendCount() {      uint AbstractEngineChannel::GetFxSendCount() {
1077          return fxSends.size();          return (uint)fxSends.size();
1078      }      }
1079    
1080      void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {      void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {
# Line 1055  namespace LinuxSampler { Line 1154  namespace LinuxSampler {
1154       */       */
1155      void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {      void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {
1156          dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));          dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
1157          if (KeyGroup) {          // when editing key groups with an instrument editor while sound was
1158            // already loaded, ActiveKeyGroups may not have the KeyGroup in question
1159            // so check for that to prevent a crash while editing instruments
1160            if (KeyGroup && ActiveKeyGroups.count(KeyGroup)) {
1161              // send a release event to all active voices in the group              // send a release event to all active voices in the group
1162              RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);              RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
1163              *itEvent = *itNoteOnEvent;              *itEvent = *itNoteOnEvent;

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

  ViewVC Help
Powered by ViewVC