/[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 1399 by schoenebeck, Thu Oct 11 18:53:29 2007 UTC revision 1762 by schoenebeck, Fri Aug 29 17:33:02 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 29  Line 29 
29    
30  #include "Engine.h"  #include "Engine.h"
31    
32    #include "../../common/global_private.h"
33    
34  namespace LinuxSampler { namespace gig {  namespace LinuxSampler { namespace gig {
35    
36      InstrumentResourceManager Engine::instruments;      InstrumentResourceManager Engine::instruments;
# Line 72  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 106  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 143  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 358  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 458  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 569  namespace LinuxSampler { namespace gig { Line 568  namespace LinuxSampler { namespace gig {
568       *  @returns       0 on success       *  @returns       0 on success
569       */       */
570      int Engine::RenderAudio(uint Samples) {      int Engine::RenderAudio(uint Samples) {
571          dmsg(7,("RenderAudio(Samples=%d)\n", Samples));          dmsg(8,("RenderAudio(Samples=%d)\n", Samples));
572    
573          // return if engine disabled          // return if engine disabled
574          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
# Line 611  namespace LinuxSampler { namespace gig { Line 610  namespace LinuxSampler { namespace gig {
610          ActiveVoiceCountTemp = 0;          ActiveVoiceCountTemp = 0;
611    
612          // handle instrument change commands          // handle instrument change commands
613          instrument_change_command_t command;          bool instrumentChanged = false;
614          if (InstrumentChangeQueue->pop(&command) > 0) {          for (int i = 0; i < engineChannels.size(); i++) {
615              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();  
616    
617              // iterate through all active voices and mark their              // as we're going to (carefully) write some status to the
618              // dimension regions as "in use". The instrument resource              // synchronized struct, we cast away the const
619              // manager may delete all of the instrument except the              EngineChannel::instrument_change_command_t& cmd =
620              // dimension regions and samples that are in use.                  const_cast<EngineChannel::instrument_change_command_t&>(pEngineChannel->InstrumentChangeCommandReader.Lock());
621              int i = 0;  
622              RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();              pEngineChannel->pDimRegionsInUse = cmd.pDimRegionsInUse;
623              RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();              pEngineChannel->pDimRegionsInUse->clear();
624              while (iuiKey != end) { // iterate through all active keys  
625                  midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];              if (cmd.bChangeInstrument) {
626                  ++iuiKey;                  // change instrument
627                    dmsg(5,("Engine: instrument change command received\n"));
628                    cmd.bChangeInstrument = false;
629                    pEngineChannel->pInstrument = cmd.pInstrument;
630                    instrumentChanged = true;
631    
632                    // Iterate through all active voices and mark them as
633                    // "orphans", which means that the dimension regions
634                    // and samples they use should be released to the
635                    // instrument resource manager when the voices die.
636                    int i = 0;
637                    RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
638                    RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
639                    while (iuiKey != end) { // iterate through all active keys
640                        midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
641                        ++iuiKey;
642    
643                  RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();                      RTList<Voice>::Iterator itVoice     = pKey->pActiveVoices->first();
644                  RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();                      RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
645                  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) {  
646                          itVoice->Orphan = true;                          itVoice->Orphan = true;
                         pDimRegionsInUse[i++] = itVoice->pDimRgn;  
647                      }                      }
648                  }                  }
649              }              }
650              pDimRegionsInUse[i] = 0; // end of list          }
651            if (instrumentChanged) {
652              // 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
653              instrument_change_reply_t reply;              ResetSuspendedRegions();
             InstrumentChangeReplyQueue->push(&reply);  
654          }          }
655    
656          // handle events on all engine channels          // handle events on all engine channels
# Line 686  namespace LinuxSampler { namespace gig { Line 693  namespace LinuxSampler { namespace gig {
693          // been deleted by the disk thread          // been deleted by the disk thread
694          if (iPendingStreamDeletions) ProcessPendingStreamDeletions();          if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
695    
696            for (int i = 0; i < engineChannels.size(); i++) {
697                engineChannels[i]->InstrumentChangeCommandReader.Unlock();
698            }
699          FrameTime += Samples;          FrameTime += Samples;
700    
701          return 0;          return 0;
# Line 767  namespace LinuxSampler { namespace gig { Line 777  namespace LinuxSampler { namespace gig {
777                  // now render current voice                  // now render current voice
778                  itVoice->Render(Samples);                  itVoice->Render(Samples);
779                  if (itVoice->IsActive()) { // still active                  if (itVoice->IsActive()) { // still active
780                        if (!itVoice->Orphan) {
781                            *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itVoice->pDimRgn;
782                        }
783                      ActiveVoiceCountTemp++;                      ActiveVoiceCountTemp++;
784                      voiceCount++;                      voiceCount++;
785    
# Line 807  namespace LinuxSampler { namespace gig { Line 820  namespace LinuxSampler { namespace gig {
820              if (itNewVoice) {              if (itNewVoice) {
821                  itNewVoice->Render(Samples);                  itNewVoice->Render(Samples);
822                  if (itNewVoice->IsActive()) { // still active                  if (itNewVoice->IsActive()) { // still active
823                        *(pEngineChannel->pDimRegionsInUse->allocAppend()) = itNewVoice->pDimRgn;
824                      ActiveVoiceCountTemp++;                      ActiveVoiceCountTemp++;
825                      pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);                      pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
826    
# Line 842  namespace LinuxSampler { namespace gig { Line 856  namespace LinuxSampler { namespace gig {
856       *                         this audio fragment cycle       *                         this audio fragment cycle
857       */       */
858      void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {      void Engine::RouteAudio(EngineChannel* pEngineChannel, uint Samples) {
859          // route master signal          // route dry signal
860          {          {
861              AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);              AudioChannel* pDstL = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelLeft);
862              AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);              AudioChannel* pDstR = pAudioOutputDevice->Channel(pEngineChannel->AudioDeviceChannelRight);
# Line 853  namespace LinuxSampler { namespace gig { Line 867  namespace LinuxSampler { namespace gig {
867          {          {
868              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
869                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
870                  // left channel                  for (int iChan = 0; iChan < 2; ++iChan) {
871                  const int iDstL = pFxSend->DestinationChannel(0);                      AudioChannel* pSource =
872                  if (iDstL < 0) {                          (iChan)
873                      dmsg(1,("Engine::RouteAudio() Error: invalid FX send (L) destination channel"));                              ? pEngineChannel->pChannelRight
874                  } else {                              : pEngineChannel->pChannelLeft;
875                      AudioChannel* pDstL = pAudioOutputDevice->Channel(iDstL);                      const int iDstChan = pFxSend->DestinationChannel(iChan);
876                      if (!pDstL) {                      if (iDstChan < 0) {
877                          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));
878                      } else pEngineChannel->pChannelLeft->MixTo(pDstL, Samples, pFxSend->Level());                          goto channel_cleanup;
879                  }                      }
880                  // right channel                      AudioChannel* pDstChan = NULL;
881                  const int iDstR = pFxSend->DestinationChannel(1);                      if (pFxSend->DestinationMasterEffectChain() >= 0) { // fx send routed to an internal master effect
882                  if (iDstR < 0) {                          EffectChain* pEffectChain =
883                      dmsg(1,("Engine::RouteAudio() Error: invalid FX send (R) destination channel"));                              pAudioOutputDevice->MasterEffectChain(
884                  } else {                                  pFxSend->DestinationMasterEffectChain()
885                      AudioChannel* pDstR = pAudioOutputDevice->Channel(iDstR);                              );
886                      if (!pDstR) {                          if (!pEffectChain) {
887                          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()));
888                      } else pEngineChannel->pChannelRight->MixTo(pDstR, Samples, pFxSend->Level());                              goto channel_cleanup;
889                            }
890                            Effect* pEffect =
891                                pEffectChain->GetEffect(
892                                    pFxSend->DestinationMasterEffect()
893                                );
894                            if (!pEffect) {
895                                dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination effect %d of effect chain %d", ((iChan) ? "R" : "L"), pFxSend->DestinationMasterEffect(), pFxSend->DestinationMasterEffectChain()));
896                                goto channel_cleanup;
897                            }
898                            pDstChan = pEffect->InputChannel(iDstChan);
899                        } else { // FX send routed directly to an audio output channel
900                            pDstChan = pAudioOutputDevice->Channel(iDstChan);
901                        }
902                        if (!pDstChan) {
903                            dmsg(1,("Engine::RouteAudio() Error: invalid FX send (%s) destination channel (%d->%d)", ((iChan) ? "R" : "L"), iChan, iDstChan));
904                            goto channel_cleanup;
905                        }
906                        pSource->MixTo(pDstChan, Samples, pFxSend->Level());
907                  }                  }
908              }              }
909          }          }
910            channel_cleanup:
911          // reset buffers with silence (zero out) for the next audio cycle          // reset buffers with silence (zero out) for the next audio cycle
912          pEngineChannel->pChannelLeft->Clear();          pEngineChannel->pChannelLeft->Clear();
913          pEngineChannel->pChannelRight->Clear();          pEngineChannel->pChannelRight->Clear();
# Line 920  namespace LinuxSampler { namespace gig { Line 953  namespace LinuxSampler { namespace gig {
953       *       *
954       *  @param pData - pointer to sysex data       *  @param pData - pointer to sysex data
955       *  @param Size  - lenght of sysex data (in bytes)       *  @param Size  - lenght of sysex data (in bytes)
956         *  @param pSender - the MIDI input port on which the SysEx message was
957         *                   received
958       */       */
959      void Engine::SendSysex(void* pData, uint Size) {      void Engine::SendSysex(void* pData, uint Size, MidiInputPort* pSender) {
960          Event event             = pEventGenerator->CreateEvent();          Event event             = pEventGenerator->CreateEvent();
961          event.Type              = Event::type_sysex;          event.Type              = Event::type_sysex;
962          event.Param.Sysex.Size  = Size;          event.Param.Sysex.Size  = Size;
963          event.pEngineChannel    = NULL; // as Engine global event          event.pEngineChannel    = NULL; // as Engine global event
964            event.pMidiInputPort    = pSender;
965          if (pEventQueue->write_space() > 0) {          if (pEventQueue->write_space() > 0) {
966              if (pSysexBuffer->write_space() >= Size) {              if (pSysexBuffer->write_space() >= Size) {
967                  // copy sysex data to input buffer                  // copy sysex data to input buffer
# Line 1603  namespace LinuxSampler { namespace gig { Line 1639  namespace LinuxSampler { namespace gig {
1639      void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {      void Engine::ProcessControlChange(EngineChannel* pEngineChannel, Pool<Event>::Iterator& itControlChangeEvent) {
1640          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));
1641    
1642            // handle the "control triggered" MIDI rule: a control change
1643            // event can trigger a new note on or note off event
1644            if (pEngineChannel->pInstrument) {
1645    
1646                ::gig::MidiRule* rule;
1647                for (int i = 0 ; (rule = pEngineChannel->pInstrument->GetMidiRule(i)) ; i++) {
1648    
1649                    if (::gig::MidiRuleCtrlTrigger* ctrlTrigger =
1650                        dynamic_cast< ::gig::MidiRuleCtrlTrigger*>(rule)) {
1651                        if (itControlChangeEvent->Param.CC.Controller ==
1652                            ctrlTrigger->ControllerNumber) {
1653    
1654                            uint8_t oldCCValue = pEngineChannel->ControllerTable[
1655                                itControlChangeEvent->Param.CC.Controller];
1656                            uint8_t newCCValue = itControlChangeEvent->Param.CC.Value;
1657    
1658                            for (int i = 0 ; i < ctrlTrigger->Triggers ; i++) {
1659                                ::gig::MidiRuleCtrlTrigger::trigger_t* pTrigger =
1660                                      &ctrlTrigger->pTriggers[i];
1661    
1662                                // check if the controller has passed the
1663                                // trigger point in the right direction
1664                                if ((pTrigger->Descending &&
1665                                     oldCCValue > pTrigger->TriggerPoint &&
1666                                     newCCValue <= pTrigger->TriggerPoint) ||
1667                                    (!pTrigger->Descending &&
1668                                     oldCCValue < pTrigger->TriggerPoint &&
1669                                     newCCValue >= pTrigger->TriggerPoint)) {
1670    
1671                                    RTList<Event>::Iterator itNewEvent = pGlobalEvents->allocAppend();
1672                                    if (itNewEvent) {
1673                                        *itNewEvent = *itControlChangeEvent;
1674                                        itNewEvent->Param.Note.Key = pTrigger->Key;
1675    
1676                                        if (pTrigger->NoteOff || pTrigger->Velocity == 0) {
1677                                            itNewEvent->Type = Event::type_note_off;
1678                                            itNewEvent->Param.Note.Velocity = 100;
1679    
1680                                            ProcessNoteOff(pEngineChannel, itNewEvent);
1681                                        } else {
1682                                            itNewEvent->Type = Event::type_note_on;
1683                                            //TODO: if Velocity is 255, the triggered velocity should
1684                                            // depend on how fast the controller is moving
1685                                            itNewEvent->Param.Note.Velocity =
1686                                                pTrigger->Velocity == 255 ? 100 :
1687                                                pTrigger->Velocity;
1688    
1689                                            ProcessNoteOn(pEngineChannel, itNewEvent);
1690                                        }
1691                                    }
1692                                    else dmsg(1,("Event pool emtpy!\n"));
1693                                }
1694                            }
1695                        }
1696                    }
1697                }
1698            }
1699    
1700          // update controller value in the engine channel's controller table          // update controller value in the engine channel's controller table
1701          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;          pEngineChannel->ControllerTable[itControlChangeEvent->Param.CC.Controller] = itControlChangeEvent->Param.CC.Value;
1702    
# Line 1636  namespace LinuxSampler { namespace gig { Line 1730  namespace LinuxSampler { namespace gig {
1730                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1731                  pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];                  pEngineChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];
1732                  pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];                  pEngineChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];
1733                    pEngineChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1734                  break;                  break;
1735              }              }
1736              case 64: { // sustain              case 64: { // sustain
# Line 1776  namespace LinuxSampler { namespace gig { Line 1871  namespace LinuxSampler { namespace gig {
1871          if (!pEngineChannel->fxSends.empty()) {          if (!pEngineChannel->fxSends.empty()) {
1872              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {              for (int iFxSend = 0; iFxSend < pEngineChannel->GetFxSendCount(); iFxSend++) {
1873                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1874                  if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)                  if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller) {
1875                      pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);                      pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1876                      pFxSend->SetInfoChanged(true);                      pFxSend->SetInfoChanged(true);
1877                    }
1878              }              }
1879          }          }
1880      }      }
# Line 1797  namespace LinuxSampler { namespace gig { Line 1893  namespace LinuxSampler { namespace gig {
1893          if (exclusive_status != 0xF0)       goto free_sysex_data;          if (exclusive_status != 0xF0)       goto free_sysex_data;
1894    
1895          switch (id) {          switch (id) {
1896                case 0x7f: { // (Realtime) Universal Sysex (GM Standard)
1897                    uint8_t sysex_channel, sub_id1, sub_id2, val_msb, val_lsb;;
1898                    if (!reader.pop(&sysex_channel)) goto free_sysex_data;
1899                    if (!reader.pop(&sub_id1)) goto free_sysex_data;
1900                    if (!reader.pop(&sub_id2)) goto free_sysex_data;
1901                    if (!reader.pop(&val_lsb)) goto free_sysex_data;
1902                    if (!reader.pop(&val_msb)) goto free_sysex_data;
1903                    //TODO: for now we simply ignore the sysex channel, seldom used anyway
1904                    switch (sub_id1) {
1905                        case 0x04: // Device Control
1906                            switch (sub_id2) {
1907                                case 0x01: { // Master Volume
1908                                    const double volume =
1909                                        double((uint(val_msb)<<7) | uint(val_lsb)) / 16383.0;
1910                                    #if CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
1911                                    // apply volume to all sampler channels that
1912                                    // are connected to the same MIDI input port
1913                                    // this sysex message arrived on
1914                                    for (int i = 0; i < engineChannels.size(); ++i) {
1915                                        EngineChannel* pEngineChannel = engineChannels[i];
1916                                        if (pEngineChannel->GetMidiInputPort() ==
1917                                            itSysexEvent->pMidiInputPort)
1918                                        {
1919                                            pEngineChannel->Volume(volume);
1920                                        }
1921                                    }
1922                                    #else
1923                                    // apply volume globally to the whole sampler
1924                                    GLOBAL_VOLUME = volume;
1925                                    #endif // CONFIG_MASTER_VOLUME_SYSEX_BY_PORT
1926                                    break;
1927                                }
1928                            }
1929                            break;
1930                    }
1931                    break;
1932                }
1933              case 0x41: { // Roland              case 0x41: { // Roland
1934                  dmsg(3,("Roland Sysex\n"));                  dmsg(3,("Roland Sysex\n"));
1935                  uint8_t device_id, model_id, cmd_id;                  uint8_t device_id, model_id, cmd_id;
# Line 1833  namespace LinuxSampler { namespace gig { Line 1966  namespace LinuxSampler { namespace gig {
1966                              dmsg(3,("\t\t\tNew scale applied.\n"));                              dmsg(3,("\t\t\tNew scale applied.\n"));
1967                              break;                              break;
1968                          }                          }
1969                            case 0x15: { // chromatic / drumkit mode
1970                                dmsg(3,("\t\tMIDI Instrument Map Switch\n"));
1971                                uint8_t part = addr[1] & 0x0f;
1972                                uint8_t map;
1973                                if (!reader.pop(&map)) goto free_sysex_data;
1974                                for (int i = 0; i < engineChannels.size(); ++i) {
1975                                    EngineChannel* pEngineChannel = engineChannels[i];
1976                                    if (
1977                                        (pEngineChannel->midiChannel == part ||
1978                                         pEngineChannel->midiChannel == midi_chan_all) &&
1979                                         pEngineChannel->GetMidiInputPort() == itSysexEvent->pMidiInputPort
1980                                    ) {
1981                                        try {
1982                                            pEngineChannel->SetMidiInstrumentMap(map);
1983                                        } catch (Exception e) {
1984                                            dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d: %s\n", map, part, e.Message().c_str()));
1985                                            goto free_sysex_data;
1986                                        } catch (...) {
1987                                            dmsg(2,("\t\t\tCould not apply MIDI instrument map %d to part %d (unknown exception)\n", map, part));
1988                                            goto free_sysex_data;
1989                                        }
1990                                    }
1991                                }
1992                                dmsg(3,("\t\t\tApplied MIDI instrument map %d to part %d.\n", map, part));
1993                                break;
1994                            }
1995                      }                      }
1996                  }                  }
1997                  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 1971  namespace LinuxSampler { namespace gig { Line 2130  namespace LinuxSampler { namespace gig {
2130      }      }
2131    
2132      String Engine::Description() {      String Engine::Description() {
2133          return "Gigasampler Engine";          return "Gigasampler Format Engine";
2134      }      }
2135    
2136      String Engine::Version() {      String Engine::Version() {
2137          String s = "$Revision: 1.82 $";          String s = "$Revision: 1.96 $";
2138          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
2139      }      }
2140    
# Line 1984  namespace LinuxSampler { namespace gig { Line 2143  namespace LinuxSampler { namespace gig {
2143      }      }
2144    
2145      // static constant initializers      // static constant initializers
2146      const float* Engine::VolumeCurve(InitVolumeCurve());      const Engine::FloatTable Engine::VolumeCurve(InitVolumeCurve());
2147      const float* Engine::PanCurve(InitPanCurve());      const Engine::FloatTable Engine::PanCurve(InitPanCurve());
2148      const float* Engine::CrossfadeCurve(InitCrossfadeCurve());      const Engine::FloatTable Engine::CrossfadeCurve(InitCrossfadeCurve());
2149    
2150      float* Engine::InitVolumeCurve() {      float* Engine::InitVolumeCurve() {
2151          // line-segment approximation          // line-segment approximation
# Line 2025  namespace LinuxSampler { namespace gig { Line 2184  namespace LinuxSampler { namespace gig {
2184          return y;          return y;
2185      }      }
2186    
     /**  
      * 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;  
     }  
   
2187  }} // namespace LinuxSampler::gig  }} // namespace LinuxSampler::gig

Legend:
Removed from v.1399  
changed lines
  Added in v.1762

  ViewVC Help
Powered by ViewVC