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

Diff of /linuxsampler/trunk/src/engines/gig/Engine.cpp

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

revision 1555 by schoenebeck, Thu Dec 6 01:39:24 2007 UTC revision 1789 by iliev, Sat Nov 1 19:01:27 2008 UTC
# Line 2  Line 2 
2   *                                                                         *   *                                                                         *
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-2007 Christian Schoenebeck                        *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *                                                                         *   *                                                                         *
8   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
9   *   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 74  namespace LinuxSampler { namespace gig { Line 74  namespace LinuxSampler { namespace gig {
74    
75      /**      /**
76       * Once an engine channel is disconnected from an audio output device,       * Once an engine channel is disconnected from an audio output device,
77       * it wil immediately call this method to unregister itself from the       * it will immediately call this method to unregister itself from the
78       * engine instance and if that engine instance is not used by any other       * engine instance and if that engine instance is not used by any other
79       * engine channel anymore, then that engine instance will be destroyed.       * engine channel anymore, then that engine instance will be destroyed.
80       *       *
# Line 108  namespace LinuxSampler { namespace gig { Line 108  namespace LinuxSampler { namespace gig {
108          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);          pEventQueue        = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0);
109          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);          pEventPool         = new Pool<Event>(CONFIG_MAX_EVENTS_PER_FRAGMENT);
110          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);          pVoicePool         = new Pool<Voice>(CONFIG_MAX_VOICES);
111          pDimRegionsInUse   = new ::gig::DimensionRegion*[CONFIG_MAX_VOICES + 1];          pDimRegionPool[0]  = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES);
112            pDimRegionPool[1]  = new Pool< ::gig::DimensionRegion*>(CONFIG_MAX_VOICES);
113          pVoiceStealingQueue = new RTList<Event>(pEventPool);          pVoiceStealingQueue = new RTList<Event>(pEventPool);
114          pGlobalEvents      = new RTList<Event>(pEventPool);          pGlobalEvents      = new RTList<Event>(pEventPool);
         InstrumentChangeQueue      = new RingBuffer<instrument_change_command_t,false>(1, 0);  
         InstrumentChangeReplyQueue = new RingBuffer<instrument_change_reply_t,false>(1, 0);  
115    
116          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {          for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
117              iterVoice->SetEngine(this);              iterVoice->SetEngine(this);
# Line 145  namespace LinuxSampler { namespace gig { Line 144  namespace LinuxSampler { namespace gig {
144          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
145          if (pSysexBuffer) delete pSysexBuffer;          if (pSysexBuffer) delete pSysexBuffer;
146          if (pGlobalEvents) delete pGlobalEvents;          if (pGlobalEvents) delete pGlobalEvents;
147          if (InstrumentChangeQueue) delete InstrumentChangeQueue;          if (pDimRegionPool[0]) delete pDimRegionPool[0];
148          if (InstrumentChangeReplyQueue) delete InstrumentChangeReplyQueue;          if (pDimRegionPool[1]) delete pDimRegionPool[1];
         if (pDimRegionsInUse) delete[] pDimRegionsInUse;  
149          ResetSuspendedRegions();          ResetSuspendedRegions();
150          Unregister();          Unregister();
151      }      }
# Line 293  namespace LinuxSampler { namespace gig { Line 291  namespace LinuxSampler { namespace gig {
291          // make sure that the engine does not get any sysex messages          // make sure that the engine does not get any sysex messages
292          // while it's reseting          // while it's reseting
293          bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);          bool sysexDisabled = MidiInputPort::RemoveSysexListener(this);
294          ActiveVoiceCount    = 0;          SetVoiceCount(0);
295          ActiveVoiceCountMax = 0;          ActiveVoiceCountMax = 0;
296    
297          // reset voice stealing parameters          // reset voice stealing parameters
# Line 360  namespace LinuxSampler { namespace gig { Line 358  namespace LinuxSampler { namespace gig {
358          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();          this->MaxSamplesPerCycle = pAudioOutputDevice->MaxSamplesPerCycle();
359          this->SampleRate         = pAudioOutputDevice->SampleRate();          this->SampleRate         = pAudioOutputDevice->SampleRate();
360    
361          // FIXME: audio drivers with varying fragment sizes might be a problem here          MinFadeOutSamples = int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;
362          MaxFadeOutPos = MaxSamplesPerCycle - int(double(SampleRate) * CONFIG_EG_MIN_RELEASE_TIME) - 1;          if (MaxSamplesPerCycle < MinFadeOutSamples) {
         if (MaxFadeOutPos < 0) {  
363              std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME "              std::cerr << "gig::Engine: WARNING, CONFIG_EG_MIN_RELEASE_TIME "
364                        << "too big for current audio fragment size & sampling rate! "                        << "too big for current audio fragment size & sampling rate! "
365                        << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;                        << "May lead to click sounds if voice stealing chimes in!\n" << std::flush;
366              // force volume ramp downs at the beginning of each fragment              // force volume ramp downs at the beginning of each fragment
367              MaxFadeOutPos = 0;              MinFadeOutSamples = MaxSamplesPerCycle;
368              // lower minimum release time              // lower minimum release time
369              const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;              const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
370              for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {              for (RTList<Voice>::Iterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
# Line 460  namespace LinuxSampler { namespace gig { Line 457  namespace LinuxSampler { namespace gig {
457              // free request slot for next caller (and to make sure that              // free request slot for next caller (and to make sure that
458              // we're not going to process the same request in the next cycle)              // we're not going to process the same request in the next cycle)
459              pPendingRegionSuspension = NULL;              pPendingRegionSuspension = NULL;
460              // if no disk stream deletions are pending, awaker other side, as              // if no disk stream deletions are pending, awaken other side, as
461              // we're done in this case              // we're done in this case
462              if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);              if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
463          }          }
# Line 576  namespace LinuxSampler { namespace gig { Line 573  namespace LinuxSampler { namespace gig {
573          // return if engine disabled          // return if engine disabled
574          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
575              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));              dmsg(5,("gig::Engine: engine disabled (val=%d)\n",EngineDisabled.GetUnsafe()));
576                EngineDisabled.RttDone();
577              return 0;              return 0;
578          }          }
579    
# Line 613  namespace LinuxSampler { namespace gig { Line 611  namespace LinuxSampler { namespace gig {
611          ActiveVoiceCountTemp = 0;          ActiveVoiceCountTemp = 0;
612    
613          // handle instrument change commands          // handle instrument change commands
614          instrument_change_command_t command;          bool instrumentChanged = false;
615          if (InstrumentChangeQueue->pop(&command) > 0) {          for (int i = 0; i < engineChannels.size(); i++) {
616              EngineChannel* pEngineChannel = command.pEngineChannel;              EngineChannel* pEngineChannel = engineChannels[i];
             pEngineChannel->pInstrument = command.pInstrument;  
   
             //TODO: this is a lazy solution ATM and not safe in case somebody is currently editing the instrument we're currently switching to (we should store all suspended regions on instrument manager side and when switching to another instrument copy that list to the engine's local list of suspensions  
             ResetSuspendedRegions();  
617    
618              // iterate through all active voices and mark their              // as we're going to (carefully) write some status to the
619              // dimension regions as "in use". The instrument resource              // synchronized struct, we cast away the const
620              // manager may delete all of the instrument except the              EngineChannel::instrument_change_command_t& cmd =
621              // dimension regions and samples that are in use.                  const_cast<EngineChannel::instrument_change_command_t&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
622              int i = 0;  
623              RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();              pEngineChannel->pDimRegionsInUse = cmd.pDimRegionsInUse;
624              RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();              pEngineChannel->pDimRegionsInUse->clear();
625              while (iuiKey != end) { // iterate through all active keys  
626                  midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];              if (cmd.bChangeInstrument) {
627                  ++iuiKey;                  // change instrument
628                    dmsg(5,("Engine: instrument change command received\n"));
629                    cmd.bChangeInstrument = false;
630                    pEngineChannel->pInstrument = cmd.pInstrument;
631                    instrumentChanged = true;
632    
633                    // Iterate through all active voices and mark them as
634                    // "orphans", which means that the dimension regions
635                    // and samples they use should be released to the
636                    // instrument resource manager when the voices die.
637                    int i = 0;
638                    RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
639                    RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
640                    while (iuiKey != end) { // iterate through all active keys
641                        midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
642                        ++iuiKey;
643    
644                  RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();                      RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
645                  RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();                      RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
646                  for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key                      for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
                     if (!itVoice->Orphan) {  
647                          itVoice->Orphan = true;                          itVoice->Orphan = true;
                         pDimRegionsInUse[i++] = itVoice->pDimRgn;  
648                      }                      }
649                  }                  }
650              }              }
651              pDimRegionsInUse[i] = 0; // end of list          }
652            if (instrumentChanged) {
653              // send a reply to the calling thread, which is waiting              //TODO: this is a lazy solution ATM and not safe in case somebody is currently editing the instrument we're currently switching to (we should store all suspended regions on instrument manager side and when switching to another instrument copy that list to the engine's local list of suspensions
654              instrument_change_reply_t reply;              ResetSuspendedRegions();
             InstrumentChangeReplyQueue->push(&reply);  
655          }          }
656    
657          // handle events on all engine channels          // handle events on all engine channels
# Line 680  namespace LinuxSampler { namespace gig { Line 686  namespace LinuxSampler { namespace gig {
686          pVoiceStealingQueue->clear();          pVoiceStealingQueue->clear();
687    
688          // just some statistics about this engine instance          // just some statistics about this engine instance
689          ActiveVoiceCount = ActiveVoiceCountTemp;          SetVoiceCount(ActiveVoiceCountTemp);
690          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;          if (VoiceCount() > ActiveVoiceCountMax) ActiveVoiceCountMax = VoiceCount();
691    
692          // in case regions were previously suspended and we killed voices          // in case regions were previously suspended and we killed voices
693          // with disk streams due to that, check if those streams have finally          // with disk streams due to that, check if those streams have finally
694          // been deleted by the disk thread          // been deleted by the disk thread
695          if (iPendingStreamDeletions) ProcessPendingStreamDeletions();          if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
696    
697            for (int i = 0; i < engineChannels.size(); i++) {
698                engineChannels[i]->InstrumentChangeCommandReader.Unlock();
699            }
700          FrameTime += Samples;          FrameTime += Samples;
701    
702            EngineDisabled.RttDone();
703          return 0;          return 0;
704      }      }
705    
# Line 769  namespace LinuxSampler { namespace gig { Line 779  namespace LinuxSampler { namespace gig {
779                  // now render current voice                  // now render current voice
780                  itVoice->Render(Samples);                  itVoice->Render(Samples);
781                  if (itVoice->IsActive()) { // still active                  if (itVoice->IsActive()) { // still active
782                        if (!itVoice->Orphan) {
783                            *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itVoice->pDimRgn;
784                        }
785                      ActiveVoiceCountTemp++;                      ActiveVoiceCountTemp++;
786                      voiceCount++;                      voiceCount++;
787    
788                      if (itVoice->PlaybackState == Voice::playback_state_disk) {                      if (itVoice->PlaybackState == Voice::playback_state_disk) {
789                          if ((itVoice->DiskStreamRef).State == Stream::state_active) streamCount++;                          if ((itVoice->DiskStreamRef).State != Stream::state_unused) streamCount++;
790                      }                      }
791                  }  else { // voice reached end, is now inactive                  }  else { // voice reached end, is now inactive
792                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
# Line 809  namespace LinuxSampler { namespace gig { Line 822  namespace LinuxSampler { namespace gig {
822              if (itNewVoice) {              if (itNewVoice) {
823                  itNewVoice->Render(Samples);                  itNewVoice->Render(Samples);
824                  if (itNewVoice->IsActive()) { // still active                  if (itNewVoice->IsActive()) { // still active
825                        *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itNewVoice->pDimRgn;
826                      ActiveVoiceCountTemp++;                      ActiveVoiceCountTemp++;
827                      pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);                      pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
828    
829                      if (itNewVoice->PlaybackState == Voice::playback_state_disk) {                      if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
830                          if (itNewVoice->DiskStreamRef.State == Stream::state_active) {                          if (itNewVoice->DiskStreamRef.State != Stream::state_unused) {
831                              pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);                              pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
832                          }                          }
833                      }                      }
# Line 844  namespace LinuxSampler { namespace gig { Line 858  namespace LinuxSampler { namespace gig {
858       *                         this audio fragment cycle       *                         this audio fragment cycle
859       */       */
860      void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {      void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
861          // route master signal          // route dry signal
862          {          {
863              AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);              AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
864              AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);              AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
# Line 855  namespace LinuxSampler { namespace gig { Line 869  namespace LinuxSampler { namespace gig {
869          {          {
870              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
871                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
872                  // left channel                  for (int iChan = 0; iChan < 2; ++iChan) {
873                  const int iDstL = pFxSend->DestinationChannel(0);                      AudioChannel* pSource =
874                  if (iDstL < 0) {                          (iChan)
875                      dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));                              ? pEngineChannel->pChannelRight
876                  } else {                              : pEngineChannel->pChannelLeft;
877                      AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);                      const int iDstChan = pFxSend->DestinationChannel(iChan);
878                      if (!pDstL) {                      if (iDstChan < 0) {
879                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
880                      } else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level());                          goto channel_cleanup;
881                  }                      }
882                  // right channel                      AudioChannel* pDstChan = NULL;
883                  const int iDstR = pFxSend->DestinationChannel(1);                      if (pFxSend->DestinationMasterEffectChain() >= 0) { // fx send routed to an internal master effect
884                  if (iDstR < 0) {                          EffectChain* pEffectChain =
885                      dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));                              pAudioOutputDevice->MasterEffectChain(
886                  } else {                                  pFxSend->DestinationMasterEffectChain()
887                      AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);                              );
888                      if (!pDstR) {                          if (!pEffectChain) {
889                          dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));                              dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffectChain()));
890                      } else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level());                              goto channel_cleanup;
891                            }
892                            Effect* pEffect =
893                                pEffectChain->GetEffect(
894                                    pFxSend->DestinationMasterEffect()
895                                );
896                            if (!pEffect) {
897                                dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffect(), pFxSend->DestinationMasterEffectChain()));
898                                goto channel_cleanup;
899                            }
900                            pDstChan = pEffect->InputChannel(iDstChan);
901                        } else { // FX send routed directly to an audio output channel
902                            pDstChan = pAudioOutputDevice->Channel(iDstChan);
903                        }
904                        if (!pDstChan) {
905                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
906                            goto channel_cleanup;
907                        }
908                        pSource->MixTo(pDstChan, Samples, pFxSend->Level());
909                  }                  }
910              }              }
911          }          }
912            channel_cleanup:
913          // reset buffers with silence (zero out) for the next audio cycle          // reset buffers with silence (zero out) for the next audio cycle
914          pEngineChannel->pChannelLeft->Clear();          pEngineChannel->pChannelLeft->Clear();
915          pEngineChannel->pChannelRight->Clear();          pEngineChannel->pChannelRight->Clear();
# Line 922  namespace LinuxSampler { namespace gig { Line 955  namespace LinuxSampler { namespace gig {
955       *       *
956       *  @param pData - pointer to sysex data       *  @param pData - pointer to sysex data
957       *  @param Size  - lenght of sysex data (in bytes)       *  @param Size  - lenght of sysex data (in bytes)
958         *  @param pSender - the MIDI input port on which the SysEx message was
959         *                   received
960       */       */
961      void Engine::SendSysex(void* pData, uint Size) {      void Engine::SendSysex(void* pData, uint Size, MidiInputPort* pSender) {
962          Event event             = pEventGenerator->CreateEvent();          Event event             = pEventGenerator->CreateEvent();
963          event.Type              = Event::type_sysex;          event.Type              = Event::type_sysex;
964          event.Param.Sysex.Size  = Size;          event.Param.Sysex.Size  = Size;
965          event.pEngineChannel    = NULL; // as Engine global event          event.pEngineChannel    = NULL; // as Engine global event
966            event.pMidiInputPort    = pSender;
967          if (pEventQueue->write_space() > 0) {          if (pEventQueue->write_space() > 0) {
968              if (pSysexBuffer->write_space() >= Size) {              if (pSysexBuffer->write_space() >= Size) {
969                  // copy sysex data to input buffer                  // copy sysex data to input buffer
# Line 1605  namespace LinuxSampler { namespace gig { Line 1641  namespace LinuxSampler { namespace gig {
1641      void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {      void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {
1642          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));          dmsg(4,("Engine::ContinuousController cc=%d v=%d\n", itControlChangeEvent->Param.CC.Controller, itControlChangeEvent->Param.CC.Value));
1643    
1644            // handle the "control triggered" MIDI rule: a control change
1645            // event can trigger a new note on or note off event
1646            if (pEngineChannel->pInstrument) {
1647    
1648                ::gig::MidiRule* rule;
1649                for (int i = 0 ; (rule = pEngineChannel->pInstrument->GetMidiRule(i)) ; i++) {
1650    
1651                    if (::gig::MidiRuleCtrlTrigger* ctrlTrigger =
1652                        dynamic_cast< ::gig::MidiRuleCtrlTrigger*>(rule)) {
1653                        if (itControlChangeEvent->Param.CC.Controller ==
1654                            ctrlTrigger->ControllerNumber) {
1655    
1656                            uint8_t oldCCValue = pEngineChannel->ControllerTable[
1657                                itControlChangeEvent->Param.CC.Controller];
1658                            uint8_t newCCValue = itControlChangeEvent->Param.CC.Value;
1659    
1660                            for (int i = 0 ; i < ctrlTrigger->Triggers ; i++) {
1661                                ::gig::MidiRuleCtrlTrigger::trigger_t* pTrigger =
1662                                      &ctrlTrigger->pTriggers[i];
1663    
1664                                // check if the controller has passed the
1665                                // trigger point in the right direction
1666                                if ((pTrigger->Descending &&
1667                                     oldCCValue > pTrigger->TriggerPoint &&
1668                                     newCCValue <= pTrigger->TriggerPoint) ||
1669                                    (!pTrigger->Descending &&
1670                                     oldCCValue < pTrigger->TriggerPoint &&
1671                                     newCCValue >= pTrigger->TriggerPoint)) {
1672    
1673                                    RTList<Event>::Iterator itNewEvent = pGlobalEvents->allocAppend();
1674                                    if (itNewEvent) {
1675                                        *itNewEvent = *itControlChangeEvent;
1676                                        itNewEvent->Param.Note.Key = pTrigger->Key;
1677    
1678                                        if (pTrigger->NoteOff || pTrigger->Velocity == 0) {
1679                                            itNewEvent->Type = Event::type_note_off;
1680                                            itNewEvent->Param.Note.Velocity = 100;
1681    
1682                                            ProcessNoteOff(pEngineChannel, itNewEvent);
1683                                        } else {
1684                                            itNewEvent->Type = Event::type_note_on;
1685                                            //TODO: if Velocity is 255, the triggered velocity should
1686                                            // depend on how fast the controller is moving
1687                                            itNewEvent->Param.Note.Velocity =
1688                                                pTrigger->Velocity == 255 ? 100 :
1689                                                pTrigger->Velocity;
1690    
1691                                            ProcessNoteOn(pEngineChannel, itNewEvent);
1692                                        }
1693                                    }
1694                                    else dmsg(1,("Event pool emtpy!\n"));
1695                                }
1696                            }
1697                        }
1698                    }
1699                }
1700            }
1701    
1702          // update controller value in the engine channel's controller table          // update controller value in the engine channel's controller table
1703          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1704    
# Line 1638  namespace LinuxSampler { namespace gig { Line 1732  namespace LinuxSampler { namespace gig {
1732                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1733                  pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];                  pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1734                  pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];                  pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
1735                    pEngineChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1736                  break;                  break;
1737              }              }
1738              case 64: { // sustain              case 64: { // sustain
# Line 1778  namespace LinuxSampler { namespace gig { Line 1873  namespace LinuxSampler { namespace gig {
1873          if (!pEngineChannel->fxSends.empty()) {          if (!pEngineChannel->fxSends.empty()) {
1874              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1875                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1876                  if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)                  if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) {
1877                      pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);                      pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1878                      pFxSend->SetInfoChanged(true);                      pFxSend->SetInfoChanged(true);
1879                    }
1880              }              }
1881          }          }
1882      }      }
# Line 1799  namespace LinuxSampler { namespace gig { Line 1895  namespace LinuxSampler { namespace gig {
1895          if (exclusive_status != 0xF0)       goto free_sysex_data;          if (exclusive_status != 0xF0)       goto free_sysex_data;
1896    
1897          switch (id) {          switch (id) {
1898                case 0x7f: { // (Realtime) Universal Sysex (GM Standard)
1899                    uint8_t sysex_channel, sub_id1, sub_id2, val_msb, val_lsb;;
1900                    if (!reader.pop(&sysex_channel)) goto free_sysex_data;
1901                    if (!reader.pop(&sub_id1)) goto free_sysex_data;
1902                    if (!reader.pop(&sub_id2)) goto free_sysex_data;
1903                    if (!reader.pop(&val_lsb)) goto free_sysex_data;
1904                    if (!reader.pop(&val_msb)) goto free_sysex_data;
1905                    //TODO: for now we simply ignore the sysex channel, seldom used anyway
1906                    switch (sub_id1) {
1907                        case 0x04: // Device Control
1908                            switch (sub_id2) {
1909                                case 0x01: { // Master Volume
1910                                    const double volume =
1911                                        double((uint(val_msb)<<7) | uint(val_lsb)) / 16383.0;
1912                                    #if CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
1913                                    // apply volume to all sampler channels that
1914                                    // are connected to the same MIDI input port
1915                                    // this sysex message arrived on
1916                                    for (int i = 0; i < engineChannels.size(); ++i) {
1917                                        EngineChannel* pEngineChannel = engineChannels[i];
1918                                        if (pEngineChannel->GetMidiInputPort() ==
1919                                            itSysexEvent->pMidiInputPort)
1920                                        {
1921                                            pEngineChannel->Volume(volume);
1922                                        }
1923                                    }
1924                                    #else
1925                                    // apply volume globally to the whole sampler
1926                                    GLOBAL_VOLUME = volume;
1927                                    #endif // CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
1928                                    break;
1929                                }
1930                            }
1931                            break;
1932                    }
1933                    break;
1934                }
1935              case 0x41: { // Roland              case 0x41: { // Roland
1936                  dmsg(3,("Roland Sysex\n"));                  dmsg(3,("Roland Sysex\n"));
1937                  uint8_t device_id, model_id, cmd_id;                  uint8_t device_id, model_id, cmd_id;
# Line 1835  namespace LinuxSampler { namespace gig { Line 1968  namespace LinuxSampler { namespace gig {
1968                              dmsg(3,("\t\t\tNew scale applied.\n"));                              dmsg(3,("\t\t\tNew scale applied.\n"));
1969                              break;                              break;
1970                          }                          }
1971                            case 0x15: { // chromatic / drumkit mode
1972                                dmsg(3,("\t\tMIDI Instrument Map Switch\n"));
1973                                uint8_t part = addr[1] & 0x0f;
1974                                uint8_t map;
1975                                if (!reader.pop(&map)) goto free_sysex_data;
1976                                for (int i = 0; i < engineChannels.size(); ++i) {
1977                                    EngineChannel* pEngineChannel = engineChannels[i];
1978                                    if (
1979                                        (pEngineChannel->midiChannel == part ||
1980                                         pEngineChannel->midiChannel == midi_chan_all) &&
1981                                         pEngineChannel->GetMidiInputPort() == itSysexEvent->pMidiInputPort
1982                                    ) {
1983                                        try {
1984                                            pEngineChannel->SetMidiInstrumentMap(map);
1985                                        } catch (Exception e) {
1986                                            dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d: %s\n", map, part, e.Message().c_str()));
1987                                            goto free_sysex_data;
1988                                        } catch (...) {
1989                                            dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d (unknown exception)\n", map, part));
1990                                            goto free_sysex_data;
1991                                        }
1992                                    }
1993                                }
1994                                dmsg(3,("\t\t\tApplied MIDI instrument map %d to part %d.\n", map, part));
1995                                break;
1996                            }
1997                      }                      }
1998                  }                  }
1999                  else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)                  else if (addr[0] == 0x40 && (addr[1] & 0xf0) == 0x20) { // Part Parameters (2)
# Line 1941  namespace LinuxSampler { namespace gig { Line 2100  namespace LinuxSampler { namespace gig {
2100      }      }
2101    
2102      uint Engine::VoiceCount() {      uint Engine::VoiceCount() {
2103          return ActiveVoiceCount;          return atomic_read(&ActiveVoiceCount);
2104        }
2105    
2106        void Engine::SetVoiceCount(uint Count) {
2107            atomic_set(&ActiveVoiceCount, Count);
2108      }      }
2109    
2110      uint Engine::VoiceCountMax() {      uint Engine::VoiceCountMax() {
# Line 1953  namespace LinuxSampler { namespace gig { Line 2116  namespace LinuxSampler { namespace gig {
2116      }      }
2117    
2118      uint Engine::DiskStreamCount() {      uint Engine::DiskStreamCount() {
2119          return (pDiskThread) ? pDiskThread->ActiveStreamCount : 0;          return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0;
2120      }      }
2121    
2122      uint Engine::DiskStreamCountMax() {      uint Engine::DiskStreamCountMax() {
# Line 1977  namespace LinuxSampler { namespace gig { Line 2140  namespace LinuxSampler { namespace gig {
2140      }      }
2141    
2142      String Engine::Version() {      String Engine::Version() {
2143          String s = "$Revision: 1.85 $";          String s = "$Revision: 1.98 $";
2144          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword          return s.substr(11, s.size() - 13); // cut dollar signs, spaces and CVS macro keyword
2145      }      }
2146    
# Line 1986  namespace LinuxSampler { namespace gig { Line 2149  namespace LinuxSampler { namespace gig {
2149      }      }
2150    
2151      // static constant initializers      // static constant initializers
2152      const float* Engine::VolumeCurve(InitVolumeCurve());      const Engine::FloatTable Engine::VolumeCurve(InitVolumeCurve());
2153      const float* Engine::PanCurve(InitPanCurve());      const Engine::FloatTable Engine::PanCurve(InitPanCurve());
2154      const float* Engine::CrossfadeCurve(InitCrossfadeCurve());      const Engine::FloatTable Engine::CrossfadeCurve(InitCrossfadeCurve());
2155    
2156      float* Engine::InitVolumeCurve() {      float* Engine::InitVolumeCurve() {
2157          // line-segment approximation          // line-segment approximation
# Line 2027  namespace LinuxSampler { namespace gig { Line 2190  namespace LinuxSampler { namespace gig {
2190          return y;          return y;
2191      }      }
2192    
     /**  
      * Changes the instrument for an engine channel.  
      *  
      * @param pEngineChannel - engine channel on which the instrument  
      *                         should be changed  
      * @param pInstrument - new instrument  
      * @returns a list of dimension regions from the old instrument  
      *          that are still in use  
      */  
     ::gig::DimensionRegion** Engine::ChangeInstrument(EngineChannel* pEngineChannel, ::gig::Instrument* pInstrument) {  
         instrument_change_command_t command;  
         command.pEngineChannel = pEngineChannel;  
         command.pInstrument = pInstrument;  
         InstrumentChangeQueue->push(&command);  
   
         // wait for the audio thread to confirm that the instrument  
         // change has been done  
         instrument_change_reply_t reply;  
         while (InstrumentChangeReplyQueue->pop(&reply) == 0) {  
             usleep(10000);  
         }  
         return pDimRegionsInUse;  
     }  
   
2193  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.1555  
changed lines
  Added in v.1789

  ViewVC Help
Powered by ViewVC