/[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 2871 by schoenebeck, Sun Apr 10 18:22:23 2016 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) 2012-2016 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 34  namespace LinuxSampler { Line 35  namespace LinuxSampler {
35      {      {
36          pEngine      = NULL;          pEngine      = NULL;
37          pEvents      = NULL; // we allocate when we retrieve the right Engine object          pEvents      = NULL; // we allocate when we retrieve the right Engine object
38            delayedEvents.pList = NULL;
39          pEventQueue  = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue  = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
40          InstrumentIdx  = -1;          InstrumentIdx  = -1;
41          InstrumentStat = -1;          InstrumentStat = -1;
# Line 41  namespace LinuxSampler { Line 43  namespace LinuxSampler {
43          pChannelRight = NULL;          pChannelRight = NULL;
44          AudioDeviceChannelLeft  = -1;          AudioDeviceChannelLeft  = -1;
45          AudioDeviceChannelRight = -1;          AudioDeviceChannelRight = -1;
         pMidiInputPort = NULL;  
46          midiChannel = midi_chan_all;          midiChannel = midi_chan_all;
47          ResetControllers();          ResetControllers();
48          PortamentoMode = false;          PortamentoMode = false;
49          PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;          PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;
50            pScript = NULL;
51      }      }
52    
53      AbstractEngineChannel::~AbstractEngineChannel() {      AbstractEngineChannel::~AbstractEngineChannel() {
# Line 100  namespace LinuxSampler { Line 102  namespace LinuxSampler {
102    
103      void AbstractEngineChannel::Reset() {      void AbstractEngineChannel::Reset() {
104          if (pEngine) pEngine->DisableAndLock();          if (pEngine) pEngine->DisableAndLock();
105          ResetInternal();          ResetInternal(false/*don't reset engine*/);
106          ResetControllers();          ResetControllers();
107          if (pEngine) {          if (pEngine) {
108              pEngine->Enable();              pEngine->Enable();
# Line 128  namespace LinuxSampler { Line 130  namespace LinuxSampler {
130      /**      /**
131       * This method is not thread safe!       * This method is not thread safe!
132       */       */
133      void AbstractEngineChannel::ResetInternal() {      void AbstractEngineChannel::ResetInternal(bool bResetEngine) {
134          CurrentKeyDimension = 0;          CurrentKeyDimension = 0;
135          PortamentoPos = -1.0f; // no portamento active yet          PortamentoPos = -1.0f; // no portamento active yet
136    
137            // delete all active instrument script events
138            if (pScript) pScript->resetEvents();
139    
140            // free all delayed MIDI events
141            delayedEvents.clear();
142    
143          // delete all input events          // delete all input events
144          pEventQueue->init();          pEventQueue->init();
145    
146          if (pEngine) pEngine->ResetInternal();          if (bResetEngine && pEngine) pEngine->ResetInternal();
147    
148          // status of engine channel has changed, so set notify flag          // status of engine channel has changed, so set notify flag
149          bStatusChanged = true;          bStatusChanged = true;
# Line 192  namespace LinuxSampler { Line 200  namespace LinuxSampler {
200       * device from other threads than the lscp thread.       * device from other threads than the lscp thread.
201       */       */
202      AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {      AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {
203          EngineMutex.Lock();          LockGuard lock(EngineMutex);
204          AudioOutputDevice* res = GetAudioOutputDevice();          return GetAudioOutputDevice();
         EngineMutex.Unlock();  
         return res;  
205      }      }
206    
207      void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {      void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
# Line 230  namespace LinuxSampler { Line 236  namespace LinuxSampler {
236          }          }
237      }      }
238    
239        void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort) {
240            if (!pMidiPort) return;
241    
242            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
243    
244            // check if connection already exists
245            for (int i = 0; i < connections->size(); ++i)
246                if ((*connections)[i] == pMidiPort)
247                    return; // to avoid endless recursion
248    
249            connections->add(pMidiPort);
250    
251            // inform MIDI port about this new connection
252            pMidiPort->Connect(this, MidiChannel());
253        }
254    
255        void AbstractEngineChannel::Disconnect(MidiInputPort* pMidiPort) {
256            if (!pMidiPort) return;
257    
258            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
259    
260            for (int i = 0; i < connections->size(); ++i) {
261                if ((*connections)[i] == pMidiPort) {
262                    connections->remove(i);
263                    // inform MIDI port about this disconnection
264                    pMidiPort->Disconnect(this);
265                    return;
266                }
267            }
268        }
269    
270        void AbstractEngineChannel::DisconnectAllMidiInputPorts() {
271            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
272            ArrayList<MidiInputPort*> clonedList = *connections;
273            connections->clear();
274            for (int i = 0; i < clonedList.size(); ++i) clonedList[i]->Disconnect(this);
275        }
276    
277        uint AbstractEngineChannel::GetMidiInputPortCount() {
278            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
279            return connections->size();
280        }
281    
282        MidiInputPort* AbstractEngineChannel::GetMidiInputPort(uint index) {
283            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
284            return (index < connections->size()) ? (*connections)[index] : NULL;
285        }
286    
287        // deprecated (just for API backward compatibility) - may be removed in future
288      void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {      void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
289          if (!pMidiPort || pMidiPort == this->pMidiInputPort) return;          if (!pMidiPort) return;
290          DisconnectMidiInputPort();  
291          this->pMidiInputPort = pMidiPort;          Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
292          this->midiChannel    = MidiChannel;  
293            // check against endless recursion
294            if (connections->size() == 1 && (*connections)[0] == pMidiPort && this->midiChannel == MidiChannel)
295                return;
296            
297            if (!isValidMidiChan(MidiChannel))
298                throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
299    
300            this->midiChannel = MidiChannel;
301    
302            // disconnect all currently connected MIDI ports
303            ArrayList<MidiInputPort*> clonedList = *connections;
304            connections->clear();
305            for (int i = 0; i < clonedList.size(); ++i)
306                clonedList[i]->Disconnect(this);
307    
308            // connect the new port
309            connections->add(pMidiPort);
310          pMidiPort->Connect(this, MidiChannel);          pMidiPort->Connect(this, MidiChannel);
311      }      }
312    
313        // deprecated (just for API backward compatibility) - may be removed in future
314      void AbstractEngineChannel::DisconnectMidiInputPort() {      void AbstractEngineChannel::DisconnectMidiInputPort() {
315          MidiInputPort* pOldPort = this->pMidiInputPort;          DisconnectAllMidiInputPorts();
         this->pMidiInputPort = NULL;  
         if (pOldPort) pOldPort->Disconnect(this);  
316      }      }
317    
318        // deprecated (just for API backward compatibility) - may be removed in future
319      MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {      MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {
320          return pMidiInputPort;          return GetMidiInputPort(0);
321      }      }
322    
323      midi_chan_t AbstractEngineChannel::MidiChannel() {      midi_chan_t AbstractEngineChannel::MidiChannel() {
324          return midiChannel;          return midiChannel;
325      }      }
326    
327        void AbstractEngineChannel::SetMidiChannel(midi_chan_t MidiChannel) {
328            if (this->midiChannel == MidiChannel) return;
329            if (!isValidMidiChan(MidiChannel))
330                throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
331    
332            this->midiChannel = MidiChannel;
333            
334            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
335            ArrayList<MidiInputPort*> clonedList = *connections;
336    
337            DisconnectAllMidiInputPorts();
338    
339            for (int i = 0; i < clonedList.size(); ++i) Connect(clonedList[i]);
340        }
341    
342      void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {      void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {
343          // double buffer ... double work ...          // double buffer ... double work ...
344          {          {
# Line 287  namespace LinuxSampler { Line 374  namespace LinuxSampler {
374       */       */
375      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
376          if (pEngine) {          if (pEngine) {
377                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
378                LockGuard g;
379                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
380    
381              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
382              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
383              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
384              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
385              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
386                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
387              event.pEngineChannel      = this;              event.pEngineChannel      = this;
388              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
389              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 324  namespace LinuxSampler { Line 416  namespace LinuxSampler {
416              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
417          }          }
418          else if (pEngine) {          else if (pEngine) {
419                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
420                LockGuard g;
421                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
422    
423              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
424              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
425              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
426              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
427              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
428                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
429              event.pEngineChannel      = this;              event.pEngineChannel      = this;
430              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
431              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 356  namespace LinuxSampler { Line 453  namespace LinuxSampler {
453       */       */
454      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
455          if (pEngine) {          if (pEngine) {
456                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
457                LockGuard g;
458                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
459    
460              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
461              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
462              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
463              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
464              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
465                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
466              event.pEngineChannel      = this;              event.pEngineChannel      = this;
467              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
468              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 393  namespace LinuxSampler { Line 495  namespace LinuxSampler {
495              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
496          }          }
497          else if (pEngine) {          else if (pEngine) {
498                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
499                LockGuard g;
500                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
501    
502              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
503              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
504              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
505              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
506              event.Param.Note.Channel  = MidiChannel;              event.Param.Note.Channel  = MidiChannel;
507                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
508              event.pEngineChannel      = this;              event.pEngineChannel      = this;
509              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
510              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 424  namespace LinuxSampler { Line 531  namespace LinuxSampler {
531       */       */
532      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
533          if (pEngine) {          if (pEngine) {
534                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
535                LockGuard g;
536                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
537    
538              Event event             = pEngine->pEventGenerator->CreateEvent();              Event event             = pEngine->pEventGenerator->CreateEvent();
539              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
540              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
541              event.Param.Pitch.Channel = MidiChannel;              event.Param.Pitch.Channel = MidiChannel;
542                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
543              event.pEngineChannel    = this;              event.pEngineChannel    = this;
544              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
545              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 449  namespace LinuxSampler { Line 561  namespace LinuxSampler {
561              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
562          }          }
563          else if (pEngine) {          else if (pEngine) {
564                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
565                LockGuard g;
566                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
567    
568              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);
569              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
570              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
571              event.Param.Pitch.Channel = MidiChannel;              event.Param.Pitch.Channel = MidiChannel;
572                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
573              event.pEngineChannel    = this;              event.pEngineChannel    = this;
574              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
575              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 470  namespace LinuxSampler { Line 587  namespace LinuxSampler {
587       */       */
588      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {
589          if (pEngine) {          if (pEngine) {
590                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
591                LockGuard g;
592                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
593    
594              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
595              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
596              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
597              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
598              event.Param.CC.Channel    = MidiChannel;              event.Param.CC.Channel    = MidiChannel;
599                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
600              event.pEngineChannel      = this;              event.pEngineChannel      = this;
601              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
602              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 497  namespace LinuxSampler { Line 619  namespace LinuxSampler {
619              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
620          }          }
621          else if (pEngine) {          else if (pEngine) {
622                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
623                LockGuard g;
624                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
625    
626              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
627              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
628              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
629              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
630              event.Param.CC.Channel    = MidiChannel;              event.Param.CC.Channel    = MidiChannel;
631                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
632              event.pEngineChannel      = this;              event.pEngineChannel      = this;
633              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
634              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
635          }          }
636      }      }
637    
638        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel) {
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();
645                event.Type                          = Event::type_channel_pressure;
646                event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
647                event.Param.ChannelPressure.Value   = Value;
648                event.Param.ChannelPressure.Channel = MidiChannel;
649                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
650                event.pEngineChannel                = this;
651                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
652                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
653            }
654        }
655    
656        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
657            if (pEngine) {
658                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
659                LockGuard g;
660                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
661    
662                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
663                event.Type                          = Event::type_channel_pressure;
664                event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
665                event.Param.ChannelPressure.Value   = Value;
666                event.Param.ChannelPressure.Channel = MidiChannel;
667                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
668                event.pEngineChannel                = this;
669                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
670                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
671            }
672        }
673    
674        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel) {
675            if (pEngine) {
676                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
677                LockGuard g;
678                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
679    
680                Event event = pEngine->pEventGenerator->CreateEvent();
681                event.Type                       = Event::type_note_pressure;
682                event.Param.NotePressure.Key     = Key;
683                event.Param.NotePressure.Value   = Value;
684                event.Param.NotePressure.Channel = MidiChannel;
685                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
686                event.pEngineChannel             = this;
687                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
688                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
689            }
690        }
691    
692        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
693            if (pEngine) {
694                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
695                LockGuard g;
696                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
697    
698                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
699                event.Type                       = Event::type_note_pressure;
700                event.Param.NotePressure.Key     = Key;
701                event.Param.NotePressure.Value   = Value;
702                event.Param.NotePressure.Channel = MidiChannel;
703                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
704                event.pEngineChannel             = this;
705                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
706                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
707            }
708        }
709    
710      /**      /**
711       * 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
712       * 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 751  namespace LinuxSampler {
751                              event.Param.Note.Channel  = channel;                              event.Param.Note.Channel  = channel;
752                              break;                              break;
753                          case VirtualMidiDevice::EVENT_TYPE_CC:                          case VirtualMidiDevice::EVENT_TYPE_CC:
754                              event.Type = Event::type_control_change;                              switch (devEvent.Arg1) {
755                              event.Param.CC.Controller = devEvent.Arg1;                                  case 0: // bank select MSB ...
756                              event.Param.CC.Value      = devEvent.Arg2;                                      SetMidiBankMsb(devEvent.Arg2);
757                              event.Param.CC.Channel    = channel;                                      continue; // don't push this event into FIFO
758                                    case 32: // bank select LSB ...
759                                        SetMidiBankLsb(devEvent.Arg2);
760                                        continue; // don't push this event into FIFO
761                                    default: // regular MIDI CC ...
762                                        event.Type = Event::type_control_change;
763                                        event.Param.CC.Controller = devEvent.Arg1;
764                                        event.Param.CC.Value      = devEvent.Arg2;
765                                        event.Param.CC.Channel    = channel;
766                                }
767                                break;
768                            case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
769                                event.Type = Event::type_pitchbend;
770                                event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
771                                event.Param.Pitch.Channel = channel;
772                              break;                              break;
773                            case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
774                                SendProgramChange(devEvent.Arg1);
775                                continue; // don't push this event into FIFO
776                          default:                          default:
777                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
778                                        << devEvent.Type << "). This is a bug!";                                        << devEvent.Type << "). This is a bug!";
779                              continue;                              continue;
780                      }                      }
781                        memset(&event.Format, 0, sizeof(event.Format)); // init format specific stuff with zeroes
782                      event.pEngineChannel = this;                      event.pEngineChannel = this;
783                      // copy event to internal event list                      // copy event to internal event list
784                      if (pEvents->poolIsEmpty()) {                      if (pEvents->poolIsEmpty()) {
# Line 598  namespace LinuxSampler { Line 815  namespace LinuxSampler {
815          eventQueueReader.free(); // free all copied events from input queue          eventQueueReader.free(); // free all copied events from input queue
816      }      }
817    
818        /**
819         * Called by real-time instrument script functions to schedule a new event
820         * @a delay microseconds in future.
821         *
822         * @b IMPORTANT: for the supplied @a delay to be scheduled correctly, the
823         * passed @a pEvent must be assigned a valid fragment time within the
824         * current audio fragment boundaries. That fragment time will be used by
825         * this method as basis for interpreting what "now" acutally is, and thus
826         * it will be used as basis for calculating the precise scheduling time
827         * for @a delay. The easiest way to achieve this is by copying a recent
828         * event which happened within the current audio fragment cycle: i.e. the
829         * original event which caused calling this method here.
830         *
831         * @param pEvent - event to be scheduled in future (event data will be copied)
832         * @param delay - amount of microseconds in future (from now) when event shall be processed
833         * @returns unique event ID of scheduled new event, or a negative number on error
834         */
835        int AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int delay) {
836            dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%d)\n", pEvent->Type, delay));
837            RTList<Event>::Iterator itEvent = pEvents->allocAppend();
838            if (!itEvent) {
839                dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n"));
840                return -1;
841            }
842            RTList<ScheduledEvent>::Iterator itNode = delayedEvents.schedulerNodes.allocAppend();
843            if (!itNode) { // scheduler node pool empty ...
844                dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): ScheduledEvent pool empty!\n"));
845                pEvents->free(itEvent);
846                return -1;
847            }
848            // copy passed event
849            *itEvent = *pEvent;
850            // move copied event to list of delayed events
851            itEvent = itEvent.moveToEndOf(delayedEvents.pList);
852            // connect scheduler node with the copied event
853            itNode->itEvent = itEvent;
854            // add entry to time sorted scheduler queue for copied event
855            pEngine->pEventGenerator->scheduleAheadMicroSec(
856                delayedEvents.queue, *itNode, itEvent->FragmentPos(), delay
857            );
858            //dmsg(5,("ScheduledEvent queue size: %d\n", delayedEvents.queue.size()));
859            return pEvents->getID(itEvent);
860        }
861    
862        /**
863         * Called by real-time instrument script functions to ignore the event
864         * reflected by given event ID. The event will be freed immediately to its
865         * pool and cannot be dereferenced by its old ID anymore. Even if its
866         * allocated back from the Pool later on, it will have a different ID.
867         */
868        void AbstractEngineChannel::IgnoreEvent(int id) {
869            RTList<Event>::Iterator it = pEvents->fromID(id);
870            if (it) pEvents->free(it);
871        }
872    
873      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
874          if (pEngine) pEngine->DisableAndLock();          if (pEngine) pEngine->DisableAndLock();
875          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);

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

  ViewVC Help
Powered by ViewVC