/[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 2521 by schoenebeck, Wed Feb 19 19:02:43 2014 UTC revision 2871 by schoenebeck, Sun Apr 10 18:22:23 2016 UTC
# Line 5  Line 5 
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8   *   Copyright (C) 2013-2014 Christian Schoenebeck and Andreas Persson     *   *   Copyright (C) 2012-2016 Christian Schoenebeck and Andreas Persson     *
9   *                                                                         *   *                                                                         *
10   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
11   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 35  namespace LinuxSampler { Line 35  namespace LinuxSampler {
35      {      {
36          pEngine      = NULL;          pEngine      = NULL;
37          pEvents      = NULL; // we allocate when we retrieve the right Engine object          pEvents      = NULL; // we allocate when we retrieve the right Engine object
38            delayedEvents.pList = NULL;
39          pEventQueue  = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue  = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
40          InstrumentIdx  = -1;          InstrumentIdx  = -1;
41          InstrumentStat = -1;          InstrumentStat = -1;
# Line 46  namespace LinuxSampler { Line 47  namespace LinuxSampler {
47          ResetControllers();          ResetControllers();
48          PortamentoMode = false;          PortamentoMode = false;
49          PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;          PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;
50            pScript = NULL;
51      }      }
52    
53      AbstractEngineChannel::~AbstractEngineChannel() {      AbstractEngineChannel::~AbstractEngineChannel() {
# Line 100  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 128  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 375  namespace LinuxSampler { Line 383  namespace LinuxSampler {
383              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
384              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
385              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
386                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
387              event.pEngineChannel      = this;              event.pEngineChannel      = this;
388              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
389              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 416  namespace LinuxSampler { Line 425  namespace LinuxSampler {
425              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
426              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
427              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
428                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
429              event.pEngineChannel      = this;              event.pEngineChannel      = this;
430              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
431              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 452  namespace LinuxSampler { Line 462  namespace LinuxSampler {
462              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
463              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
464              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
465                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
466              event.pEngineChannel      = this;              event.pEngineChannel      = this;
467              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
468              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 493  namespace LinuxSampler { Line 504  namespace LinuxSampler {
504              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
505              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
506              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
507                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
508              event.pEngineChannel      = this;              event.pEngineChannel      = this;
509              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
510              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 527  namespace LinuxSampler { Line 539  namespace LinuxSampler {
539              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
540              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
541              event.Param.Pitch.Channel = MidiChannel;              event.Param.Pitch.Channel = MidiChannel;
542                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
543              event.pEngineChannel    = this;              event.pEngineChannel    = this;
544              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
545              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 556  namespace LinuxSampler { Line 569  namespace LinuxSampler {
569              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
570              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
571              event.Param.Pitch.Channel = MidiChannel;              event.Param.Pitch.Channel = MidiChannel;
572                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
573              event.pEngineChannel    = this;              event.pEngineChannel    = this;
574              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
575              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 582  namespace LinuxSampler { Line 596  namespace LinuxSampler {
596              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
597              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
598              event.Param.CC.Channel    = MidiChannel;              event.Param.CC.Channel    = MidiChannel;
599                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
600              event.pEngineChannel      = this;              event.pEngineChannel      = this;
601              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
602              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 613  namespace LinuxSampler { Line 628  namespace LinuxSampler {
628              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
629              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
630              event.Param.CC.Channel    = MidiChannel;              event.Param.CC.Channel    = MidiChannel;
631                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
632              event.pEngineChannel      = this;              event.pEngineChannel      = this;
633              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
634              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
635          }          }
636      }      }
637    
638        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel) {
639            if (pEngine) {
640                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
641                LockGuard g;
642                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
643    
644                Event event = pEngine->pEventGenerator->CreateEvent();
645                event.Type                          = Event::type_channel_pressure;
646                event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
647                event.Param.ChannelPressure.Value   = Value;
648                event.Param.ChannelPressure.Channel = MidiChannel;
649                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
650                event.pEngineChannel                = this;
651                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
652                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
653            }
654        }
655    
656        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
657            if (pEngine) {
658                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
659                LockGuard g;
660                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
661    
662                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
663                event.Type                          = Event::type_channel_pressure;
664                event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
665                event.Param.ChannelPressure.Value   = Value;
666                event.Param.ChannelPressure.Channel = MidiChannel;
667                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
668                event.pEngineChannel                = this;
669                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
670                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
671            }
672        }
673    
674        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel) {
675            if (pEngine) {
676                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
677                LockGuard g;
678                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
679    
680                Event event = pEngine->pEventGenerator->CreateEvent();
681                event.Type                       = Event::type_note_pressure;
682                event.Param.NotePressure.Key     = Key;
683                event.Param.NotePressure.Value   = Value;
684                event.Param.NotePressure.Channel = MidiChannel;
685                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
686                event.pEngineChannel             = this;
687                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
688                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
689            }
690        }
691    
692        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
693            if (pEngine) {
694                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
695                LockGuard g;
696                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
697    
698                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
699                event.Type                       = Event::type_note_pressure;
700                event.Param.NotePressure.Key     = Key;
701                event.Param.NotePressure.Value   = Value;
702                event.Param.NotePressure.Channel = MidiChannel;
703                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
704                event.pEngineChannel             = this;
705                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
706                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
707            }
708        }
709    
710      /**      /**
711       * 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
712       * 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 690  namespace LinuxSampler { Line 778  namespace LinuxSampler {
778                                        << devEvent.Type << "). This is a bug!";                                        << devEvent.Type << "). This is a bug!";
779                              continue;                              continue;
780                      }                      }
781                        memset(&event.Format, 0, sizeof(event.Format)); // init format specific stuff with zeroes
782                      event.pEngineChannel = this;                      event.pEngineChannel = this;
783                      // copy event to internal event list                      // copy event to internal event list
784                      if (pEvents->poolIsEmpty()) {                      if (pEvents->poolIsEmpty()) {
# Line 726  namespace LinuxSampler { Line 815  namespace LinuxSampler {
815          eventQueueReader.free(); // free all copied events from input queue          eventQueueReader.free(); // free all copied events from input queue
816      }      }
817    
818        /**
819         * Called by real-time instrument script functions to schedule a new event
820         * @a delay microseconds in future.
821         *
822         * @b IMPORTANT: for the supplied @a delay to be scheduled correctly, the
823         * passed @a pEvent must be assigned a valid fragment time within the
824         * current audio fragment boundaries. That fragment time will be used by
825         * this method as basis for interpreting what "now" acutally is, and thus
826         * it will be used as basis for calculating the precise scheduling time
827         * for @a delay. The easiest way to achieve this is by copying a recent
828         * event which happened within the current audio fragment cycle: i.e. the
829         * original event which caused calling this method here.
830         *
831         * @param pEvent - event to be scheduled in future (event data will be copied)
832         * @param delay - amount of microseconds in future (from now) when event shall be processed
833         * @returns unique event ID of scheduled new event, or a negative number on error
834         */
835        int AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int delay) {
836            dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%d)\n", pEvent->Type, delay));
837            RTList<Event>::Iterator itEvent = pEvents->allocAppend();
838            if (!itEvent) {
839                dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n"));
840                return -1;
841            }
842            RTList<ScheduledEvent>::Iterator itNode = delayedEvents.schedulerNodes.allocAppend();
843            if (!itNode) { // scheduler node pool empty ...
844                dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): ScheduledEvent pool empty!\n"));
845                pEvents->free(itEvent);
846                return -1;
847            }
848            // copy passed event
849            *itEvent = *pEvent;
850            // move copied event to list of delayed events
851            itEvent = itEvent.moveToEndOf(delayedEvents.pList);
852            // connect scheduler node with the copied event
853            itNode->itEvent = itEvent;
854            // add entry to time sorted scheduler queue for copied event
855            pEngine->pEventGenerator->scheduleAheadMicroSec(
856                delayedEvents.queue, *itNode, itEvent->FragmentPos(), delay
857            );
858            //dmsg(5,("ScheduledEvent queue size: %d\n", delayedEvents.queue.size()));
859            return pEvents->getID(itEvent);
860        }
861    
862        /**
863         * Called by real-time instrument script functions to ignore the event
864         * reflected by given event ID. The event will be freed immediately to its
865         * pool and cannot be dereferenced by its old ID anymore. Even if its
866         * allocated back from the Pool later on, it will have a different ID.
867         */
868        void AbstractEngineChannel::IgnoreEvent(int id) {
869            RTList<Event>::Iterator it = pEvents->fromID(id);
870            if (it) pEvents->free(it);
871        }
872    
873      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
874          if (pEngine) pEngine->DisableAndLock();          if (pEngine) pEngine->DisableAndLock();
875          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);

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

  ViewVC Help
Powered by ViewVC