/[svn]/linuxsampler/trunk/src/engines/AbstractEngineChannel.cpp
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/AbstractEngineChannel.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 2012 by iliev, Fri Oct 23 17:53:17 2009 UTC revision 2382 by persson, Sun Dec 2 16:30:42 2012 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2009 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009 Grigor Iliev                                       *   *   Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev        *
8   *                                                                         *   *                                                                         *
9   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
10   *   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 49  namespace LinuxSampler { Line 49  namespace LinuxSampler {
49      }      }
50    
51      AbstractEngineChannel::~AbstractEngineChannel() {      AbstractEngineChannel::~AbstractEngineChannel() {
52                    delete pEventQueue;
53          if (pEventQueue) delete pEventQueue;          DeleteGroupEventLists();
54          RemoveAllFxSends();          RemoveAllFxSends();
55      }      }
56    
# Line 112  namespace LinuxSampler { Line 112  namespace LinuxSampler {
112          Pitch          = 0;          Pitch          = 0;
113          GlobalVolume   = 1.0f;          GlobalVolume   = 1.0f;
114          MidiVolume     = 1.0;          MidiVolume     = 1.0;
         GlobalPanLeft  = 1.0f;  
         GlobalPanRight = 1.0f;  
115          iLastPanRequest = 64;          iLastPanRequest = 64;
116          GlobalTranspose = 0;          GlobalTranspose = 0;
117          // set all MIDI controller values to zero          // set all MIDI controller values to zero
# Line 182  namespace LinuxSampler { Line 180  namespace LinuxSampler {
180          int iMidiPan = int(f * 64.0f) + 64;          int iMidiPan = int(f * 64.0f) + 64;
181          if (iMidiPan > 127) iMidiPan = 127;          if (iMidiPan > 127) iMidiPan = 127;
182          else if (iMidiPan < 0) iMidiPan = 0;          else if (iMidiPan < 0) iMidiPan = 0;
         GlobalPanLeft  = AbstractEngine::PanCurve[128 - iMidiPan];  
         GlobalPanRight = AbstractEngine::PanCurve[iMidiPan];  
183          iLastPanRequest = iMidiPan;          iLastPanRequest = iMidiPan;
184      }      }
185    
# Line 191  namespace LinuxSampler { Line 187  namespace LinuxSampler {
187          return (pEngine) ? pEngine->pAudioOutputDevice : NULL;          return (pEngine) ? pEngine->pAudioOutputDevice : NULL;
188      }      }
189    
190        /**
191         * Gets thread safe access to the currently connected audio output
192         * device from other threads than the lscp thread.
193         */
194        AudioOutputDevice* AbstractEngineChannel::GetAudioOutputDeviceSafe() {
195            EngineMutex.Lock();
196            AudioOutputDevice* res = GetAudioOutputDevice();
197            EngineMutex.Unlock();
198            return res;
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 278  namespace LinuxSampler { Line 285  namespace LinuxSampler {
285       *  @param Key      - MIDI key number of the triggered key       *  @param Key      - MIDI key number of the triggered key
286       *  @param Velocity - MIDI velocity value of the triggered key       *  @param Velocity - MIDI velocity value of the triggered key
287       */       */
288      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity) {      void AbstractEngineChannel::SendNoteOn(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
289          if (pEngine) {          if (pEngine) {
290              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
291              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
292              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
293              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
294                event.Param.Note.Channel  = MidiChannel;
295              event.pEngineChannel      = this;              event.pEngineChannel      = this;
296              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
297              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 311  namespace LinuxSampler { Line 319  namespace LinuxSampler {
319       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
320       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
321       */       */
322      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) {
323          if (FragmentPos < 0) {          if (FragmentPos < 0) {
324              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOn(): negative FragmentPos! Seems MIDI driver is buggy!"));
325          }          }
# Line 320  namespace LinuxSampler { Line 328  namespace LinuxSampler {
328              event.Type                = Event::type_note_on;              event.Type                = Event::type_note_on;
329              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
330              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
331                event.Param.Note.Channel  = MidiChannel;
332              event.pEngineChannel      = this;              event.pEngineChannel      = this;
333              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
334              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 345  namespace LinuxSampler { Line 354  namespace LinuxSampler {
354       *  @param Key      - MIDI key number of the released key       *  @param Key      - MIDI key number of the released key
355       *  @param Velocity - MIDI release velocity value of the released key       *  @param Velocity - MIDI release velocity value of the released key
356       */       */
357      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity) {      void AbstractEngineChannel::SendNoteOff(uint8_t Key, uint8_t Velocity, uint8_t MidiChannel) {
358          if (pEngine) {          if (pEngine) {
359              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
360              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
361              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
362              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
363                event.Param.Note.Channel  = MidiChannel;
364              event.pEngineChannel      = this;              event.pEngineChannel      = this;
365              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
366              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 378  namespace LinuxSampler { Line 388  namespace LinuxSampler {
388       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
389       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
390       */       */
391      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) {
392          if (FragmentPos < 0) {          if (FragmentPos < 0) {
393              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("EngineChannel::SendNoteOff(): negative FragmentPos! Seems MIDI driver is buggy!"));
394          }          }
# Line 387  namespace LinuxSampler { Line 397  namespace LinuxSampler {
397              event.Type                = Event::type_note_off;              event.Type                = Event::type_note_off;
398              event.Param.Note.Key      = Key;              event.Param.Note.Key      = Key;
399              event.Param.Note.Velocity = Velocity;              event.Param.Note.Velocity = Velocity;
400                event.Param.Note.Channel  = MidiChannel;
401              event.pEngineChannel      = this;              event.pEngineChannel      = this;
402              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
403              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 411  namespace LinuxSampler { Line 422  namespace LinuxSampler {
422       *       *
423       *  @param Pitch - MIDI pitch value (-8192 ... +8191)       *  @param Pitch - MIDI pitch value (-8192 ... +8191)
424       */       */
425      void AbstractEngineChannel::SendPitchbend(int Pitch) {      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel) {
426          if (pEngine) {          if (pEngine) {
427              Event event             = pEngine->pEventGenerator->CreateEvent();              Event event             = pEngine->pEventGenerator->CreateEvent();
428              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
429              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
430                event.Param.Pitch.Channel = MidiChannel;
431              event.pEngineChannel    = this;              event.pEngineChannel    = this;
432              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
433              else dmsg(1,("EngineChannel: Input event queue full!"));              else dmsg(1,("EngineChannel: Input event queue full!"));
# Line 432  namespace LinuxSampler { Line 444  namespace LinuxSampler {
444       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
445       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
446       */       */
447      void AbstractEngineChannel::SendPitchbend(int Pitch, int32_t FragmentPos) {      void AbstractEngineChannel::SendPitchbend(int Pitch, uint8_t MidiChannel, int32_t FragmentPos) {
448          if (FragmentPos < 0) {          if (FragmentPos < 0) {
449              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendPitchBend(): negative FragmentPos! Seems MIDI driver is buggy!"));
450          }          }
# Line 440  namespace LinuxSampler { Line 452  namespace LinuxSampler {
452              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event             = pEngine->pEventGenerator->CreateEvent(FragmentPos);
453              event.Type              = Event::type_pitchbend;              event.Type              = Event::type_pitchbend;
454              event.Param.Pitch.Pitch = Pitch;              event.Param.Pitch.Pitch = Pitch;
455                event.Param.Pitch.Channel = MidiChannel;
456              event.pEngineChannel    = this;              event.pEngineChannel    = this;
457              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
458              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 455  namespace LinuxSampler { Line 468  namespace LinuxSampler {
468       *  @param Controller - MIDI controller number of the occured control change       *  @param Controller - MIDI controller number of the occured control change
469       *  @param Value      - value of the control change       *  @param Value      - value of the control change
470       */       */
471      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value) {      void AbstractEngineChannel::SendControlChange(uint8_t Controller, uint8_t Value, uint8_t MidiChannel) {
472          if (pEngine) {          if (pEngine) {
473              Event event               = pEngine->pEventGenerator->CreateEvent();              Event event               = pEngine->pEventGenerator->CreateEvent();
474              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
475              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
476              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
477                event.Param.CC.Channel    = MidiChannel;
478              event.pEngineChannel      = this;              event.pEngineChannel      = this;
479              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
480              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 478  namespace LinuxSampler { Line 492  namespace LinuxSampler {
492       *  @param FragmentPos - sample point position in the current audio       *  @param FragmentPos - sample point position in the current audio
493       *                       fragment to which this event belongs to       *                       fragment to which this event belongs to
494       */       */
495      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) {
496          if (FragmentPos < 0) {          if (FragmentPos < 0) {
497              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));              dmsg(1,("AbstractEngineChannel::SendControlChange(): negative FragmentPos! Seems MIDI driver is buggy!"));
498          }          }
# Line 487  namespace LinuxSampler { Line 501  namespace LinuxSampler {
501              event.Type                = Event::type_control_change;              event.Type                = Event::type_control_change;
502              event.Param.CC.Controller = Controller;              event.Param.CC.Controller = Controller;
503              event.Param.CC.Value      = Value;              event.Param.CC.Value      = Value;
504                event.Param.CC.Channel    = MidiChannel;
505              event.pEngineChannel      = this;              event.pEngineChannel      = this;
506              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);              if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event);
507              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));              else dmsg(1,("AbstractEngineChannel: Input event queue full!"));
# Line 510  namespace LinuxSampler { Line 525  namespace LinuxSampler {
525          // import events from pure software MIDI "devices"          // import events from pure software MIDI "devices"
526          // (e.g. virtual keyboard in instrument editor)          // (e.g. virtual keyboard in instrument editor)
527          {          {
528                const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel();
529              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
530              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);              Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos);
531              VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device              VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device
# Line 522  namespace LinuxSampler { Line 538  namespace LinuxSampler {
538                  VirtualMidiDevice* pDev = devices[i];                  VirtualMidiDevice* pDev = devices[i];
539                  // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)                  // I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-)
540                  while (pDev->GetMidiEventFromDevice(devEvent)) {                  while (pDev->GetMidiEventFromDevice(devEvent)) {
541                      event.Type =                      switch (devEvent.Type) {
542                          (devEvent.Type == VirtualMidiDevice::EVENT_TYPE_NOTEON) ?                          case VirtualMidiDevice::EVENT_TYPE_NOTEON:
543                              Event::type_note_on : Event::type_note_off;                              event.Type = Event::type_note_on;
544                      event.Param.Note.Key      = devEvent.Key;                              event.Param.Note.Key      = devEvent.Arg1;
545                      event.Param.Note.Velocity = devEvent.Velocity;                              event.Param.Note.Velocity = devEvent.Arg2;
546                      event.pEngineChannel      = this;                              event.Param.Note.Channel  = channel;
547                                break;
548                            case VirtualMidiDevice::EVENT_TYPE_NOTEOFF:
549                                event.Type = Event::type_note_off;
550                                event.Param.Note.Key      = devEvent.Arg1;
551                                event.Param.Note.Velocity = devEvent.Arg2;
552                                event.Param.Note.Channel  = channel;
553                                break;
554                            case VirtualMidiDevice::EVENT_TYPE_CC:
555                                event.Type = Event::type_control_change;
556                                event.Param.CC.Controller = devEvent.Arg1;
557                                event.Param.CC.Value      = devEvent.Arg2;
558                                event.Param.CC.Channel    = channel;
559                                break;
560                            default:
561                                std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type ("
562                                          << devEvent.Type << "). This is a bug!";
563                                continue;
564                        }
565                        event.pEngineChannel = this;
566                      // copy event to internal event list                      // copy event to internal event list
567                      if (pEvents->poolIsEmpty()) {                      if (pEvents->poolIsEmpty()) {
568                          dmsg(1,("Event pool emtpy!\n"));                          dmsg(1,("Event pool emtpy!\n"));
# Line 645  namespace LinuxSampler { Line 680  namespace LinuxSampler {
680          if (pEngine) pEngine->Enable();          if (pEngine) pEngine->Enable();
681      }      }
682    
683        /**
684         * Add a group number to the set of key groups. Should be called
685         * when an instrument is loaded to make sure there are event lists
686         * for all key groups.
687         */
688        void AbstractEngineChannel::AddGroup(uint group) {
689            if (group) {
690                std::pair<ActiveKeyGroupMap::iterator, bool> p =
691                    ActiveKeyGroups.insert(ActiveKeyGroupMap::value_type(group, 0));
692                if (p.second) {
693                    // If the engine channel is pending deletion (see bug
694                    // #113), pEngine will be null, so we can't use
695                    // pEngine->pEventPool here. Instead we're using a
696                    // specialized RTList that allows specifying the pool
697                    // later.
698                    (*p.first).second = new LazyList<Event>;
699                }
700            }
701        }
702    
703        /**
704         * Handle key group (a.k.a. exclusive group) conflicts.
705         */
706        void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) {
707            dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup));
708            if (KeyGroup) {
709                // send a release event to all active voices in the group
710                RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool);
711                *itEvent = *itNoteOnEvent;
712            }
713        }
714    
715        /**
716         * Empty the lists of group events. Should be called from the
717         * audio thread, after all voices have been rendered.
718         */
719        void AbstractEngineChannel::ClearGroupEventLists() {
720            for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
721                 iter != ActiveKeyGroups.end(); iter++) {
722                if (iter->second) {
723                    iter->second->clear();
724                } else {
725                    dmsg(1,("EngineChannel: group event list was NULL"));
726                }
727            }
728        }
729    
730        /**
731         * Remove all lists with group events.
732         */
733        void AbstractEngineChannel::DeleteGroupEventLists() {
734            for (ActiveKeyGroupMap::iterator iter = ActiveKeyGroups.begin();
735                 iter != ActiveKeyGroups.end(); iter++) {
736                delete iter->second;
737            }
738            ActiveKeyGroups.clear();
739        }
740    
741  } // namespace LinuxSampler  } // namespace LinuxSampler

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

  ViewVC Help
Powered by ViewVC