/[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 2114 by persson, Tue Aug 10 12:05:19 2010 UTC revision 3054 by schoenebeck, Thu Dec 15 12:47:45 2016 UTC
# Line 4  Line 4 
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-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2010 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 112  namespace LinuxSampler { Line 114  namespace LinuxSampler {
114          Pitch          = 0;          Pitch          = 0;
115          GlobalVolume   = 1.0f;          GlobalVolume   = 1.0f;
116          MidiVolume     = 1.0;          MidiVolume     = 1.0;
         GlobalPanLeft  = 1.0f;  
         GlobalPanRight = 1.0f;  
117          iLastPanRequest = 64;          iLastPanRequest = 64;
118          GlobalTranspose = 0;          GlobalTranspose = 0;
119          // set all MIDI controller values to zero          // set all MIDI controller values to zero
# Line 130  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 182  namespace LinuxSampler { Line 188  namespace LinuxSampler {
188          int iMidiPan = int(f * 64.0f) + 64;          int iMidiPan = int(f * 64.0f) + 64;
189          if (iMidiPan > 127) iMidiPan = 127;          if (iMidiPan > 127) iMidiPan = 127;
190          else if (iMidiPan < 0) iMidiPan = 0;          else if (iMidiPan < 0) iMidiPan = 0;
         GlobalPanLeft  = AbstractEngine::PanCurve[128 - iMidiPan];  
         GlobalPanRight = AbstractEngine::PanCurve[iMidiPan];  
191          iLastPanRequest = iMidiPan;          iLastPanRequest = iMidiPan;
192      }      }
193    
# Line 191  namespace LinuxSampler { Line 195  namespace LinuxSampler {
195          return (pEngine) ? pEngine->pAudioOutputDevice : NULL;          return (pEngine) ? pEngine->pAudioOutputDevice : NULL;
196      }      }
197    
198        /**
199         * Gets thread safe access to the currently connected audio output
200         * device from other threads than the lscp thread.
201         */
202        AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {
203            LockGuard lock(EngineMutex);
204            return GetAudioOutputDevice();
205        }
206    
207      void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {      void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
208          if (!pEngine || !pEngine->pAudioOutputDevice) throw AudioOutputException("No audio output device connected yet.");          if (!pEngine || !pEngine->pAudioOutputDevice) throw AudioOutputException("No audio output device connected yet.");
209    
# Line 223  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 278  namespace LinuxSampler { Line 372  namespace LinuxSampler {
372       *  @param Key      - MIDI key number of the triggered key       *  @param Key      - MIDI key number of the triggered key
373       *  @param Velocity - MIDI velocity value of the triggered key       *  @param Velocity - MIDI velocity value of the triggered key
374       */       */
375      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity) {      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;
386              event.pEngineChannel      = this;              event.pEngineChannel      = this;
387              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
388              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 311  namespace LinuxSampler { Line 410  namespace LinuxSampler {
410       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
411       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
412       */       */
413      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) {
414          if (FragmentPos < 0) {          if (FragmentPos < 0) {
415              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
416          }          }
417          else if (pEngine) {          else if (pEngine) {
418                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
419                LockGuard g;
420                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
421    
422              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
423              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
424              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
425              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
426                event.Param.Note.Channel  = MidiChannel;
427              event.pEngineChannel      = this;              event.pEngineChannel      = this;
428              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
429              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 345  namespace LinuxSampler { Line 449  namespace LinuxSampler {
449       *  @param Key      - MIDI key number of the released key       *  @param Key      - MIDI key number of the released key
450       *  @param Velocity - MIDI release velocity value of the released key       *  @param Velocity - MIDI release velocity value of the released key
451       */       */
452      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity) {      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
453          if (pEngine) {          if (pEngine) {
454                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
455                LockGuard g;
456                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
457    
458              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
459              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
460              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
461              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
462                event.Param.Note.Channel  = MidiChannel;
463              event.pEngineChannel      = this;              event.pEngineChannel      = this;
464              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
465              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 378  namespace LinuxSampler { Line 487  namespace LinuxSampler {
487       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
488       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
489       */       */
490      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) {
491          if (FragmentPos < 0) {          if (FragmentPos < 0) {
492              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
493          }          }
494          else if (pEngine) {          else if (pEngine) {
495                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
496                LockGuard g;
497                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
498    
499              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
500              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
501              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
502              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
503                event.Param.Note.Channel  = MidiChannel;
504              event.pEngineChannel      = this;              event.pEngineChannel      = this;
505              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
506              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 411  namespace LinuxSampler { Line 525  namespace LinuxSampler {
525       *       *
526       *  @param Pitch - MIDI pitch value (-8192 ... +8191)       *  @param Pitch - MIDI pitch value (-8192 ... +8191)
527       */       */
528      void AbstractEngineChannel::SendPitchbend(int Pitch) {      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
529          if (pEngine) {          if (pEngine) {
530                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
531                LockGuard g;
532                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
533    
534              Event event             = pEngine->pEventGenerator->CreateEvent();              Event event             = pEngine->pEventGenerator->CreateEvent();
535              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
536              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
537                event.Param.Pitch.Channel = MidiChannel;
538              event.pEngineChannel    = this;              event.pEngineChannel    = this;
539              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
540              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 432  namespace LinuxSampler { Line 551  namespace LinuxSampler {
551       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
552       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
553       */       */
554      void AbstractEngineChannel::SendPitchbend(int Pitch, int32_t FragmentPos) {      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel, int32_t FragmentPos) {
555          if (FragmentPos < 0) {          if (FragmentPos < 0) {
556              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
557          }          }
558          else if (pEngine) {          else if (pEngine) {
559                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
560                LockGuard g;
561                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
562    
563              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);
564              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
565              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
566                event.Param.Pitch.Channel = MidiChannel;
567              event.pEngineChannel    = this;              event.pEngineChannel    = this;
568              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
569              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 455  namespace LinuxSampler { Line 579  namespace LinuxSampler {
579       *  @param Controller - MIDI controller number of the occured control change       *  @param Controller - MIDI controller number of the occured control change
580       *  @param Value      - value of the control change       *  @param Value      - value of the control change
581       */       */
582      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value) {      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {
583          if (pEngine) {          if (pEngine) {
584                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
585                LockGuard g;
586                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
587    
588              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
589              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
590              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
591              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
592                event.Param.CC.Channel    = MidiChannel;
593              event.pEngineChannel      = this;              event.pEngineChannel      = this;
594              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
595              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 478  namespace LinuxSampler { Line 607  namespace LinuxSampler {
607       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
608       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
609       */       */
610      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) {
611          if (FragmentPos < 0) {          if (FragmentPos < 0) {
612              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
613          }          }
614          else if (pEngine) {          else if (pEngine) {
615                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
616                LockGuard g;
617                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
618    
619              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
620              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
621              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
622              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
623                event.Param.CC.Channel    = MidiChannel;
624              event.pEngineChannel      = this;              event.pEngineChannel      = this;
625              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
626              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
627          }          }
628      }      }
629    
630        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel) {
631            if (pEngine) {
632                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
633                LockGuard g;
634                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
635    
636                Event event = pEngine->pEventGenerator->CreateEvent();
637                event.Type                          = Event::type_channel_pressure;
638                event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
639                event.Param.ChannelPressure.Value   = Value;
640                event.Param.ChannelPressure.Channel = MidiChannel;
641                event.pEngineChannel                = this;
642                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
643                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
644            }
645        }
646    
647        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
648            if (pEngine) {
649                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
650                LockGuard g;
651                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
652    
653                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
654                event.Type                          = Event::type_channel_pressure;
655                event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
656                event.Param.ChannelPressure.Value   = Value;
657                event.Param.ChannelPressure.Channel = MidiChannel;
658                event.pEngineChannel                = this;
659                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
660                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
661            }
662        }
663    
664        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel) {
665            if (pEngine) {
666                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
667                LockGuard g;
668                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
669    
670                Event event = pEngine->pEventGenerator->CreateEvent();
671                event.Type                       = Event::type_note_pressure;
672                event.Param.NotePressure.Key     = Key;
673                event.Param.NotePressure.Value   = Value;
674                event.Param.NotePressure.Channel = MidiChannel;
675                event.pEngineChannel             = this;
676                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
677                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
678            }
679        }
680    
681        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
682            if (pEngine) {
683                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
684                LockGuard g;
685                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
686    
687                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
688                event.Type                       = Event::type_note_pressure;
689                event.Param.NotePressure.Key     = Key;
690                event.Param.NotePressure.Value   = Value;
691                event.Param.NotePressure.Channel = MidiChannel;
692                event.pEngineChannel             = this;
693                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
694                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
695            }
696        }
697    
698        bool AbstractEngineChannel::applyTranspose(Event* event) {
699            if (event->Type != Event::type_note_on && event->Type != Event::type_note_off)
700                return true; // event OK (not a note event, nothing to do with it here)
701    
702            //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing
703            const int k = event->Param.Note.Key + GlobalTranspose;
704            if (k < 0 || k > 127)
705                return false; // bad event, drop it
706    
707            event->Param.Note.Key = k;
708    
709            return true; // event OK
710        }
711    
712      /**      /**
713       * 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
714       * 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 726  namespace LinuxSampler {
726          // import events from pure software MIDI "devices"          // import events from pure software MIDI "devices"
727          // (e.g. virtual keyboard in instrument editor)          // (e.g. virtual keyboard in instrument editor)
728          {          {
729                const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
730              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
731              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
732              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 744  namespace LinuxSampler {
744                              event.Type = Event::type_note_on;                              event.Type = Event::type_note_on;
745                              event.Param.Note.Key      = devEvent.Arg1;                              event.Param.Note.Key      = devEvent.Arg1;
746                              event.Param.Note.Velocity = devEvent.Arg2;                              event.Param.Note.Velocity = devEvent.Arg2;
747                                event.Param.Note.Channel  = channel;
748                                // apply transpose setting to (note on/off) event
749                                if (!applyTranspose(&event))
750                                    continue; // note value is out of range, so drop this event
751                                // assign a new note to this note-on event
752                                if (!pEngine->LaunchNewNote(this, &event))
753                                    continue; // failed launching new note, so drop this event
754                              break;                              break;
755                          case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:                          case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
756                              event.Type = Event::type_note_off;                              event.Type = Event::type_note_off;
757                              event.Param.Note.Key      = devEvent.Arg1;                              event.Param.Note.Key      = devEvent.Arg1;
758                              event.Param.Note.Velocity = devEvent.Arg2;                              event.Param.Note.Velocity = devEvent.Arg2;
759                                event.Param.Note.Channel  = channel;
760                                if (!applyTranspose(&event))
761                                    continue; // note value is out of range, so drop this event
762                              break;                              break;
763                          case VirtualMidiDevice::EVENT_TYPE_CC:                          case VirtualMidiDevice::EVENT_TYPE_CC:
764                              event.Type = Event::type_control_change;                              switch (devEvent.Arg1) {
765                              event.Param.CC.Controller = devEvent.Arg1;                                  case 0: // bank select MSB ...
766                              event.Param.CC.Value      = devEvent.Arg2;                                      SetMidiBankMsb(devEvent.Arg2);
767                                        continue; // don't push this event into FIFO
768                                    case 32: // bank select LSB ...
769                                        SetMidiBankLsb(devEvent.Arg2);
770                                        continue; // don't push this event into FIFO
771                                    default: // regular MIDI CC ...
772                                        event.Type = Event::type_control_change;
773                                        event.Param.CC.Controller = devEvent.Arg1;
774                                        event.Param.CC.Value      = devEvent.Arg2;
775                                        event.Param.CC.Channel    = channel;
776                                }
777                                break;
778                            case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
779                                event.Type = Event::type_pitchbend;
780                                event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
781                                event.Param.Pitch.Channel = channel;
782                                break;
783                            case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
784                                SendProgramChange(devEvent.Arg1);
785                                continue; // don't push this event into FIFO
786                            case VirtualMidiDevice::EVENT_TYPE_CHPRESSURE:
787                                event.Type = Event::type_channel_pressure;
788                                event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH;
789                                event.Param.ChannelPressure.Value   = devEvent.Arg2;
790                                event.Param.ChannelPressure.Channel = channel;
791                              break;                              break;
792                          default:                          default:
793                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
# Line 569  namespace LinuxSampler { Line 820  namespace LinuxSampler {
820                  pEvent->ResetFragmentPos();                  pEvent->ResetFragmentPos();
821                  break;                  break;
822              }              }
             // copy event to internal event list  
823              if (pEvents->poolIsEmpty()) {              if (pEvents->poolIsEmpty()) {
824                  dmsg(1,("Event pool emtpy!\n"));                  dmsg(1,("Event pool emtpy!\n"));
825                  break;                  break;
826              }              }
827                // apply transpose setting to (note on/off) event
828                if (!applyTranspose(pEvent))
829                    continue; // it's a note event which has a note value out of range, so drop this event
830                // assign a new note to this event (if its a note-on event)
831                if (pEvent->Type == Event::type_note_on)
832                    if (!pEngine->LaunchNewNote(this, pEvent))
833                        continue; // failed launching new note, so drop this event
834                // copy event to internal event list
835              *pEvents->allocAppend() = *pEvent;              *pEvents->allocAppend() = *pEvent;
836          }          }
837          eventQueueReader.free(); // free all copied events from input queue          eventQueueReader.free(); // free all copied events from input queue
838      }      }
839    
840        /**
841         * Called by real-time instrument script functions to schedule a new event
842         * @a delay microseconds in future.
843         *
844         * @b IMPORTANT: for the supplied @a delay to be scheduled correctly, the
845         * passed @a pEvent must be assigned a valid fragment time within the
846         * current audio fragment boundaries. That fragment time will be used by
847         * this method as basis for interpreting what "now" acutally is, and thus
848         * it will be used as basis for calculating the precise scheduling time
849         * for @a delay. The easiest way to achieve this is by copying a recent
850         * event which happened within the current audio fragment cycle: i.e. the
851         * original event which caused calling this method here.
852         *
853         * @param pEvent - event to be scheduled in future (event data will be copied)
854         * @param delay - amount of microseconds in future (from now) when event shall be processed
855         * @returns unique event ID of scheduled new event, or NULL on error
856         */
857        event_id_t AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int delay) {
858            dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%d)\n", pEvent->Type, delay));
859            RTList<Event>::Iterator itEvent = pEvents->allocAppend();
860            if (!itEvent) {
861                dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n"));
862                return 0;
863            }
864            RTList<ScheduledEvent>::Iterator itNode = delayedEvents.schedulerNodes.allocAppend();
865            if (!itNode) { // scheduler node pool empty ...
866                dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): ScheduledEvent pool empty!\n"));
867                pEvents->free(itEvent);
868                return 0;
869            }
870            // copy passed event
871            *itEvent = *pEvent;
872            // move copied event to list of delayed events
873            itEvent = itEvent.moveToEndOf(delayedEvents.pList);
874            // connect scheduler node with the copied event
875            itNode->itEvent = itEvent;
876            // add entry to time sorted scheduler queue for copied event
877            pEngine->pEventGenerator->scheduleAheadMicroSec(
878                delayedEvents.queue, *itNode, itEvent->FragmentPos(), delay
879            );
880            //dmsg(5,("ScheduledEvent queue size: %d\n", delayedEvents.queue.size()));
881            return pEvents->getID(itEvent);
882        }
883    
884        /**
885         * Called by real-time instrument script functions to ignore the event
886         * reflected by given event ID. The event will be freed immediately to its
887         * pool and cannot be dereferenced by its old ID anymore. Even if its
888         * allocated back from the Pool later on, it will have a different ID.
889         *
890         * @param id - unique ID of event to be dropped
891         */
892        void AbstractEngineChannel::IgnoreEvent(event_id_t id) {
893            RTList<Event>::Iterator it = pEvents->fromID(id);
894            if (it) pEvents->free(it);
895        }
896    
897        /** @brief Drop the requested event.
898         *
899         * Called by real-time instrument script functions to ignore the event
900         * reflected by the given event @a id. This method detects whether the
901         * passed ID is actually a @c Note ID or a regular @c Event ID and act
902         * accordingly.
903         *
904         * @param id - event id (from script scope)
905         * @see ScriptID
906         */
907        void AbstractEngineChannel::IgnoreEventByScriptID(const ScriptID& id) {
908            switch (id.type()) {
909                case ScriptID::EVENT:
910                    IgnoreEvent( id.eventID() );
911                    break;
912                case ScriptID::NOTE:
913                    IgnoreNote( id.noteID() );
914                    break;
915            }
916        }
917    
918        /** @brief Order resuming of script execution instance "now".
919         *
920         * Called by real-time instrument script function stop_wait() to resume a
921         * script callback currently being suspended (i.e. due to a wait() script
922         * function call).
923         *
924         * @param itCallback - suspended script callback to be resumed
925         * @param now - current scheduler time to be "now"
926         * @param forever - whether this particulare script callback should ignore
927         *                  all subsequent wait*() script function calls
928         */
929        void AbstractEngineChannel::ScheduleResumeOfScriptCallback(RTList<ScriptEvent>::Iterator& itCallback, sched_time_t now, bool forever) {
930            // ignore if invalid iterator was passed
931            if (!itCallback) return;
932    
933            ScriptEvent* pCallback = &*itCallback;
934    
935            // mark this callback to ignore all subsequent built-in wait*() script function calls
936            if (forever) pCallback->ignoreAllWaitCalls = true;
937    
938            // ignore if callback is not in the scheduler queue
939            if (pCallback->currentSchedulerQueue() != &pScript->suspendedEvents) return;
940    
941            // ignore if callback is already scheduled to be resumed "now"
942            if (pCallback->scheduleTime <= now) return;
943    
944            // take it out from the scheduler queue and re-insert callback
945            // to schedule the script callback for resuming execution "now"
946            pScript->suspendedEvents.erase(*pCallback);
947            pCallback->scheduleTime = now + 1;
948            pScript->suspendedEvents.insert(*pCallback);
949        }
950    
951      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
952          if (pEngine) pEngine->DisableAndLock();          if (pEngine) pEngine->DisableAndLock();
953          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
# Line 606  namespace LinuxSampler { Line 975  namespace LinuxSampler {
975      }      }
976    
977      uint AbstractEngineChannel::GetFxSendCount() {      uint AbstractEngineChannel::GetFxSendCount() {
978          return fxSends.size();          return (uint)fxSends.size();
979      }      }
980    
981      void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {      void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) {
# Line 668  namespace LinuxSampler { Line 1037  namespace LinuxSampler {
1037       */       */
1038      void AbstractEngineChannel::AddGroup(uint group) {      void AbstractEngineChannel::AddGroup(uint group) {
1039          if (group) {          if (group) {
1040              typedef std::map<uint, RTList<Event>*> map_t;              std::pair<ActiveKeyGroupMap::iterator, bool> p =
1041                    ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
             std::pair<map_t::iterator, bool> p =  
                 ActiveKeyGroups.insert(map_t::value_type(group, 0));  
1042              if (p.second) {              if (p.second) {
1043                  (*p.first).second = new RTList<Event>(pEngine->pEventPool);                  // If the engine channel is pending deletion (see bug
1044                    // #113), pEngine will be null, so we can't use
1045                    // pEngine->pEventPool here. Instead we're using a
1046                    // specialized RTList that allows specifying the pool
1047                    // later.
1048                    (*p.first).second = new LazyList<Event>;
1049              }              }
1050          }          }
1051      }      }
# Line 685  namespace LinuxSampler { Line 1057  namespace LinuxSampler {
1057          dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));          dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
1058          if (KeyGroup) {          if (KeyGroup) {
1059              // send a release event to all active voices in the group              // send a release event to all active voices in the group
1060              RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend();              RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
1061              *itEvent = *itNoteOnEvent;              *itEvent = *itNoteOnEvent;
1062          }          }
1063      }      }
# Line 695  namespace LinuxSampler { Line 1067  namespace LinuxSampler {
1067       * audio thread, after all voices have been rendered.       * audio thread, after all voices have been rendered.
1068       */       */
1069      void AbstractEngineChannel::ClearGroupEventLists() {      void AbstractEngineChannel::ClearGroupEventLists() {
1070          for (std::map<uint,RTList<Event>*>::iterator iter = ActiveKeyGroups.begin();          for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
1071               iter != ActiveKeyGroups.end(); iter++) {               iter != ActiveKeyGroups.end(); iter++) {
1072              if (iter->second) {              if (iter->second) {
1073                  iter->second->clear();                  iter->second->clear();
# Line 709  namespace LinuxSampler { Line 1081  namespace LinuxSampler {
1081       * Remove all lists with group events.       * Remove all lists with group events.
1082       */       */
1083      void AbstractEngineChannel::DeleteGroupEventLists() {      void AbstractEngineChannel::DeleteGroupEventLists() {
1084          for (std::map<uint,RTList<Event>*>::iterator iter = ActiveKeyGroups.begin();          for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
1085               iter != ActiveKeyGroups.end(); iter++) {               iter != ActiveKeyGroups.end(); iter++) {
1086              delete iter->second;              delete iter->second;
1087          }          }

Legend:
Removed from v.2114  
changed lines
  Added in v.3054

  ViewVC Help
Powered by ViewVC