/[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 2382 by persson, Sun Dec 2 16:30:42 2012 UTC revision 2606 by persson, Sun Jun 8 05:42:56 2014 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     *
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 41  namespace LinuxSampler { Line 42  namespace LinuxSampler {
42          pChannelRight = NULL;          pChannelRight = NULL;
43          AudioDeviceChannelLeft  = -1;          AudioDeviceChannelLeft  = -1;
44          AudioDeviceChannelRight = -1;          AudioDeviceChannelRight = -1;
         pMidiInputPort = NULL;  
45          midiChannel = midi_chan_all;          midiChannel = midi_chan_all;
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 192  namespace LinuxSampler { Line 288  namespace LinuxSampler {
288       * device from other threads than the lscp thread.       * device from other threads than the lscp thread.
289       */       */
290      AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {      AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {
291          EngineMutex.Lock();          LockGuard lock(EngineMutex);
292          AudioOutputDevice* res = GetAudioOutputDevice();          return GetAudioOutputDevice();
         EngineMutex.Unlock();  
         return res;  
293      }      }
294    
295      void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {      void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
# Line 230  namespace LinuxSampler { Line 324  namespace LinuxSampler {
324          }          }
325      }      }
326    
327        void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort) {
328            if (!pMidiPort) return;
329    
330            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
331    
332            // check if connection already exists
333            for (int i = 0; i < connections->size(); ++i)
334                if ((*connections)[i] == pMidiPort)
335                    return; // to avoid endless recursion
336    
337            connections->add(pMidiPort);
338    
339            // inform MIDI port about this new connection
340            pMidiPort->Connect(this, MidiChannel());
341        }
342    
343        void AbstractEngineChannel::Disconnect(MidiInputPort* pMidiPort) {
344            if (!pMidiPort) return;
345    
346            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
347    
348            for (int i = 0; i < connections->size(); ++i) {
349                if ((*connections)[i] == pMidiPort) {
350                    connections->remove(i);
351                    // inform MIDI port about this disconnection
352                    pMidiPort->Disconnect(this);
353                    return;
354                }
355            }
356        }
357    
358        void AbstractEngineChannel::DisconnectAllMidiInputPorts() {
359            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
360            ArrayList<MidiInputPort*> clonedList = *connections;
361            connections->clear();
362            for (int i = 0; i < clonedList.size(); ++i) clonedList[i]->Disconnect(this);
363        }
364    
365        uint AbstractEngineChannel::GetMidiInputPortCount() {
366            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
367            return connections->size();
368        }
369    
370        MidiInputPort* AbstractEngineChannel::GetMidiInputPort(uint index) {
371            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
372            return (index < connections->size()) ? (*connections)[index] : NULL;
373        }
374    
375        // deprecated (just for API backward compatibility) - may be removed in future
376      void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {      void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
377          if (!pMidiPort || pMidiPort == this->pMidiInputPort) return;          if (!pMidiPort) return;
378          DisconnectMidiInputPort();  
379          this->pMidiInputPort = pMidiPort;          Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
380          this->midiChannel    = MidiChannel;  
381            // check against endless recursion
382            if (connections->size() == 1 && (*connections)[0] == pMidiPort && this->midiChannel == MidiChannel)
383                return;
384            
385            if (!isValidMidiChan(MidiChannel))
386                throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
387    
388            this->midiChannel = MidiChannel;
389    
390            // disconnect all currently connected MIDI ports
391            ArrayList<MidiInputPort*> clonedList = *connections;
392            connections->clear();
393            for (int i = 0; i < clonedList.size(); ++i)
394                clonedList[i]->Disconnect(this);
395    
396            // connect the new port
397            connections->add(pMidiPort);
398          pMidiPort->Connect(this, MidiChannel);          pMidiPort->Connect(this, MidiChannel);
399      }      }
400    
401        // deprecated (just for API backward compatibility) - may be removed in future
402      void AbstractEngineChannel::DisconnectMidiInputPort() {      void AbstractEngineChannel::DisconnectMidiInputPort() {
403          MidiInputPort* pOldPort = this->pMidiInputPort;          DisconnectAllMidiInputPorts();
         this->pMidiInputPort = NULL;  
         if (pOldPort) pOldPort->Disconnect(this);  
404      }      }
405    
406        // deprecated (just for API backward compatibility) - may be removed in future
407      MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {      MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {
408          return pMidiInputPort;          return GetMidiInputPort(0);
409      }      }
410    
411      midi_chan_t AbstractEngineChannel::MidiChannel() {      midi_chan_t AbstractEngineChannel::MidiChannel() {
412          return midiChannel;          return midiChannel;
413      }      }
414    
415        void AbstractEngineChannel::SetMidiChannel(midi_chan_t MidiChannel) {
416            if (this->midiChannel == MidiChannel) return;
417            if (!isValidMidiChan(MidiChannel))
418                throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
419    
420            this->midiChannel = MidiChannel;
421            
422            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
423            ArrayList<MidiInputPort*> clonedList = *connections;
424    
425            DisconnectAllMidiInputPorts();
426    
427            for (int i = 0; i < clonedList.size(); ++i) Connect(clonedList[i]);
428        }
429    
430      void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {      void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {
431          // double buffer ... double work ...          // double buffer ... double work ...
432          {          {
# Line 287  namespace LinuxSampler { Line 462  namespace LinuxSampler {
462       */       */
463      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
464          if (pEngine) {          if (pEngine) {
465                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
466                LockGuard g;
467                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
468    
469              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
470              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific 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 324  namespace LinuxSampler { Line 504  namespace LinuxSampler {
504              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
505          }          }
506          else if (pEngine) {          else if (pEngine) {
507                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
508                LockGuard g;
509                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
510    
511              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
512              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific 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 356  namespace LinuxSampler { Line 541  namespace LinuxSampler {
541       */       */
542      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
543          if (pEngine) {          if (pEngine) {
544                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
545                LockGuard g;
546                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
547    
548              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
549              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific 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 393  namespace LinuxSampler { Line 583  namespace LinuxSampler {
583              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
584          }          }
585          else if (pEngine) {          else if (pEngine) {
586                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
587                LockGuard g;
588                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
589    
590              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
591              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific 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 424  namespace LinuxSampler { Line 619  namespace LinuxSampler {
619       */       */
620      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
621          if (pEngine) {          if (pEngine) {
622                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
623                LockGuard g;
624                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
625    
626              Event event             = pEngine->pEventGenerator->CreateEvent();              Event event             = pEngine->pEventGenerator->CreateEvent();
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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific 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 449  namespace LinuxSampler { Line 649  namespace LinuxSampler {
649              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
650          }          }
651          else if (pEngine) {          else if (pEngine) {
652                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
653                LockGuard g;
654                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
655    
656              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);
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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific 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 470  namespace LinuxSampler { Line 675  namespace LinuxSampler {
675       */       */
676      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {
677          if (pEngine) {          if (pEngine) {
678                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
679                LockGuard g;
680                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
681    
682              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
683              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific 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 497  namespace LinuxSampler { Line 707  namespace LinuxSampler {
707              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
708          }          }
709          else if (pEngine) {          else if (pEngine) {
710                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
711                LockGuard g;
712                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
713    
714              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
715              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific 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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific 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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific 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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific 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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific 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 552  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;
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;                              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 598  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.2382  
changed lines
  Added in v.2606

  ViewVC Help
Powered by ViewVC