/[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 2012 by iliev, Fri Oct 23 17:53:17 2009 UTC revision 2521 by schoenebeck, Wed Feb 19 19:02:43 2014 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2009 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009 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;
# Line 49  namespace LinuxSampler { Line 49  namespace LinuxSampler {
49      }      }
50    
51      AbstractEngineChannel::~AbstractEngineChannel() {      AbstractEngineChannel::~AbstractEngineChannel() {
52                    delete pEventQueue;
53          if (pEventQueue) delete pEventQueue;          DeleteGroupEventLists();
54          RemoveAllFxSends();          RemoveAllFxSends();
55      }      }
56    
# Line 112  namespace LinuxSampler { Line 112  namespace LinuxSampler {
112          Pitch          = 0;          Pitch          = 0;
113          GlobalVolume   = 1.0f;          GlobalVolume   = 1.0f;
114          MidiVolume     = 1.0;          MidiVolume     = 1.0;
         GlobalPanLeft  = 1.0f;  
         GlobalPanRight = 1.0f;  
115          iLastPanRequest = 64;          iLastPanRequest = 64;
116          GlobalTranspose = 0;          GlobalTranspose = 0;
117          // set all MIDI controller values to zero          // set all MIDI controller values to zero
# Line 182  namespace LinuxSampler { Line 180  namespace LinuxSampler {
180          int iMidiPan = int(f * 64.0f) + 64;          int iMidiPan = int(f * 64.0f) + 64;
181          if (iMidiPan > 127) iMidiPan = 127;          if (iMidiPan > 127) iMidiPan = 127;
182          else if (iMidiPan < 0) iMidiPan = 0;          else if (iMidiPan < 0) iMidiPan = 0;
         GlobalPanLeft  = AbstractEngine::PanCurve[128 - iMidiPan];  
         GlobalPanRight = AbstractEngine::PanCurve[iMidiPan];  
183          iLastPanRequest = iMidiPan;          iLastPanRequest = iMidiPan;
184      }      }
185    
# Line 191  namespace LinuxSampler { Line 187  namespace LinuxSampler {
187          return (pEngine) ? pEngine->pAudioOutputDevice : NULL;          return (pEngine) ? pEngine->pAudioOutputDevice : NULL;
188      }      }
189    
190        /**
191         * Gets thread safe access to the currently connected audio output
192         * device from other threads than the lscp thread.
193         */
194        AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {
195            LockGuard lock(EngineMutex);
196            return GetAudioOutputDevice();
197        }
198    
199      void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {      void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
200          if (!pEngine || !pEngine->pAudioOutputDevice) throw AudioOutputException("No audio output device connected yet.");          if (!pEngine || !pEngine->pAudioOutputDevice) throw AudioOutputException("No audio output device connected yet.");
201    
# Line 223  namespace LinuxSampler { Line 228  namespace LinuxSampler {
228          }          }
229      }      }
230    
231        void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort) {
232            if (!pMidiPort) return;
233    
234            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
235    
236            // check if connection already exists
237            for (int i = 0; i < connections->size(); ++i)
238                if ((*connections)[i] == pMidiPort)
239                    return; // to avoid endless recursion
240    
241            connections->add(pMidiPort);
242    
243            // inform MIDI port about this new connection
244            pMidiPort->Connect(this, MidiChannel());
245        }
246    
247        void AbstractEngineChannel::Disconnect(MidiInputPort* pMidiPort) {
248            if (!pMidiPort) return;
249    
250            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
251    
252            for (int i = 0; i < connections->size(); ++i) {
253                if ((*connections)[i] == pMidiPort) {
254                    connections->remove(i);
255                    // inform MIDI port about this disconnection
256                    pMidiPort->Disconnect(this);
257                    return;
258                }
259            }
260        }
261    
262        void AbstractEngineChannel::DisconnectAllMidiInputPorts() {
263            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
264            ArrayList<MidiInputPort*> clonedList = *connections;
265            connections->clear();
266            for (int i = 0; i < clonedList.size(); ++i) clonedList[i]->Disconnect(this);
267        }
268    
269        uint AbstractEngineChannel::GetMidiInputPortCount() {
270            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
271            return connections->size();
272        }
273    
274        MidiInputPort* AbstractEngineChannel::GetMidiInputPort(uint index) {
275            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
276            return (index < connections->size()) ? (*connections)[index] : NULL;
277        }
278    
279        // deprecated (just for API backward compatibility) - may be removed in future
280      void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {      void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
281          if (!pMidiPort || pMidiPort == this->pMidiInputPort) return;          if (!pMidiPort) return;
282          DisconnectMidiInputPort();  
283          this->pMidiInputPort = pMidiPort;          Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
284          this->midiChannel    = MidiChannel;  
285            // check against endless recursion
286            if (connections->size() == 1 && (*connections)[0] == pMidiPort && this->midiChannel == MidiChannel)
287                return;
288            
289            if (!isValidMidiChan(MidiChannel))
290                throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
291    
292            this->midiChannel = MidiChannel;
293    
294            // disconnect all currently connected MIDI ports
295            ArrayList<MidiInputPort*> clonedList = *connections;
296            connections->clear();
297            for (int i = 0; i < clonedList.size(); ++i)
298                clonedList[i]->Disconnect(this);
299    
300            // connect the new port
301            connections->add(pMidiPort);
302          pMidiPort->Connect(this, MidiChannel);          pMidiPort->Connect(this, MidiChannel);
303      }      }
304    
305        // deprecated (just for API backward compatibility) - may be removed in future
306      void AbstractEngineChannel::DisconnectMidiInputPort() {      void AbstractEngineChannel::DisconnectMidiInputPort() {
307          MidiInputPort* pOldPort = this->pMidiInputPort;          DisconnectAllMidiInputPorts();
         this->pMidiInputPort = NULL;  
         if (pOldPort) pOldPort->Disconnect(this);  
308      }      }
309    
310        // deprecated (just for API backward compatibility) - may be removed in future
311      MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {      MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {
312          return pMidiInputPort;          return GetMidiInputPort(0);
313      }      }
314    
315      midi_chan_t AbstractEngineChannel::MidiChannel() {      midi_chan_t AbstractEngineChannel::MidiChannel() {
316          return midiChannel;          return midiChannel;
317      }      }
318    
319        void AbstractEngineChannel::SetMidiChannel(midi_chan_t MidiChannel) {
320            if (this->midiChannel == MidiChannel) return;
321            if (!isValidMidiChan(MidiChannel))
322                throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
323    
324            this->midiChannel = MidiChannel;
325            
326            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
327            ArrayList<MidiInputPort*> clonedList = *connections;
328    
329            DisconnectAllMidiInputPorts();
330    
331            for (int i = 0; i < clonedList.size(); ++i) Connect(clonedList[i]);
332        }
333    
334      void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {      void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {
335          // double buffer ... double work ...          // double buffer ... double work ...
336          {          {
# Line 278  namespace LinuxSampler { Line 364  namespace LinuxSampler {
364       *  @param Key      - MIDI key number of the triggered key       *  @param Key      - MIDI key number of the triggered key
365       *  @param Velocity - MIDI velocity value of the triggered key       *  @param Velocity - MIDI velocity value of the triggered key
366       */       */
367      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity) {      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
368          if (pEngine) {          if (pEngine) {
369                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
370                LockGuard g;
371                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
372    
373              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
374              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
375              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
376              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
377                event.Param.Note.Channel  = MidiChannel;
378              event.pEngineChannel      = this;              event.pEngineChannel      = this;
379              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
380              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 311  namespace LinuxSampler { Line 402  namespace LinuxSampler {
402       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
403       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
404       */       */
405      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, int32_t FragmentPos) {      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
406          if (FragmentPos < 0) {          if (FragmentPos < 0) {
407              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
408          }          }
409          else if (pEngine) {          else if (pEngine) {
410                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
411                LockGuard g;
412                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
413    
414              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
415              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
416              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
417              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
418                event.Param.Note.Channel  = MidiChannel;
419              event.pEngineChannel      = this;              event.pEngineChannel      = this;
420              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
421              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 345  namespace LinuxSampler { Line 441  namespace LinuxSampler {
441       *  @param Key      - MIDI key number of the released key       *  @param Key      - MIDI key number of the released key
442       *  @param Velocity - MIDI release velocity value of the released key       *  @param Velocity - MIDI release velocity value of the released key
443       */       */
444      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity) {      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
445          if (pEngine) {          if (pEngine) {
446                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
447                LockGuard g;
448                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
449    
450              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
451              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
452              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
453              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
454                event.Param.Note.Channel  = MidiChannel;
455              event.pEngineChannel      = this;              event.pEngineChannel      = this;
456              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
457              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 378  namespace LinuxSampler { Line 479  namespace LinuxSampler {
479       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
480       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
481       */       */
482      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, int32_t FragmentPos) {      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel, int32_t FragmentPos) {
483          if (FragmentPos < 0) {          if (FragmentPos < 0) {
484              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
485          }          }
486          else if (pEngine) {          else if (pEngine) {
487                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
488                LockGuard g;
489                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
490    
491              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
492              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
493              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
494              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
495                event.Param.Note.Channel  = MidiChannel;
496              event.pEngineChannel      = this;              event.pEngineChannel      = this;
497              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
498              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 411  namespace LinuxSampler { Line 517  namespace LinuxSampler {
517       *       *
518       *  @param Pitch - MIDI pitch value (-8192 ... +8191)       *  @param Pitch - MIDI pitch value (-8192 ... +8191)
519       */       */
520      void AbstractEngineChannel::SendPitchbend(int Pitch) {      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
521          if (pEngine) {          if (pEngine) {
522                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
523                LockGuard g;
524                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
525    
526              Event event             = pEngine->pEventGenerator->CreateEvent();              Event event             = pEngine->pEventGenerator->CreateEvent();
527              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
528              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
529                event.Param.Pitch.Channel = MidiChannel;
530              event.pEngineChannel    = this;              event.pEngineChannel    = this;
531              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
532              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 432  namespace LinuxSampler { Line 543  namespace LinuxSampler {
543       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
544       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
545       */       */
546      void AbstractEngineChannel::SendPitchbend(int Pitch, int32_t FragmentPos) {      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel, int32_t FragmentPos) {
547          if (FragmentPos < 0) {          if (FragmentPos < 0) {
548              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
549          }          }
550          else if (pEngine) {          else if (pEngine) {
551                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
552                LockGuard g;
553                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
554    
555              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);
556              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
557              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
558                event.Param.Pitch.Channel = MidiChannel;
559              event.pEngineChannel    = this;              event.pEngineChannel    = this;
560              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
561              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 455  namespace LinuxSampler { Line 571  namespace LinuxSampler {
571       *  @param Controller - MIDI controller number of the occured control change       *  @param Controller - MIDI controller number of the occured control change
572       *  @param Value      - value of the control change       *  @param Value      - value of the control change
573       */       */
574      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value) {      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {
575          if (pEngine) {          if (pEngine) {
576                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
577                LockGuard g;
578                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
579    
580              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
581              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
582              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
583              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
584                event.Param.CC.Channel    = MidiChannel;
585              event.pEngineChannel      = this;              event.pEngineChannel      = this;
586              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
587              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 478  namespace LinuxSampler { Line 599  namespace LinuxSampler {
599       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
600       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
601       */       */
602      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, int32_t FragmentPos) {      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
603          if (FragmentPos < 0) {          if (FragmentPos < 0) {
604              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
605          }          }
606          else if (pEngine) {          else if (pEngine) {
607                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
608                LockGuard g;
609                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
610    
611              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
612              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
613              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
614              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
615                event.Param.CC.Channel    = MidiChannel;
616              event.pEngineChannel      = this;              event.pEngineChannel      = this;
617              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
618              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 510  namespace LinuxSampler { Line 636  namespace LinuxSampler {
636          // import events from pure software MIDI "devices"          // import events from pure software MIDI "devices"
637          // (e.g. virtual keyboard in instrument editor)          // (e.g. virtual keyboard in instrument editor)
638          {          {
639                const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
640              const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices              const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices
641              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
642              VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device              VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
# Line 522  namespace LinuxSampler { Line 649  namespace LinuxSampler {
649                  VirtualMidiDevice* pDev = devices[i];                  VirtualMidiDevice* pDev = devices[i];
650                  // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)                  // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
651                  while (pDev->GetMidiEventFromDevice(devEvent)) {                  while (pDev->GetMidiEventFromDevice(devEvent)) {
652                      event.Type =                      switch (devEvent.Type) {
653                          (devEvent.Type == VirtualMidiDevice::EVENT_TYPE_NOTEON) ?                          case VirtualMidiDevice::EVENT_TYPE_NOTEON:
654                              Event::type_note_on : Event::type_note_off;                              event.Type = Event::type_note_on;
655                      event.Param.Note.Key      = devEvent.Key;                              event.Param.Note.Key      = devEvent.Arg1;
656                      event.Param.Note.Velocity = devEvent.Velocity;                              event.Param.Note.Velocity = devEvent.Arg2;
657                      event.pEngineChannel      = this;                              event.Param.Note.Channel  = channel;
658                                break;
659                            case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
660                                event.Type = Event::type_note_off;
661                                event.Param.Note.Key      = devEvent.Arg1;
662                                event.Param.Note.Velocity = devEvent.Arg2;
663                                event.Param.Note.Channel  = channel;
664                                break;
665                            case VirtualMidiDevice::EVENT_TYPE_CC:
666                                switch (devEvent.Arg1) {
667                                    case 0: // bank select MSB ...
668                                        SetMidiBankMsb(devEvent.Arg2);
669                                        continue; // don't push this event into FIFO
670                                    case 32: // bank select LSB ...
671                                        SetMidiBankLsb(devEvent.Arg2);
672                                        continue; // don't push this event into FIFO
673                                    default: // regular MIDI CC ...
674                                        event.Type = Event::type_control_change;
675                                        event.Param.CC.Controller = devEvent.Arg1;
676                                        event.Param.CC.Value      = devEvent.Arg2;
677                                        event.Param.CC.Channel    = channel;
678                                }
679                                break;
680                            case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
681                                event.Type = Event::type_pitchbend;
682                                event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
683                                event.Param.Pitch.Channel = channel;
684                                break;
685                            case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
686                                SendProgramChange(devEvent.Arg1);
687                                continue; // don't push this event into FIFO
688                            default:
689                                std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
690                                          << devEvent.Type << "). This is a bug!";
691                                continue;
692                        }
693                        event.pEngineChannel = this;
694                      // copy event to internal event list                      // copy event to internal event list
695                      if (pEvents->poolIsEmpty()) {                      if (pEvents->poolIsEmpty()) {
696                          dmsg(1,("Event pool emtpy!\n"));                          dmsg(1,("Event pool emtpy!\n"));
# Line 645  namespace LinuxSampler { Line 808  namespace LinuxSampler {
808          if (pEngine) pEngine->Enable();          if (pEngine) pEngine->Enable();
809      }      }
810    
811        /**
812         * Add a group number to the set of key groups. Should be called
813         * when an instrument is loaded to make sure there are event lists
814         * for all key groups.
815         */
816        void AbstractEngineChannel::AddGroup(uint group) {
817            if (group) {
818                std::pair<ActiveKeyGroupMap::iterator, bool> p =
819                    ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
820                if (p.second) {
821                    // If the engine channel is pending deletion (see bug
822                    // #113), pEngine will be null, so we can't use
823                    // pEngine->pEventPool here. Instead we're using a
824                    // specialized RTList that allows specifying the pool
825                    // later.
826                    (*p.first).second = new LazyList<Event>;
827                }
828            }
829        }
830    
831        /**
832         * Handle key group (a.k.a. exclusive group) conflicts.
833         */
834        void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {
835            dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
836            if (KeyGroup) {
837                // send a release event to all active voices in the group
838                RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
839                *itEvent = *itNoteOnEvent;
840            }
841        }
842    
843        /**
844         * Empty the lists of group events. Should be called from the
845         * audio thread, after all voices have been rendered.
846         */
847        void AbstractEngineChannel::ClearGroupEventLists() {
848            for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
849                 iter != ActiveKeyGroups.end(); iter++) {
850                if (iter->second) {
851                    iter->second->clear();
852                } else {
853                    dmsg(1,("EngineChannel: group event list was NULL"));
854                }
855            }
856        }
857    
858        /**
859         * Remove all lists with group events.
860         */
861        void AbstractEngineChannel::DeleteGroupEventLists() {
862            for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
863                 iter != ActiveKeyGroups.end(); iter++) {
864                delete iter->second;
865            }
866            ActiveKeyGroups.clear();
867        }
868    
869  } // namespace LinuxSampler  } // namespace LinuxSampler

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

  ViewVC Help
Powered by ViewVC