/[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 2612 by schoenebeck, Tue Jun 10 13:32:16 2014 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) 2013-2014 Christian Schoenebeck and Andreas Persson     *
9   *                                                                         *   *                                                                         *
10   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
11   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 41  namespace LinuxSampler { Line 42  namespace LinuxSampler {
42          pChannelRight = NULL;          pChannelRight = NULL;
43          AudioDeviceChannelLeft  = -1;          AudioDeviceChannelLeft  = -1;
44          AudioDeviceChannelRight = -1;          AudioDeviceChannelRight = -1;
         pMidiInputPort = NULL;  
45          midiChannel = midi_chan_all;          midiChannel = midi_chan_all;
46          ResetControllers();          ResetControllers();
47          PortamentoMode = false;          PortamentoMode = false;
48          PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;          PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT;
49            pScript = NULL;
50      }      }
51    
52      AbstractEngineChannel::~AbstractEngineChannel() {      AbstractEngineChannel::~AbstractEngineChannel() {
53            if (pScript) pScript->resetAll(); // unloads script (in case one is loaded)
54          delete pEventQueue;          delete pEventQueue;
55          DeleteGroupEventLists();          DeleteGroupEventLists();
56          RemoveAllFxSends();          RemoveAllFxSends();
# 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 182  namespace LinuxSampler { Line 182  namespace LinuxSampler {
182          int iMidiPan = int(f * 64.0f) + 64;          int iMidiPan = int(f * 64.0f) + 64;
183          if (iMidiPan > 127) iMidiPan = 127;          if (iMidiPan > 127) iMidiPan = 127;
184          else if (iMidiPan < 0) iMidiPan = 0;          else if (iMidiPan < 0) iMidiPan = 0;
         GlobalPanLeft  = AbstractEngine::PanCurve[128 - iMidiPan];  
         GlobalPanRight = AbstractEngine::PanCurve[iMidiPan];  
185          iLastPanRequest = iMidiPan;          iLastPanRequest = iMidiPan;
186      }      }
187    
# Line 191  namespace LinuxSampler { Line 189  namespace LinuxSampler {
189          return (pEngine) ? pEngine->pAudioOutputDevice : NULL;          return (pEngine) ? pEngine->pAudioOutputDevice : NULL;
190      }      }
191    
192        /**
193         * Gets thread safe access to the currently connected audio output
194         * device from other threads than the lscp thread.
195         */
196        AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {
197            LockGuard lock(EngineMutex);
198            return GetAudioOutputDevice();
199        }
200    
201      void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {      void AbstractEngineChannel::SetOutputChannel(uint EngineAudioChannel, uint AudioDeviceChannel) {
202          if (!pEngine || !pEngine->pAudioOutputDevice) throw AudioOutputException("No audio output device connected yet.");          if (!pEngine || !pEngine->pAudioOutputDevice) throw AudioOutputException("No audio output device connected yet.");
203    
# Line 223  namespace LinuxSampler { Line 230  namespace LinuxSampler {
230          }          }
231      }      }
232    
233        void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort) {
234            if (!pMidiPort) return;
235    
236            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
237    
238            // check if connection already exists
239            for (int i = 0; i < connections->size(); ++i)
240                if ((*connections)[i] == pMidiPort)
241                    return; // to avoid endless recursion
242    
243            connections->add(pMidiPort);
244    
245            // inform MIDI port about this new connection
246            pMidiPort->Connect(this, MidiChannel());
247        }
248    
249        void AbstractEngineChannel::Disconnect(MidiInputPort* pMidiPort) {
250            if (!pMidiPort) return;
251    
252            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
253    
254            for (int i = 0; i < connections->size(); ++i) {
255                if ((*connections)[i] == pMidiPort) {
256                    connections->remove(i);
257                    // inform MIDI port about this disconnection
258                    pMidiPort->Disconnect(this);
259                    return;
260                }
261            }
262        }
263    
264        void AbstractEngineChannel::DisconnectAllMidiInputPorts() {
265            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
266            ArrayList<MidiInputPort*> clonedList = *connections;
267            connections->clear();
268            for (int i = 0; i < clonedList.size(); ++i) clonedList[i]->Disconnect(this);
269        }
270    
271        uint AbstractEngineChannel::GetMidiInputPortCount() {
272            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
273            return connections->size();
274        }
275    
276        MidiInputPort* AbstractEngineChannel::GetMidiInputPort(uint index) {
277            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
278            return (index < connections->size()) ? (*connections)[index] : NULL;
279        }
280    
281        // deprecated (just for API backward compatibility) - may be removed in future
282      void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {      void AbstractEngineChannel::Connect(MidiInputPort* pMidiPort, midi_chan_t MidiChannel) {
283          if (!pMidiPort || pMidiPort == this->pMidiInputPort) return;          if (!pMidiPort) return;
284          DisconnectMidiInputPort();  
285          this->pMidiInputPort = pMidiPort;          Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
286          this->midiChannel    = MidiChannel;  
287            // check against endless recursion
288            if (connections->size() == 1 && (*connections)[0] == pMidiPort && this->midiChannel == MidiChannel)
289                return;
290            
291            if (!isValidMidiChan(MidiChannel))
292                throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
293    
294            this->midiChannel = MidiChannel;
295    
296            // disconnect all currently connected MIDI ports
297            ArrayList<MidiInputPort*> clonedList = *connections;
298            connections->clear();
299            for (int i = 0; i < clonedList.size(); ++i)
300                clonedList[i]->Disconnect(this);
301    
302            // connect the new port
303            connections->add(pMidiPort);
304          pMidiPort->Connect(this, MidiChannel);          pMidiPort->Connect(this, MidiChannel);
305      }      }
306    
307        // deprecated (just for API backward compatibility) - may be removed in future
308      void AbstractEngineChannel::DisconnectMidiInputPort() {      void AbstractEngineChannel::DisconnectMidiInputPort() {
309          MidiInputPort* pOldPort = this->pMidiInputPort;          DisconnectAllMidiInputPorts();
         this->pMidiInputPort = NULL;  
         if (pOldPort) pOldPort->Disconnect(this);  
310      }      }
311    
312        // deprecated (just for API backward compatibility) - may be removed in future
313      MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {      MidiInputPort* AbstractEngineChannel::GetMidiInputPort() {
314          return pMidiInputPort;          return GetMidiInputPort(0);
315      }      }
316    
317      midi_chan_t AbstractEngineChannel::MidiChannel() {      midi_chan_t AbstractEngineChannel::MidiChannel() {
318          return midiChannel;          return midiChannel;
319      }      }
320    
321        void AbstractEngineChannel::SetMidiChannel(midi_chan_t MidiChannel) {
322            if (this->midiChannel == MidiChannel) return;
323            if (!isValidMidiChan(MidiChannel))
324                throw MidiInputException("Invalid MIDI channel (" + ToString(int(MidiChannel)) + ")");
325    
326            this->midiChannel = MidiChannel;
327            
328            Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back();
329            ArrayList<MidiInputPort*> clonedList = *connections;
330    
331            DisconnectAllMidiInputPorts();
332    
333            for (int i = 0; i < clonedList.size(); ++i) Connect(clonedList[i]);
334        }
335    
336      void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {      void AbstractEngineChannel::Connect(VirtualMidiDevice* pDevice) {
337          // double buffer ... double work ...          // double buffer ... double work ...
338          {          {
# Line 278  namespace LinuxSampler { Line 366  namespace LinuxSampler {
366       *  @param Key      - MIDI key number of the triggered key       *  @param Key      - MIDI key number of the triggered key
367       *  @param Velocity - MIDI velocity value of the triggered key       *  @param Velocity - MIDI velocity value of the triggered key
368       */       */
369      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity) {      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
370          if (pEngine) {          if (pEngine) {
371                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
372                LockGuard g;
373                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
374    
375              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
376              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
377              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
378              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
379                event.Param.Note.Channel  = MidiChannel;
380                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
381              event.pEngineChannel      = this;              event.pEngineChannel      = this;
382              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
383              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 311  namespace LinuxSampler { Line 405  namespace LinuxSampler {
405       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
406       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
407       */       */
408      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) {
409          if (FragmentPos < 0) {          if (FragmentPos < 0) {
410              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
411          }          }
412          else if (pEngine) {          else if (pEngine) {
413                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
414                LockGuard g;
415                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
416    
417              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
418              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
419              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
420              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
421                event.Param.Note.Channel  = MidiChannel;
422                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
423              event.pEngineChannel      = this;              event.pEngineChannel      = this;
424              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
425              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 345  namespace LinuxSampler { Line 445  namespace LinuxSampler {
445       *  @param Key      - MIDI key number of the released key       *  @param Key      - MIDI key number of the released key
446       *  @param Velocity - MIDI release velocity value of the released key       *  @param Velocity - MIDI release velocity value of the released key
447       */       */
448      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity) {      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
449          if (pEngine) {          if (pEngine) {
450                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
451                LockGuard g;
452                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
453    
454              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
455              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
456              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
457              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
458                event.Param.Note.Channel  = MidiChannel;
459                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
460              event.pEngineChannel      = this;              event.pEngineChannel      = this;
461              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
462              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 378  namespace LinuxSampler { Line 484  namespace LinuxSampler {
484       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
485       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
486       */       */
487      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) {
488          if (FragmentPos < 0) {          if (FragmentPos < 0) {
489              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
490          }          }
491          else if (pEngine) {          else if (pEngine) {
492                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
493                LockGuard g;
494                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
495    
496              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
497              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
498              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
499              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
500                event.Param.Note.Channel  = MidiChannel;
501                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
502              event.pEngineChannel      = this;              event.pEngineChannel      = this;
503              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
504              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 411  namespace LinuxSampler { Line 523  namespace LinuxSampler {
523       *       *
524       *  @param Pitch - MIDI pitch value (-8192 ... +8191)       *  @param Pitch - MIDI pitch value (-8192 ... +8191)
525       */       */
526      void AbstractEngineChannel::SendPitchbend(int Pitch) {      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
527          if (pEngine) {          if (pEngine) {
528                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
529                LockGuard g;
530                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
531    
532              Event event             = pEngine->pEventGenerator->CreateEvent();              Event event             = pEngine->pEventGenerator->CreateEvent();
533              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
534              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
535                event.Param.Pitch.Channel = MidiChannel;
536                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
537              event.pEngineChannel    = this;              event.pEngineChannel    = this;
538              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
539              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 432  namespace LinuxSampler { Line 550  namespace LinuxSampler {
550       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
551       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
552       */       */
553      void AbstractEngineChannel::SendPitchbend(int Pitch, int32_t FragmentPos) {      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel, int32_t FragmentPos) {
554          if (FragmentPos < 0) {          if (FragmentPos < 0) {
555              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
556          }          }
557          else if (pEngine) {          else if (pEngine) {
558                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
559                LockGuard g;
560                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
561    
562              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);
563              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
564              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
565                event.Param.Pitch.Channel = MidiChannel;
566                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
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                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
594              event.pEngineChannel      = this;              event.pEngineChannel      = this;
595              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
596              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 478  namespace LinuxSampler { Line 608  namespace LinuxSampler {
608       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
609       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
610       */       */
611      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) {
612          if (FragmentPos < 0) {          if (FragmentPos < 0) {
613              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
614          }          }
615          else if (pEngine) {          else if (pEngine) {
616                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
617                LockGuard g;
618                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
619    
620              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event               = pEngine->pEventGenerator->CreateEvent(FragmentPos);
621              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
622              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
623              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
624                event.Param.CC.Channel    = MidiChannel;
625                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
626              event.pEngineChannel      = this;              event.pEngineChannel      = this;
627              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
628              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
629          }          }
630      }      }
631    
632        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel) {
633            if (pEngine) {
634                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
635                LockGuard g;
636                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
637    
638                Event event = pEngine->pEventGenerator->CreateEvent();
639                event.Type                          = Event::type_channel_pressure;
640                event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
641                event.Param.ChannelPressure.Value   = Value;
642                event.Param.ChannelPressure.Channel = MidiChannel;
643                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
644                event.pEngineChannel                = this;
645                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
646                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
647            }
648        }
649    
650        void AbstractEngineChannel::SendChannelPressure(uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
651            if (pEngine) {
652                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
653                LockGuard g;
654                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
655    
656                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
657                event.Type                          = Event::type_channel_pressure;
658                event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts
659                event.Param.ChannelPressure.Value   = Value;
660                event.Param.ChannelPressure.Channel = MidiChannel;
661                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
662                event.pEngineChannel                = this;
663                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
664                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
665            }
666        }
667    
668        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel) {
669            if (pEngine) {
670                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
671                LockGuard g;
672                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
673    
674                Event event = pEngine->pEventGenerator->CreateEvent();
675                event.Type                       = Event::type_note_pressure;
676                event.Param.NotePressure.Key     = Key;
677                event.Param.NotePressure.Value   = Value;
678                event.Param.NotePressure.Channel = MidiChannel;
679                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
680                event.pEngineChannel             = this;
681                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
682                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
683            }
684        }
685    
686        void AbstractEngineChannel::SendPolyphonicKeyPressure(uint8_t Key, uint8_t Value, uint8_t MidiChannel, int32_t FragmentPos) {
687            if (pEngine) {
688                // protection in case there are more than 1 MIDI input threads sending MIDI events to this EngineChannel
689                LockGuard g;
690                if (hasMultipleMIDIInputs()) g = LockGuard(MidiInputMutex);
691    
692                Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
693                event.Type                       = Event::type_note_pressure;
694                event.Param.NotePressure.Key     = Key;
695                event.Param.NotePressure.Value   = Value;
696                event.Param.NotePressure.Channel = MidiChannel;
697                memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes
698                event.pEngineChannel             = this;
699                if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
700                else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
701            }
702        }
703    
704      /**      /**
705       * 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
706       * 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 718  namespace LinuxSampler {
718          // import events from pure software MIDI "devices"          // import events from pure software MIDI "devices"
719          // (e.g. virtual keyboard in instrument editor)          // (e.g. virtual keyboard in instrument editor)
720          {          {
721                const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
722              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
723              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
724              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 736  namespace LinuxSampler {
736                              event.Type = Event::type_note_on;                              event.Type = Event::type_note_on;
737                              event.Param.Note.Key      = devEvent.Arg1;                              event.Param.Note.Key      = devEvent.Arg1;
738                              event.Param.Note.Velocity = devEvent.Arg2;                              event.Param.Note.Velocity = devEvent.Arg2;
739                                event.Param.Note.Channel  = channel;
740                              break;                              break;
741                          case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:                          case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
742                              event.Type = Event::type_note_off;                              event.Type = Event::type_note_off;
743                              event.Param.Note.Key      = devEvent.Arg1;                              event.Param.Note.Key      = devEvent.Arg1;
744                              event.Param.Note.Velocity = devEvent.Arg2;                              event.Param.Note.Velocity = devEvent.Arg2;
745                                event.Param.Note.Channel  = channel;
746                              break;                              break;
747                          case VirtualMidiDevice::EVENT_TYPE_CC:                          case VirtualMidiDevice::EVENT_TYPE_CC:
748                              event.Type = Event::type_control_change;                              switch (devEvent.Arg1) {
749                              event.Param.CC.Controller = devEvent.Arg1;                                  case 0: // bank select MSB ...
750                              event.Param.CC.Value      = devEvent.Arg2;                                      SetMidiBankMsb(devEvent.Arg2);
751                                        continue; // don't push this event into FIFO
752                                    case 32: // bank select LSB ...
753                                        SetMidiBankLsb(devEvent.Arg2);
754                                        continue; // don't push this event into FIFO
755                                    default: // regular MIDI CC ...
756                                        event.Type = Event::type_control_change;
757                                        event.Param.CC.Controller = devEvent.Arg1;
758                                        event.Param.CC.Value      = devEvent.Arg2;
759                                        event.Param.CC.Channel    = channel;
760                                }
761                              break;                              break;
762                            case VirtualMidiDevice::EVENT_TYPE_PITCHBEND:
763                                event.Type = Event::type_pitchbend;
764                                event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192;
765                                event.Param.Pitch.Channel = channel;
766                                break;
767                            case VirtualMidiDevice::EVENT_TYPE_PROGRAM:
768                                SendProgramChange(devEvent.Arg1);
769                                continue; // don't push this event into FIFO
770                          default:                          default:
771                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("                              std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
772                                        << devEvent.Type << "). This is a bug!";                                        << devEvent.Type << "). This is a bug!";
# Line 579  namespace LinuxSampler { Line 808  namespace LinuxSampler {
808          eventQueueReader.free(); // free all copied events from input queue          eventQueueReader.free(); // free all copied events from input queue
809      }      }
810    
811        /**
812         * Called by real-time instrument script functions to schedule a new event
813         * somewhere in future.
814         *
815         * @returns unique event ID of scheduled new event
816         */
817        int AbstractEngineChannel::ScheduleEvent(const Event* pEvent, int delay) { //TODO: delay not implemented yet
818            // since delay is not implemented yet, we simply add the new event
819            // to the event list of the current audio fragmet cycle for now
820            RTList<Event>::Iterator itEvent = pEvents->allocAppend();
821            if (itEvent) *itEvent = *pEvent; // copy event
822            return pEvents->getID(itEvent);
823        }
824    
825        /**
826         * Called by real-time instrument script functions to ignore the event
827         * reflected by given event ID. The event will be freed immediately to its
828         * pool and cannot be dereferenced by its old ID anymore. Even if its
829         * allocated back from the Pool later on, it will have a different ID.
830         */
831        void AbstractEngineChannel::IgnoreEvent(int id) {
832            RTList<Event>::Iterator it = pEvents->fromID(id);
833            if (it) pEvents->free(it);
834        }
835    
836      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {      FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) {
837          if (pEngine) pEngine->DisableAndLock();          if (pEngine) pEngine->DisableAndLock();
838          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);          FxSend* pFxSend = new FxSend(this, MidiCtrl, Name);
# Line 668  namespace LinuxSampler { Line 922  namespace LinuxSampler {
922       */       */
923      void AbstractEngineChannel::AddGroup(uint group) {      void AbstractEngineChannel::AddGroup(uint group) {
924          if (group) {          if (group) {
925              typedef std::map<uint, RTList<Event>*> map_t;              std::pair<ActiveKeyGroupMap::iterator, bool> p =
926                    ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
             std::pair<map_t::iterator, bool> p =  
                 ActiveKeyGroups.insert(map_t::value_type(group, 0));  
927              if (p.second) {              if (p.second) {
928                  (*p.first).second = new RTList<Event>(pEngine->pEventPool);                  // If the engine channel is pending deletion (see bug
929                    // #113), pEngine will be null, so we can't use
930                    // pEngine->pEventPool here. Instead we're using a
931                    // specialized RTList that allows specifying the pool
932                    // later.
933                    (*p.first).second = new LazyList<Event>;
934              }              }
935          }          }
936      }      }
# Line 685  namespace LinuxSampler { Line 942  namespace LinuxSampler {
942          dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));          dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
943          if (KeyGroup) {          if (KeyGroup) {
944              // send a release event to all active voices in the group              // send a release event to all active voices in the group
945              RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend();              RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
946              *itEvent = *itNoteOnEvent;              *itEvent = *itNoteOnEvent;
947          }          }
948      }      }
# Line 695  namespace LinuxSampler { Line 952  namespace LinuxSampler {
952       * audio thread, after all voices have been rendered.       * audio thread, after all voices have been rendered.
953       */       */
954      void AbstractEngineChannel::ClearGroupEventLists() {      void AbstractEngineChannel::ClearGroupEventLists() {
955          for (std::map<uint,RTList<Event>*>::iterator iter = ActiveKeyGroups.begin();          for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
956               iter != ActiveKeyGroups.end(); iter++) {               iter != ActiveKeyGroups.end(); iter++) {
957              if (iter->second) {              if (iter->second) {
958                  iter->second->clear();                  iter->second->clear();
# Line 709  namespace LinuxSampler { Line 966  namespace LinuxSampler {
966       * Remove all lists with group events.       * Remove all lists with group events.
967       */       */
968      void AbstractEngineChannel::DeleteGroupEventLists() {      void AbstractEngineChannel::DeleteGroupEventLists() {
969          for (std::map<uint,RTList<Event>*>::iterator iter = ActiveKeyGroups.begin();          for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
970               iter != ActiveKeyGroups.end(); iter++) {               iter != ActiveKeyGroups.end(); iter++) {
971              delete iter->second;              delete iter->second;
972          }          }

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

  ViewVC Help
Powered by ViewVC