/[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 2025 by schoenebeck, Sun Nov 1 18:47:59 2009 UTC revision 2559 by schoenebeck, Sun May 18 17:38:25 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!"));
619          }          }
620      }      }
621    
622        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel) {
623            if (pEngine) {
624                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
625                LockGuard g;
626                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
627    
628                Event event = pEngine->pEventGenerator->CreateEvent();
629                event.Type                          = Event::type_channel_pressure;
630                event.Param.ChannelPressure.Value   = Value;
631                event.Param.ChannelPressure.Channel = MidiChannel;
632                event.pEngineChannel                = this;
633                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
634                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
635            }
636        }
637    
638        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
639            if (pEngine) {
640                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
641                LockGuard g;
642                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
643    
644                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
645                event.Type                          = Event::type_channel_pressure;
646                event.Param.ChannelPressure.Value   = Value;
647                event.Param.ChannelPressure.Channel = MidiChannel;
648                event.pEngineChannel                = this;
649                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
650                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
651            }
652        }
653    
654        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel) {
655            if (pEngine) {
656                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
657                LockGuard g;
658                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
659    
660                Event event = pEngine->pEventGenerator->CreateEvent();
661                event.Type                       = Event::type_note_pressure;
662                event.Param.NotePressure.Key     = Key;
663                event.Param.NotePressure.Value   = Value;
664                event.Param.NotePressure.Channel = MidiChannel;
665                event.pEngineChannel             = this;
666                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
667                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
668            }
669        }
670    
671        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
672            if (pEngine) {
673                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
674                LockGuard g;
675                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
676    
677                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
678                event.Type                       = Event::type_note_pressure;
679                event.Param.NotePressure.Key     = Key;
680                event.Param.NotePressure.Value   = Value;
681                event.Param.NotePressure.Channel = MidiChannel;
682                event.pEngineChannel             = this;
683                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
684                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
685            }
686        }
687    
688      /**      /**
689       * 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
690       * 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 510  namespace LinuxSampler { Line 702  namespace LinuxSampler {
702          // import events from pure software MIDI "devices"          // import events from pure software MIDI "devices"
703          // (e.g. virtual keyboard in instrument editor)          // (e.g. virtual keyboard in instrument editor)
704          {          {
705                const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
706              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
707              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
708              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 527  namespace LinuxSampler { Line 720  namespace LinuxSampler {
720                              event.Type = Event::type_note_on;                              event.Type = Event::type_note_on;
721                              event.Param.Note.Key      = devEvent.Arg1;                              event.Param.Note.Key      = devEvent.Arg1;
722                              event.Param.Note.Velocity = devEvent.Arg2;                              event.Param.Note.Velocity = devEvent.Arg2;
723                                event.Param.Note.Channel  = channel;
724                              break;                              break;
725                          case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:                          case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
726                              event.Type = Event::type_note_off;                              event.Type = Event::type_note_off;
727                              event.Param.Note.Key      = devEvent.Arg1;                              event.Param.Note.Key      = devEvent.Arg1;
728                              event.Param.Note.Velocity = devEvent.Arg2;                              event.Param.Note.Velocity = devEvent.Arg2;
729                                event.Param.Note.Channel  = channel;
730                              break;                              break;
731                          case VirtualMidiDevice::EVENT_TYPE_CC:                          case VirtualMidiDevice::EVENT_TYPE_CC:
732                              event.Type = Event::type_control_change;                              switch (devEvent.Arg1) {
733                              event.Param.CC.Controller = devEvent.Arg1;                                  case 0: // bank select MSB ...
734                              event.Param.CC.Value      = devEvent.Arg2;                                      SetMidiBankMsb(devEvent.Arg2);
735                                        continue; // don't push this event into FIFO
736                                    case 32: // bank select LSB ...
737                                        SetMidiBankLsb(devEvent.Arg2);
738                                        continue; // don't push this event into FIFO
739                                    default: // regular MIDI CC ...
740                                        event.Type = Event::type_control_change;
741                                        event.Param.CC.Controller = devEvent.Arg1;
742                                        event.Param.CC.Value      = devEvent.Arg2;
743                                        event.Param.CC.Channel    = channel;
744                                }
745                              break;                              break;
746                            case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
747                                event.Type = Event::type_pitchbend;
748                                event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
749                                event.Param.Pitch.Channel = channel;
750                                break;
751                            case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
752                                SendProgramChange(devEvent.Arg1);
753                                continue; // don't push this event into FIFO
754                          default:                          default:
755                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
756                                        << devEvent.Type << "). This is a bug!";                                        << devEvent.Type << "). This is a bug!";
# Line 661  namespace LinuxSampler { Line 874  namespace LinuxSampler {
874          if (pEngine) pEngine->Enable();          if (pEngine) pEngine->Enable();
875      }      }
876    
877        /**
878         * Add a group number to the set of key groups. Should be called
879         * when an instrument is loaded to make sure there are event lists
880         * for all key groups.
881         */
882        void AbstractEngineChannel::AddGroup(uint group) {
883            if (group) {
884                std::pair<ActiveKeyGroupMap::iterator, bool> p =
885                    ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
886                if (p.second) {
887                    // If the engine channel is pending deletion (see bug
888                    // #113), pEngine will be null, so we can't use
889                    // pEngine->pEventPool here. Instead we're using a
890                    // specialized RTList that allows specifying the pool
891                    // later.
892                    (*p.first).second = new LazyList<Event>;
893                }
894            }
895        }
896    
897        /**
898         * Handle key group (a.k.a. exclusive group) conflicts.
899         */
900        void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {
901            dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
902            if (KeyGroup) {
903                // send a release event to all active voices in the group
904                RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
905                *itEvent = *itNoteOnEvent;
906            }
907        }
908    
909        /**
910         * Empty the lists of group events. Should be called from the
911         * audio thread, after all voices have been rendered.
912         */
913        void AbstractEngineChannel::ClearGroupEventLists() {
914            for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
915                 iter != ActiveKeyGroups.end(); iter++) {
916                if (iter->second) {
917                    iter->second->clear();
918                } else {
919                    dmsg(1,("EngineChannel: group event list was NULL"));
920                }
921            }
922        }
923    
924        /**
925         * Remove all lists with group events.
926         */
927        void AbstractEngineChannel::DeleteGroupEventLists() {
928            for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
929                 iter != ActiveKeyGroups.end(); iter++) {
930                delete iter->second;
931            }
932            ActiveKeyGroups.clear();
933        }
934    
935  } // namespace LinuxSampler  } // namespace LinuxSampler

Legend:
Removed from v.2025  
changed lines
  Added in v.2559

  ViewVC Help
Powered by ViewVC