/[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 2500 by schoenebeck, Fri Jan 10 12:20:05 2014 UTC revision 2600 by schoenebeck, Sat Jun 7 00:16:03 2014 UTC
# Line 46  namespace LinuxSampler { Line 46  namespace LinuxSampler {
46          ResetControllers();          ResetControllers();
47          PortamentoMode = false;          PortamentoMode = false;
48          PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;          PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;
49            pScriptEvents = NULL;
50      }      }
51    
52      AbstractEngineChannel::~AbstractEngineChannel() {      AbstractEngineChannel::~AbstractEngineChannel() {
53            unloadCurrentInstrumentScript();
54            if (pScriptEvents) delete pScriptEvents;
55          delete pEventQueue;          delete pEventQueue;
56          DeleteGroupEventLists();          DeleteGroupEventLists();
57          RemoveAllFxSends();          RemoveAllFxSends();
# Line 142  namespace LinuxSampler { Line 145  namespace LinuxSampler {
145      }      }
146    
147      /**      /**
148         * Loads the real-time instrument script given by @a text on this engine
149         * channel. A resource manager is used to allocate and share equivalent
150         * scripts on multiple engine channels.
151         *
152         * @param text - source code of script
153         */
154        void AbstractEngineChannel::loadInstrumentScript(const String& text) {
155            dmsg(1,("Loading real-time instrument script ... "));
156    
157            // hand back old script reference and VM execution contexts
158            // (if not done already)
159            unloadCurrentInstrumentScript();
160    
161            // get new script reference
162            script.parserContext = pEngine->scripts.Borrow(text, this);
163            if (!script.parserContext->errors().empty()) {
164                std::vector<ParserIssue> errors = script.parserContext->errors();
165                std::cerr << "[ScriptVM] Could not load instrument script, there were "
166                          << errors.size() << " parser errors:\n";
167                for (int i = 0; i < errors.size(); ++i)
168                    errors[i].dump();
169                return; // stop here if there were any parser errors
170            }
171    
172            script.handlerInit = script.parserContext->eventHandlerByName("init");
173            script.handlerNote = script.parserContext->eventHandlerByName("note");
174            script.handlerRelease = script.parserContext->eventHandlerByName("release");
175            script.handlerController = script.parserContext->eventHandlerByName("controller");
176            script.bHasValidScript =
177                script.handlerInit || script.handlerNote || script.handlerRelease ||
178                script.handlerController;
179    
180            // amount of script handlers each script event has to execute
181            int handlerExecCount = 0;
182            if (script.handlerInit) handlerExecCount++; // "init" handler is always executed before the actual event handler
183            if (script.handlerNote || script.handlerRelease || script.handlerController) // only one of these are executed after "init" handler
184                handlerExecCount++;
185    
186            // create script event pool (if it doesn't exist already)
187            if (!pScriptEvents)
188                pScriptEvents = new Pool<ScriptEvent>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
189    
190            // create new VM execution contexts for new script
191            while (!pScriptEvents->poolIsEmpty()) {
192                RTList<ScriptEvent>::Iterator it = pScriptEvents->allocAppend();
193                it->execCtx = pEngine->pScriptVM->createExecContext(
194                    script.parserContext
195                );
196                it->handlers = new VMEventHandler*[handlerExecCount+1];
197            }
198            pScriptEvents->clear();
199    
200            dmsg(1,("Done\n"));
201        }
202    
203        /**
204         * Unloads the currently used real-time instrument script on this sampler
205         * channel. A resource manager is used to share equivalent scripts among
206         * multiple sampler channels, and to deallocate the parsed script once not
207         * used on any engine channel anymore.
208         */
209        void AbstractEngineChannel::unloadCurrentInstrumentScript() {
210            if (script.parserContext)
211                dmsg(1,("Unloading current instrument script."));
212    
213            // free allocated VM execution contexts
214            if (pScriptEvents) {
215                pScriptEvents->clear();
216                while (!pScriptEvents->poolIsEmpty()) {
217                    RTList<ScriptEvent>::Iterator it = pScriptEvents->allocAppend();
218                    if (it->execCtx) {
219                        // free VM execution context object
220                        delete it->execCtx;
221                        it->execCtx = NULL;
222                        // free C array of handler pointers
223                        delete [] it->handlers;
224                    }
225                }
226                pScriptEvents->clear();
227            }
228            // hand back VM representation of script
229            if (script.parserContext) {
230                pEngine->scripts.HandBack(script.parserContext, this);
231                script.parserContext = NULL;
232                script.handlerInit = NULL;
233                script.handlerNote = NULL;
234                script.handlerRelease = NULL;
235                script.handlerController = NULL;
236            }
237            script.bHasValidScript = false;
238        }
239    
240        /**
241       * Implementation of virtual method from abstract EngineChannel interface.       * Implementation of virtual method from abstract EngineChannel interface.
242       * This method will periodically be polled (e.g. by the LSCP server) to       * This method will periodically be polled (e.g. by the LSCP server) to
243       * check if some engine channel parameter has changed since the last       * check if some engine channel parameter has changed since the last
# Line 375  namespace LinuxSampler { Line 471  namespace LinuxSampler {
471              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
472              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
473              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
474                event.Format              = {}; // init format specific stuff with zeroes
475              event.pEngineChannel      = this;              event.pEngineChannel      = this;
476              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
477              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 416  namespace LinuxSampler { Line 513  namespace LinuxSampler {
513              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
514              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
515              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
516                event.Format              = {}; // init format specific stuff with zeroes
517              event.pEngineChannel      = this;              event.pEngineChannel      = this;
518              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
519              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 452  namespace LinuxSampler { Line 550  namespace LinuxSampler {
550              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
551              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
552              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
553                event.Format              = {}; // init format specific stuff with zeroes
554              event.pEngineChannel      = this;              event.pEngineChannel      = this;
555              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
556              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 493  namespace LinuxSampler { Line 592  namespace LinuxSampler {
592              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
593              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
594              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
595                event.Format              = {}; // init format specific stuff with zeroes
596              event.pEngineChannel      = this;              event.pEngineChannel      = this;
597              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
598              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 527  namespace LinuxSampler { Line 627  namespace LinuxSampler {
627              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
628              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
629              event.Param.Pitch.Channel = MidiChannel;              event.Param.Pitch.Channel = MidiChannel;
630                event.Format            = {}; // init format specific stuff with zeroes
631              event.pEngineChannel    = this;              event.pEngineChannel    = this;
632              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
633              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 556  namespace LinuxSampler { Line 657  namespace LinuxSampler {
657              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
658              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
659              event.Param.Pitch.Channel = MidiChannel;              event.Param.Pitch.Channel = MidiChannel;
660                event.Format            = {}; // init format specific stuff with zeroes
661              event.pEngineChannel    = this;              event.pEngineChannel    = this;
662              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
663              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 582  namespace LinuxSampler { Line 684  namespace LinuxSampler {
684              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
685              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
686              event.Param.CC.Channel    = MidiChannel;              event.Param.CC.Channel    = MidiChannel;
687                event.Format              = {}; // init format specific stuff with zeroes
688              event.pEngineChannel      = this;              event.pEngineChannel      = this;
689              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
690              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 613  namespace LinuxSampler { Line 716  namespace LinuxSampler {
716              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
717              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
718              event.Param.CC.Channel    = MidiChannel;              event.Param.CC.Channel    = MidiChannel;
719                event.Format              = {}; // init format specific stuff with zeroes
720              event.pEngineChannel      = this;              event.pEngineChannel      = this;
721              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
722              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
723          }          }
724      }      }
725    
726        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel) {
727            if (pEngine) {
728                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
729                LockGuard g;
730                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
731    
732                Event event = pEngine->pEventGenerator->CreateEvent();
733                event.Type                          = Event::type_channel_pressure;
734                event.Param.ChannelPressure.Value   = Value;
735                event.Param.ChannelPressure.Channel = MidiChannel;
736                event.Format                        = {}; // init format specific stuff with zeroes
737                event.pEngineChannel                = this;
738                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
739                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
740            }
741        }
742    
743        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
744            if (pEngine) {
745                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
746                LockGuard g;
747                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
748    
749                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
750                event.Type                          = Event::type_channel_pressure;
751                event.Param.ChannelPressure.Value   = Value;
752                event.Param.ChannelPressure.Channel = MidiChannel;
753                event.Format                        = {}; // init format specific stuff with zeroes
754                event.pEngineChannel                = this;
755                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
756                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
757            }
758        }
759    
760        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel) {
761            if (pEngine) {
762                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
763                LockGuard g;
764                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
765    
766                Event event = pEngine->pEventGenerator->CreateEvent();
767                event.Type                       = Event::type_note_pressure;
768                event.Param.NotePressure.Key     = Key;
769                event.Param.NotePressure.Value   = Value;
770                event.Param.NotePressure.Channel = MidiChannel;
771                event.Format                     = {}; // init format specific stuff with zeroes
772                event.pEngineChannel             = this;
773                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
774                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
775            }
776        }
777    
778        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
779            if (pEngine) {
780                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
781                LockGuard g;
782                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
783    
784                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
785                event.Type                       = Event::type_note_pressure;
786                event.Param.NotePressure.Key     = Key;
787                event.Param.NotePressure.Value   = Value;
788                event.Param.NotePressure.Channel = MidiChannel;
789                event.Format                     = {}; // init format specific stuff with zeroes
790                event.pEngineChannel             = this;
791                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
792                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
793            }
794        }
795    
796      /**      /**
797       * 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
798       * 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 663  namespace LinuxSampler { Line 837  namespace LinuxSampler {
837                              event.Param.Note.Channel  = channel;                              event.Param.Note.Channel  = channel;
838                              break;                              break;
839                          case VirtualMidiDevice::EVENT_TYPE_CC:                          case VirtualMidiDevice::EVENT_TYPE_CC:
840                              event.Type = Event::type_control_change;                              switch (devEvent.Arg1) {
841                              event.Param.CC.Controller = devEvent.Arg1;                                  case 0: // bank select MSB ...
842                              event.Param.CC.Value      = devEvent.Arg2;                                      SetMidiBankMsb(devEvent.Arg2);
843                              event.Param.CC.Channel    = channel;                                      continue; // don't push this event into FIFO
844                                    case 32: // bank select LSB ...
845                                        SetMidiBankLsb(devEvent.Arg2);
846                                        continue; // don't push this event into FIFO
847                                    default: // regular MIDI CC ...
848                                        event.Type = Event::type_control_change;
849                                        event.Param.CC.Controller = devEvent.Arg1;
850                                        event.Param.CC.Value      = devEvent.Arg2;
851                                        event.Param.CC.Channel    = channel;
852                                }
853                              break;                              break;
854                            case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
855                                event.Type = Event::type_pitchbend;
856                                event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
857                                event.Param.Pitch.Channel = channel;
858                                break;
859                            case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
860                                SendProgramChange(devEvent.Arg1);
861                                continue; // don't push this event into FIFO
862                          default:                          default:
863                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
864                                        << devEvent.Type << "). This is a bug!";                                        << devEvent.Type << "). This is a bug!";
# Line 709  namespace LinuxSampler { Line 900  namespace LinuxSampler {
900          eventQueueReader.free(); // free all copied events from input queue          eventQueueReader.free(); // free all copied events from input queue
901      }      }
902    
903        /**
904         * Called by real-time instrument script functions to schedule a new event
905         * somewhere in future.
906         *
907         * @returns unique event ID of scheduled new event
908         */
909        int AbstractEngineChannel::ScheduleEvent(const Event* pEvent, int delay) { //TODO: delay not implemented yet
910            // since delay is not implemented yet, we simply add the new event
911            // to the event list of the current audio fragmet cycle for now
912            RTList<Event>::Iterator itEvent = pEvents->allocAppend();
913            if (itEvent) *itEvent = *pEvent; // copy event
914            return pEvents->getID(itEvent);
915        }
916    
917        /**
918         * Called by real-time instrument script functions to ignore the event
919         * reflected by given event ID. The event will be freed immediately to its
920         * pool and cannot be dereferenced by its old ID anymore. Even if its
921         * allocated back from the Pool later on, it will have a different ID.
922         */
923        void AbstractEngineChannel::IgnoreEvent(int id) {
924            RTList<Event>::Iterator it = pEvents->fromID(id);
925            if (it) pEvents->free(it);
926        }
927    
928      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
929          if (pEngine) pEngine->DisableAndLock();          if (pEngine) pEngine->DisableAndLock();
930          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);

Legend:
Removed from v.2500  
changed lines
  Added in v.2600

  ViewVC Help
Powered by ViewVC