/[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 2594 by schoenebeck, Thu Jun 5 00:16:25 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.handlerController = script.parserContext->eventHandlerByName("controller");
175            script.bHasValidScript =
176                script.handlerInit || script.handlerNote || script.handlerController;
177    
178            // amount of script handlers each script event has to execute
179            int handlerExecCount = 0;
180            if (script.handlerInit) handlerExecCount++;
181            if (script.handlerNote || script.handlerController) handlerExecCount++;
182    
183            // create script event pool (if it doesn't exist already)
184            if (!pScriptEvents)
185                pScriptEvents = new Pool<ScriptEvent>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
186    
187            // create new VM execution contexts for new script
188            while (!pScriptEvents->poolIsEmpty()) {
189                RTList<ScriptEvent>::Iterator it = pScriptEvents->allocAppend();
190                it->execCtx = pEngine->pScriptVM->createExecContext(
191                    script.parserContext
192                );
193                it->handlers = new VMEventHandler*[handlerExecCount+1];
194            }
195            pScriptEvents->clear();
196    
197            dmsg(1,("Done\n"));
198        }
199    
200        /**
201         * Unloads the currently used real-time instrument script on this sampler
202         * channel. A resource manager is used to share equivalent scripts among
203         * multiple sampler channels, and to deallocate the parsed script once not
204         * used on any engine channel anymore.
205         */
206        void AbstractEngineChannel::unloadCurrentInstrumentScript() {
207            if (script.parserContext)
208                dmsg(1,("Unloading current instrument script."));
209    
210            // free allocated VM execution contexts
211            if (pScriptEvents) {
212                pScriptEvents->clear();
213                while (!pScriptEvents->poolIsEmpty()) {
214                    RTList<ScriptEvent>::Iterator it = pScriptEvents->allocAppend();
215                    if (it->execCtx) {
216                        // free VM execution context object
217                        delete it->execCtx;
218                        it->execCtx = NULL;
219                        // free C array of handler pointers
220                        delete [] it->handlers;
221                    }
222                }
223                pScriptEvents->clear();
224            }
225            // hand back VM representation of script
226            if (script.parserContext) {
227                pEngine->scripts.HandBack(script.parserContext, this);
228                script.parserContext = NULL;
229                script.handlerInit = NULL;
230                script.handlerNote = NULL;
231                script.handlerController = NULL;
232            }
233            script.bHasValidScript = false;
234        }
235    
236        /**
237       * Implementation of virtual method from abstract EngineChannel interface.       * Implementation of virtual method from abstract EngineChannel interface.
238       * 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
239       * 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 284  namespace LinuxSampler {
284       * device from other threads than the lscp thread.       * device from other threads than the lscp thread.
285       */       */
286      AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {      AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {
287          EngineMutex.Lock();          LockGuard lock(EngineMutex);
288          AudioOutputDevice* res = GetAudioOutputDevice();          return GetAudioOutputDevice();
         EngineMutex.Unlock();  
         return res;  
289      }      }
290    
291      void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {      void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
# Line 230  namespace LinuxSampler { Line 320  namespace LinuxSampler {
320          }          }
321      }      }
322    
323        void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort) {
324            if (!pMidiPort) return;
325    
326            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
327    
328            // check if connection already exists
329            for (int i = 0; i < connections->size(); ++i)
330                if ((*connections)[i] == pMidiPort)
331                    return; // to avoid endless recursion
332    
333            connections->add(pMidiPort);
334    
335            // inform MIDI port about this new connection
336            pMidiPort->Connect(this, MidiChannel());
337        }
338    
339        void AbstractEngineChannel::Disconnect(MidiInputPort* pMidiPort) {
340            if (!pMidiPort) return;
341    
342            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
343    
344            for (int i = 0; i < connections->size(); ++i) {
345                if ((*connections)[i] == pMidiPort) {
346                    connections->remove(i);
347                    // inform MIDI port about this disconnection
348                    pMidiPort->Disconnect(this);
349                    return;
350                }
351            }
352        }
353    
354        void AbstractEngineChannel::DisconnectAllMidiInputPorts() {
355            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
356            ArrayList<MidiInputPort*> clonedList = *connections;
357            connections->clear();
358            for (int i = 0; i < clonedList.size(); ++i) clonedList[i]->Disconnect(this);
359        }
360    
361        uint AbstractEngineChannel::GetMidiInputPortCount() {
362            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
363            return connections->size();
364        }
365    
366        MidiInputPort* AbstractEngineChannel::GetMidiInputPort(uint index) {
367            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
368            return (index < connections->size()) ? (*connections)[index] : NULL;
369        }
370    
371        // deprecated (just for API backward compatibility) - may be removed in future
372      void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {      void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
373          if (!pMidiPort || pMidiPort == this->pMidiInputPort) return;          if (!pMidiPort) return;
374          DisconnectMidiInputPort();  
375          this->pMidiInputPort = pMidiPort;          Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
376          this->midiChannel    = MidiChannel;  
377            // check against endless recursion
378            if (connections->size() == 1 && (*connections)[0] == pMidiPort && this->midiChannel == MidiChannel)
379                return;
380            
381            if (!isValidMidiChan(MidiChannel))
382                throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
383    
384            this->midiChannel = MidiChannel;
385    
386            // disconnect all currently connected MIDI ports
387            ArrayList<MidiInputPort*> clonedList = *connections;
388            connections->clear();
389            for (int i = 0; i < clonedList.size(); ++i)
390                clonedList[i]->Disconnect(this);
391    
392            // connect the new port
393            connections->add(pMidiPort);
394          pMidiPort->Connect(this, MidiChannel);          pMidiPort->Connect(this, MidiChannel);
395      }      }
396    
397        // deprecated (just for API backward compatibility) - may be removed in future
398      void AbstractEngineChannel::DisconnectMidiInputPort() {      void AbstractEngineChannel::DisconnectMidiInputPort() {
399          MidiInputPort* pOldPort = this->pMidiInputPort;          DisconnectAllMidiInputPorts();
         this->pMidiInputPort = NULL;  
         if (pOldPort) pOldPort->Disconnect(this);  
400      }      }
401    
402        // deprecated (just for API backward compatibility) - may be removed in future
403      MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {      MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {
404          return pMidiInputPort;          return GetMidiInputPort(0);
405      }      }
406    
407      midi_chan_t AbstractEngineChannel::MidiChannel() {      midi_chan_t AbstractEngineChannel::MidiChannel() {
408          return midiChannel;          return midiChannel;
409      }      }
410    
411        void AbstractEngineChannel::SetMidiChannel(midi_chan_t MidiChannel) {
412            if (this->midiChannel == MidiChannel) return;
413            if (!isValidMidiChan(MidiChannel))
414                throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
415    
416            this->midiChannel = MidiChannel;
417            
418            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
419            ArrayList<MidiInputPort*> clonedList = *connections;
420    
421            DisconnectAllMidiInputPorts();
422    
423            for (int i = 0; i < clonedList.size(); ++i) Connect(clonedList[i]);
424        }
425    
426      void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {      void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {
427          // double buffer ... double work ...          // double buffer ... double work ...
428          {          {
# Line 287  namespace LinuxSampler { Line 458  namespace LinuxSampler {
458       */       */
459      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
460          if (pEngine) {          if (pEngine) {
461                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
462                LockGuard g;
463                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
464    
465              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
466              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
467              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
# Line 324  namespace LinuxSampler { Line 499  namespace LinuxSampler {
499              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
500          }          }
501          else if (pEngine) {          else if (pEngine) {
502                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
503                LockGuard g;
504                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
505    
506              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
507              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
508              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
# Line 356  namespace LinuxSampler { Line 535  namespace LinuxSampler {
535       */       */
536      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
537          if (pEngine) {          if (pEngine) {
538                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
539                LockGuard g;
540                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
541    
542              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
543              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
544              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
# Line 393  namespace LinuxSampler { Line 576  namespace LinuxSampler {
576              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
577          }          }
578          else if (pEngine) {          else if (pEngine) {
579                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
580                LockGuard g;
581                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
582    
583              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
584              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
585              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
# Line 424  namespace LinuxSampler { Line 611  namespace LinuxSampler {
611       */       */
612      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
613          if (pEngine) {          if (pEngine) {
614                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
615                LockGuard g;
616                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
617    
618              Event event             = pEngine->pEventGenerator->CreateEvent();              Event event             = pEngine->pEventGenerator->CreateEvent();
619              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
620              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
# Line 449  namespace LinuxSampler { Line 640  namespace LinuxSampler {
640              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
641          }          }
642          else if (pEngine) {          else if (pEngine) {
643                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
644                LockGuard g;
645                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
646    
647              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);
648              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
649              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
# Line 470  namespace LinuxSampler { Line 665  namespace LinuxSampler {
665       */       */
666      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {
667          if (pEngine) {          if (pEngine) {
668                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
669                LockGuard g;
670                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
671    
672              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
673              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
674              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
# Line 497  namespace LinuxSampler { Line 696  namespace LinuxSampler {
696              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
697          }          }
698          else if (pEngine) {          else if (pEngine) {
699                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
700                LockGuard g;
701                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
702    
703              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
704              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
705              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
# Line 508  namespace LinuxSampler { Line 711  namespace LinuxSampler {
711          }          }
712      }      }
713    
714        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel) {
715            if (pEngine) {
716                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
717                LockGuard g;
718                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
719    
720                Event event = pEngine->pEventGenerator->CreateEvent();
721                event.Type                          = Event::type_channel_pressure;
722                event.Param.ChannelPressure.Value   = Value;
723                event.Param.ChannelPressure.Channel = MidiChannel;
724                event.pEngineChannel                = this;
725                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
726                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
727            }
728        }
729    
730        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
731            if (pEngine) {
732                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
733                LockGuard g;
734                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
735    
736                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
737                event.Type                          = Event::type_channel_pressure;
738                event.Param.ChannelPressure.Value   = Value;
739                event.Param.ChannelPressure.Channel = MidiChannel;
740                event.pEngineChannel                = this;
741                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
742                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
743            }
744        }
745    
746        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel) {
747            if (pEngine) {
748                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
749                LockGuard g;
750                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
751    
752                Event event = pEngine->pEventGenerator->CreateEvent();
753                event.Type                       = Event::type_note_pressure;
754                event.Param.NotePressure.Key     = Key;
755                event.Param.NotePressure.Value   = Value;
756                event.Param.NotePressure.Channel = MidiChannel;
757                event.pEngineChannel             = this;
758                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
759                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
760            }
761        }
762    
763        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
764            if (pEngine) {
765                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
766                LockGuard g;
767                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
768    
769                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
770                event.Type                       = Event::type_note_pressure;
771                event.Param.NotePressure.Key     = Key;
772                event.Param.NotePressure.Value   = Value;
773                event.Param.NotePressure.Channel = MidiChannel;
774                event.pEngineChannel             = this;
775                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
776                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
777            }
778        }
779    
780      /**      /**
781       * 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
782       * 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 821  namespace LinuxSampler {
821                              event.Param.Note.Channel  = channel;                              event.Param.Note.Channel  = channel;
822                              break;                              break;
823                          case VirtualMidiDevice::EVENT_TYPE_CC:                          case VirtualMidiDevice::EVENT_TYPE_CC:
824                              event.Type = Event::type_control_change;                              switch (devEvent.Arg1) {
825                              event.Param.CC.Controller = devEvent.Arg1;                                  case 0: // bank select MSB ...
826                              event.Param.CC.Value      = devEvent.Arg2;                                      SetMidiBankMsb(devEvent.Arg2);
827                              event.Param.CC.Channel    = channel;                                      continue; // don't push this event into FIFO
828                                    case 32: // bank select LSB ...
829                                        SetMidiBankLsb(devEvent.Arg2);
830                                        continue; // don't push this event into FIFO
831                                    default: // regular MIDI CC ...
832                                        event.Type = Event::type_control_change;
833                                        event.Param.CC.Controller = devEvent.Arg1;
834                                        event.Param.CC.Value      = devEvent.Arg2;
835                                        event.Param.CC.Channel    = channel;
836                                }
837                                break;
838                            case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
839                                event.Type = Event::type_pitchbend;
840                                event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
841                                event.Param.Pitch.Channel = channel;
842                              break;                              break;
843                            case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
844                                SendProgramChange(devEvent.Arg1);
845                                continue; // don't push this event into FIFO
846                          default:                          default:
847                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
848                                        << devEvent.Type << "). This is a bug!";                                        << devEvent.Type << "). This is a bug!";

Legend:
Removed from v.2382  
changed lines
  Added in v.2594

  ViewVC Help
Powered by ViewVC