/[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 1038 by persson, Sat Feb 3 15:33:00 2007 UTC revision 1481 by senoner, Wed Nov 14 23:42:15 2007 UTC
# 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 51  namespace LinuxSampler { namespace gig { Line 53  namespace LinuxSampler { namespace gig {
53          if (engines.count(pDevice)) {          if (engines.count(pDevice)) {
54              dmsg(4,("Using existing gig::Engine.\n"));              dmsg(4,("Using existing gig::Engine.\n"));
55              pEngine = engines[pDevice];              pEngine = engines[pDevice];
56    
57                // Disable the engine while the new engine channel is
58                // added and initialized. The engine will be enabled again
59                // in EngineChannel::Connect.
60                pEngine->DisableAndLock();
61          } else { // create a new engine (and disk thread) instance for the given audio output device          } else { // create a new engine (and disk thread) instance for the given audio output device
62              dmsg(4,("Creating new gig::Engine.\n"));              dmsg(4,("Creating new gig::Engine.\n"));
63              pEngine = (Engine*) EngineFactory::Create("gig");              pEngine = (Engine*) EngineFactory::Create("gig");
64              pEngine->Connect(pDevice);              pEngine->Connect(pDevice);
65              engines[pDevice] = pEngine;              engines[pDevice] = pEngine;
66          }          }
   
67          // register engine channel to the engine instance          // register engine channel to the engine instance
   
         // Disable the engine while the new engine channel is added  
         // and initialized. The engine will be enabled again in  
         // EngineChannel::Connect.  
         pEngine->DisableAndLock();  
   
68          pEngine->engineChannels.add(pChannel);          pEngine->engineChannels.add(pChannel);
69          // remember index in the ArrayList          // remember index in the ArrayList
70          pChannel->iEngineIndexSelf = pEngine->engineChannels.size() - 1;          pChannel->iEngineIndexSelf = pEngine->engineChannels.size() - 1;
# Line 100  namespace LinuxSampler { namespace gig { Line 100  namespace LinuxSampler { namespace gig {
100      /**      /**
101       * Constructor       * Constructor
102       */       */
103      Engine::Engine() {      Engine::Engine() : SuspendedRegions(128) {
104          pAudioOutputDevice = NULL;          pAudioOutputDevice = NULL;
105          pDiskThread        = NULL;          pDiskThread        = NULL;
106          pEventGenerator    = NULL;          pEventGenerator    = NULL;
# Line 121  namespace LinuxSampler { namespace gig { Line 121  namespace LinuxSampler { namespace gig {
121    
122          ResetInternal();          ResetInternal();
123          ResetScaleTuning();          ResetScaleTuning();
124            ResetSuspendedRegions();
125      }      }
126    
127      /**      /**
# Line 143  namespace LinuxSampler { namespace gig { Line 144  namespace LinuxSampler { namespace gig {
144          if (pEventGenerator) delete pEventGenerator;          if (pEventGenerator) delete pEventGenerator;
145          if (pVoiceStealingQueue) delete pVoiceStealingQueue;          if (pVoiceStealingQueue) delete pVoiceStealingQueue;
146          if (pSysexBuffer) delete pSysexBuffer;          if (pSysexBuffer) delete pSysexBuffer;
147            if (pGlobalEvents) delete pGlobalEvents;
148            if (InstrumentChangeQueue) delete InstrumentChangeQueue;
149            if (InstrumentChangeReplyQueue) delete InstrumentChangeReplyQueue;
150            if (pDimRegionsInUse) delete[] pDimRegionsInUse;
151            ResetSuspendedRegions();
152          Unregister();          Unregister();
153      }      }
154    
# Line 152  namespace LinuxSampler { namespace gig { Line 158  namespace LinuxSampler { namespace gig {
158          dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));          dmsg(3,("gig::Engine: enabled (val=%d)\n", EngineDisabled.GetUnsafe()));
159      }      }
160    
161        /**
162         * Temporarily stop the engine to not do anything. The engine will just be
163         * frozen during that time, that means after enabling it again it will
164         * continue where it was, with all its voices and playback state it had at
165         * the point of disabling. Notice that the engine's (audio) thread will
166         * continue to run, it just remains in an inactive loop during that time.
167         *
168         * If you need to be sure that all voices and disk streams are killed as
169         * well, use @c SuspendAll() instead.
170         *
171         * @see Enable(), SuspendAll()
172         */
173      void Engine::Disable() {      void Engine::Disable() {
174          dmsg(3,("gig::Engine: disabling\n"));          dmsg(3,("gig::Engine: disabling\n"));
175          bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s          bool* pWasDisabled = EngineDisabled.PushAndUnlock(true, 2); // wait max. 2s
# Line 165  namespace LinuxSampler { namespace gig { Line 183  namespace LinuxSampler { namespace gig {
183      }      }
184    
185      /**      /**
186         * Similar to @c Disable() but this method additionally kills all voices
187         * and disk streams and blocks until all voices and disk streams are actually
188         * killed / deleted.
189         *
190         * @e Note: only the original calling thread is able to re-enable the
191         * engine afterwards by calling @c ResumeAll() later on!
192         */
193        void Engine::SuspendAll() {
194            dmsg(2,("gig::Engine: Suspending all ...\n"));
195            // stop the engine, so we can safely modify the engine's
196            // data structures from this foreign thread
197            DisableAndLock();
198            // we could also use the respective class member variable here,
199            // but this is probably safer and cleaner
200            int iPendingStreamDeletions = 0;
201            // kill all voices on all engine channels the *die hard* way
202            for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
203                EngineChannel* pEngineChannel = engineChannels[iChannel];
204                RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
205                RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
206                for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
207                    midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
208                    RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
209                    RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
210                    for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
211                        // request a notification from disk thread side for stream deletion
212                        const Stream::Handle hStream = itVoice->KillImmediately(true);
213                        if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
214                            iPendingStreamDeletions++;
215                        }
216                    }
217                }
218            }
219            // wait until all streams were actually deleted by the disk thread
220            while (iPendingStreamDeletions) {
221                while (
222                    iPendingStreamDeletions &&
223                    pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
224                ) iPendingStreamDeletions--;
225                if (!iPendingStreamDeletions) break;
226                usleep(10000); // sleep for 10ms
227            }
228            dmsg(2,("gig::Engine: Everything suspended.\n"));
229        }
230    
231        /**
232         * At the moment same as calling @c Enable() directly, but this might
233         * change in future, so better call this method as counterpart to
234         * @c SuspendAll() instead of @c Enable() !
235         */
236        void Engine::ResumeAll() {
237            Enable();
238        }
239    
240        /**
241         * Order the engine to stop rendering audio for the given region.
242         * Additionally this method will block until all voices and their disk
243         * streams associated with that region are actually killed / deleted, so
244         * one can i.e. safely modify the region with an instrument editor after
245         * returning from this method.
246         *
247         * @param pRegion - region the engine shall stop using
248         */
249        void Engine::Suspend(::gig::Region* pRegion) {
250            dmsg(2,("gig::Engine: Suspending Region %x ...\n",pRegion));
251            SuspendedRegionsMutex.Lock();
252            SuspensionChangeOngoing.Set(true);
253            pPendingRegionSuspension = pRegion;
254            SuspensionChangeOngoing.WaitAndUnlockIf(true);
255            SuspendedRegionsMutex.Unlock();
256            dmsg(2,("gig::Engine: Region %x suspended.",pRegion));
257        }
258    
259        /**
260         * Orders the engine to resume playing back the given region, previously
261         * suspended with @c Suspend() .
262         *
263         * @param pRegion - region the engine shall be allowed to use again
264         */
265        void Engine::Resume(::gig::Region* pRegion) {
266            dmsg(2,("gig::Engine: Resuming Region %x ...\n",pRegion));
267            SuspendedRegionsMutex.Lock();
268            SuspensionChangeOngoing.Set(true);
269            pPendingRegionResumption = pRegion;
270            SuspensionChangeOngoing.WaitAndUnlockIf(true);
271            SuspendedRegionsMutex.Unlock();
272            dmsg(2,("gig::Engine: Region %x resumed.\n",pRegion));
273        }
274    
275        /**
276       *  Reset all voices and disk thread and clear input event queue and all       *  Reset all voices and disk thread and clear input event queue and all
277       *  control and status variables.       *  control and status variables.
278       */       */
# Line 219  namespace LinuxSampler { namespace gig { Line 327  namespace LinuxSampler { namespace gig {
327          memset(&ScaleTuning[0], 0x00, 12);          memset(&ScaleTuning[0], 0x00, 12);
328      }      }
329    
330        void Engine::ResetSuspendedRegions() {
331            SuspendedRegions.clear();
332            iPendingStreamDeletions = 0;
333            pPendingRegionSuspension = pPendingRegionResumption = NULL;
334            SuspensionChangeOngoing.Set(false);
335        }
336    
337      /**      /**
338       * Connect this engine instance with the given audio output device.       * Connect this engine instance with the given audio output device.
339       * This method will be called when an Engine instance is created.       * This method will be called when an Engine instance is created.
# Line 298  namespace LinuxSampler { namespace gig { Line 413  namespace LinuxSampler { namespace gig {
413      }      }
414    
415      /**      /**
416         * Called by the engine's (audio) thread once per cycle to process requests
417         * from the outer world to suspend or resume a given @c gig::Region .
418         */
419        void Engine::ProcessSuspensionsChanges() {
420            // process request for suspending one region
421            if (pPendingRegionSuspension) {
422                // kill all voices on all engine channels that use this region
423                for (int iChannel = 0; iChannel < engineChannels.size(); iChannel++) {
424                    EngineChannel* pEngineChannel = engineChannels[iChannel];
425                    RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
426                    RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
427                    for (; iuiKey != end; ++iuiKey) { // iterate through all active keys
428                        midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[*iuiKey];
429                        RTList<Voice>::Iterator itVoice = pKey->pActiveVoices->first();
430                        // if current key is not associated with this region, skip this key
431                        if (itVoice->pDimRgn->GetParent() != pPendingRegionSuspension) continue;
432                        RTList<Voice>::Iterator itVoicesEnd = pKey->pActiveVoices->end();
433                        for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
434                            // request a notification from disk thread side for stream deletion
435                            const Stream::Handle hStream = itVoice->KillImmediately(true);
436                            if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
437                                iPendingStreamDeletions++;
438                            }
439                        }
440                    }
441                }
442                // make sure the region is not yet on the list
443                bool bAlreadySuspended = false;
444                RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
445                RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
446                for (; iter != end; ++iter) { // iterate through all suspended regions
447                    if (*iter == pPendingRegionSuspension) { // found
448                        bAlreadySuspended = true;
449                        dmsg(1,("gig::Engine: attempt to suspend an already suspended region !!!\n"));
450                        break;
451                    }
452                }
453                if (!bAlreadySuspended) {
454                    // put the region on the list of suspended regions
455                    RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.allocAppend();
456                    if (iter) {
457                        *iter = pPendingRegionSuspension;
458                    } else std::cerr << "gig::Engine: Could not suspend Region, list is full. This is a bug!!!\n" << std::flush;
459                }
460                // free request slot for next caller (and to make sure that
461                // we're not going to process the same request in the next cycle)
462                pPendingRegionSuspension = NULL;
463                // if no disk stream deletions are pending, awaker other side, as
464                // we're done in this case
465                if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
466            }
467    
468            // process request for resuming one region
469            if (pPendingRegionResumption) {
470                // remove region from the list of suspended regions
471                RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
472                RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
473                for (; iter != end; ++iter) { // iterate through all suspended regions
474                    if (*iter == pPendingRegionResumption) { // found
475                        SuspendedRegions.free(iter);
476                        break; // done
477                    }
478                }
479                // free request slot for next caller
480                pPendingRegionResumption = NULL;
481                // awake other side as we're done
482                SuspensionChangeOngoing.Set(false);
483            }
484        }
485    
486        /**
487         * Called by the engine's (audio) thread once per cycle to check if
488         * streams of voices that were killed due to suspension request have
489         * finally really been deleted by the disk thread.
490         */
491        void Engine::ProcessPendingStreamDeletions() {
492            if (!iPendingStreamDeletions) return;
493            //TODO: or shall we better store a list with stream handles instead of a scalar amount of streams to be deleted? might be safer
494            while (
495                iPendingStreamDeletions &&
496                pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE
497            ) iPendingStreamDeletions--;
498            // just for safety ...
499            while (pDiskThread->AskForDeletedStream() != Stream::INVALID_HANDLE);
500            // now that all disk streams are deleted, awake other side as
501            // we're finally done with suspending the requested region
502            if (!iPendingStreamDeletions) SuspensionChangeOngoing.Set(false);
503        }
504    
505        /**
506         * Returns @c true if the given region is currently set to be suspended
507         * from being used, @c false otherwise.
508         */
509        bool Engine::RegionSuspended(::gig::Region* pRegion) {
510            if (SuspendedRegions.isEmpty()) return false;
511            //TODO: or shall we use a sorted container instead of the RTList? might be faster ... or trivial ;-)
512            RTList< ::gig::Region*>::Iterator iter = SuspendedRegions.first();
513            RTList< ::gig::Region*>::Iterator end  = SuspendedRegions.end();
514            for (; iter != end; ++iter)  // iterate through all suspended regions
515                if (*iter == pRegion) return true;
516            return false;
517        }
518    
519        /**
520       * Clear all engine global event lists.       * Clear all engine global event lists.
521       */       */
522      void Engine::ClearEventLists() {      void Engine::ClearEventLists() {
# Line 352  namespace LinuxSampler { namespace gig { Line 571  namespace LinuxSampler { namespace gig {
571       *  @returns       0 on success       *  @returns       0 on success
572       */       */
573      int Engine::RenderAudio(uint Samples) {      int Engine::RenderAudio(uint Samples) {
574          dmsg(7,("RenderAudio(Samples=%d)\n", Samples));          dmsg(8,("RenderAudio(Samples=%d)\n", Samples));
575    
576          // return if engine disabled          // return if engine disabled
577          if (EngineDisabled.Pop()) {          if (EngineDisabled.Pop()) {
# Line 360  namespace LinuxSampler { namespace gig { Line 579  namespace LinuxSampler { namespace gig {
579              return 0;              return 0;
580          }          }
581    
582            // process requests for suspending / resuming regions (i.e. to avoid
583            // crashes while these regions are modified by an instrument editor)
584            ProcessSuspensionsChanges();
585    
586          // update time of start and end of this audio fragment (as events' time stamps relate to this)          // update time of start and end of this audio fragment (as events' time stamps relate to this)
587          pEventGenerator->UpdateFragmentTime(Samples);          pEventGenerator->UpdateFragmentTime(Samples);
588    
# Line 395  namespace LinuxSampler { namespace gig { Line 618  namespace LinuxSampler { namespace gig {
618              EngineChannel* pEngineChannel = command.pEngineChannel;              EngineChannel* pEngineChannel = command.pEngineChannel;
619              pEngineChannel->pInstrument = command.pInstrument;              pEngineChannel->pInstrument = command.pInstrument;
620    
621                //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
622                ResetSuspendedRegions();
623    
624              // iterate through all active voices and mark their              // iterate through all active voices and mark their
625              // dimension regions as "in use". The instrument resource              // dimension regions as "in use". The instrument resource
626              // manager may delete all of the instrument except the              // manager may delete all of the instrument except the
# Line 457  namespace LinuxSampler { namespace gig { Line 683  namespace LinuxSampler { namespace gig {
683          ActiveVoiceCount = ActiveVoiceCountTemp;          ActiveVoiceCount = ActiveVoiceCountTemp;
684          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;          if (ActiveVoiceCount > ActiveVoiceCountMax) ActiveVoiceCountMax = ActiveVoiceCount;
685    
686            // in case regions were previously suspended and we killed voices
687            // with disk streams due to that, check if those streams have finally
688            // been deleted by the disk thread
689            if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
690    
691          FrameTime += Samples;          FrameTime += Samples;
692    
693          return 0;          return 0;
# Line 524  namespace LinuxSampler { namespace gig { Line 755  namespace LinuxSampler { namespace gig {
755          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
756          #endif          #endif
757    
758            uint voiceCount = 0;
759            uint streamCount = 0;
760          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();          RTList<uint>::Iterator iuiKey = pEngineChannel->pActiveKeys->first();
761          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();          RTList<uint>::Iterator end    = pEngineChannel->pActiveKeys->end();
762          while (iuiKey != end) { // iterate through all active keys          while (iuiKey != end) { // iterate through all active keys
# Line 535  namespace LinuxSampler { namespace gig { Line 768  namespace LinuxSampler { namespace gig {
768              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key              for (; itVoice != itVoicesEnd; ++itVoice) { // iterate through all voices on this key
769                  // now render current voice                  // now render current voice
770                  itVoice->Render(Samples);                  itVoice->Render(Samples);
771                  if (itVoice->IsActive()) ActiveVoiceCountTemp++; // still active                  if (itVoice->IsActive()) { // still active
772                  else { // voice reached end, is now inactive                      ActiveVoiceCountTemp++;
773                        voiceCount++;
774    
775                        if (itVoice->PlaybackState == Voice::playback_state_disk) {
776                            if ((itVoice->DiskStreamRef).State == Stream::state_active) streamCount++;
777                        }
778                    }  else { // voice reached end, is now inactive
779                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itVoice); // remove voice from the list of active voices
780                  }                  }
781              }              }
782          }          }
783    
784            pEngineChannel->SetVoiceCount(voiceCount);
785            pEngineChannel->SetDiskStreamCount(streamCount);
786      }      }
787    
788      /**      /**
# Line 566  namespace LinuxSampler { namespace gig { Line 808  namespace LinuxSampler { namespace gig {
808                  LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);                  LaunchVoice(pEngineChannel, itVoiceStealEvent, itVoiceStealEvent->Param.Note.Layer, itVoiceStealEvent->Param.Note.ReleaseTrigger, false, false);
809              if (itNewVoice) {              if (itNewVoice) {
810                  itNewVoice->Render(Samples);                  itNewVoice->Render(Samples);
811                  if (itNewVoice->IsActive()) ActiveVoiceCountTemp++; // still active                  if (itNewVoice->IsActive()) { // still active
812                  else { // voice reached end, is now inactive                      ActiveVoiceCountTemp++;
813                        pEngineChannel->SetVoiceCount(pEngineChannel->GetVoiceCount() + 1);
814    
815                        if (itNewVoice->PlaybackState == Voice::playback_state_disk) {
816                            if (itNewVoice->DiskStreamRef.State == Stream::state_active) {
817                                pEngineChannel->SetDiskStreamCount(pEngineChannel->GetDiskStreamCount() + 1);
818                            }
819                        }
820                    } else { // voice reached end, is now inactive
821                      FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices                      FreeVoice(pEngineChannel, itNewVoice); // remove voice from the list of active voices
822                  }                  }
823              }              }
# Line 711  namespace LinuxSampler { namespace gig { Line 961  namespace LinuxSampler { namespace gig {
961    
962          if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded          if (!pEngineChannel->pInstrument) return; // ignore if no instrument loaded
963    
964            //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing
965            itNoteOnEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
966    
967          const int key = itNoteOnEvent->Param.Note.Key;          const int key = itNoteOnEvent->Param.Note.Key;
968          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[key];
969    
# Line 768  namespace LinuxSampler { namespace gig { Line 1021  namespace LinuxSampler { namespace gig {
1021          {          {
1022              // first, get total amount of required voices (dependant on amount of layers)              // first, get total amount of required voices (dependant on amount of layers)
1023              ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);              ::gig::Region* pRegion = pEngineChannel->pInstrument->GetRegion(itNoteOnEventOnKeyList->Param.Note.Key);
1024              if (pRegion) {              if (pRegion && !RegionSuspended(pRegion)) {
1025                  int voicesRequired = pRegion->Layers;                  int voicesRequired = pRegion->Layers;
1026                  // now launch the required amount of voices                  // now launch the required amount of voices
1027                  for (int i = 0; i < voicesRequired; i++)                  for (int i = 0; i < voicesRequired; i++)
# Line 798  namespace LinuxSampler { namespace gig { Line 1051  namespace LinuxSampler { namespace gig {
1051          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted          if (pEngineChannel->GetMute()) return; // skip if sampler channel is muted
1052          #endif          #endif
1053    
1054            //HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing
1055            itNoteOffEvent->Param.Note.Key += pEngineChannel->GlobalTranspose;
1056    
1057          const int iKey = itNoteOffEvent->Param.Note.Key;          const int iKey = itNoteOffEvent->Param.Note.Key;
1058          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];          midi_key_info_t* pKey = &pEngineChannel->pMIDIKeyInfo[iKey];
1059          pKey->KeyPressed = false; // the MIDI key was now released          pKey->KeyPressed = false; // the MIDI key was now released
# Line 1358  namespace LinuxSampler { namespace gig { Line 1614  namespace LinuxSampler { namespace gig {
1614                  pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;                  pEngineChannel->PortamentoTime = (float) itControlChangeEvent->Param.CC.Value / 127.0f * (float) CONFIG_PORTAMENTO_TIME_MAX + (float) CONFIG_PORTAMENTO_TIME_MIN;
1615                  break;                  break;
1616              }              }
1617                case 6: { // data entry (currently only used for RPN controllers)
1618                    if (pEngineChannel->GetMidiRpnController() == 2) { // coarse tuning in half tones
1619                        int transpose = (int) itControlChangeEvent->Param.CC.Value - 64;
1620                        // limit to +- two octaves for now
1621                        transpose = RTMath::Min(transpose,  24);
1622                        transpose = RTMath::Max(transpose, -24);
1623                        pEngineChannel->GlobalTranspose = transpose;
1624                        // workaround, so we won't have hanging notes
1625                        ReleaseAllVoices(pEngineChannel, itControlChangeEvent);
1626                    }
1627                    // to avoid other MIDI CC #6 messages to be misenterpreted as RPN controller data
1628                    pEngineChannel->ResetMidiRpnController();
1629                    break;
1630                }
1631              case 7: { // volume              case 7: { // volume
1632                  //TODO: not sample accurate yet                  //TODO: not sample accurate yet
1633                  pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];                  pEngineChannel->MidiVolume = VolumeCurve[itControlChangeEvent->Param.CC.Value];
# Line 1418  namespace LinuxSampler { namespace gig { Line 1688  namespace LinuxSampler { namespace gig {
1688                  break;                  break;
1689              }              }
1690              case 65: { // portamento on / off              case 65: { // portamento on / off
1691                  KillAllVoices(pEngineChannel, itControlChangeEvent);                  const bool bPortamento = itControlChangeEvent->Param.CC.Value >= 64;
1692                  pEngineChannel->PortamentoMode = itControlChangeEvent->Param.CC.Value >= 64;                  if (bPortamento != pEngineChannel->PortamentoMode)
1693                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1694                    pEngineChannel->PortamentoMode = bPortamento;
1695                  break;                  break;
1696              }              }
1697              case 66: { // sostenuto              case 66: { // sostenuto
# Line 1462  namespace LinuxSampler { namespace gig { Line 1734  namespace LinuxSampler { namespace gig {
1734                  }                  }
1735                  break;                  break;
1736              }              }
1737                case 100: { // RPN controller LSB
1738                    pEngineChannel->SetMidiRpnControllerLsb(itControlChangeEvent->Param.CC.Value);
1739                    break;
1740                }
1741                case 101: { // RPN controller MSB
1742                    pEngineChannel->SetMidiRpnControllerMsb(itControlChangeEvent->Param.CC.Value);
1743                    break;
1744                }
1745    
1746    
1747              // Channel Mode Messages              // Channel Mode Messages
# Line 1481  namespace LinuxSampler { namespace gig { Line 1761  namespace LinuxSampler { namespace gig {
1761                  break;                  break;
1762              }              }
1763              case 126: { // mono mode on              case 126: { // mono mode on
1764                  KillAllVoices(pEngineChannel, itControlChangeEvent);                  if (!pEngineChannel->SoloMode)
1765                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1766                  pEngineChannel->SoloMode = true;                  pEngineChannel->SoloMode = true;
1767                  break;                  break;
1768              }              }
1769              case 127: { // poly mode on              case 127: { // poly mode on
1770                  KillAllVoices(pEngineChannel, itControlChangeEvent);                  if (pEngineChannel->SoloMode)
1771                        KillAllVoices(pEngineChannel, itControlChangeEvent);
1772                  pEngineChannel->SoloMode = false;                  pEngineChannel->SoloMode = false;
1773                  break;                  break;
1774              }              }
# Line 1498  namespace LinuxSampler { namespace gig { Line 1780  namespace LinuxSampler { namespace gig {
1780                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);                  FxSend* pFxSend = pEngineChannel->GetFxSend(iFxSend);
1781                  if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)                  if (pFxSend->MidiController() == itControlChangeEvent->Param.CC.Controller)
1782                      pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);                      pFxSend->SetLevel(itControlChangeEvent->Param.CC.Value);
1783                        pFxSend->SetInfoChanged(true);
1784              }              }
1785          }          }
1786      }      }
# Line 1694  namespace LinuxSampler { namespace gig { Line 1977  namespace LinuxSampler { namespace gig {
1977      }      }
1978    
1979      String Engine::Version() {      String Engine::Version() {
1980          String s = "$Revision: 1.71 $";          String s = "$Revision: 1.84 $";
1981          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
1982      }      }
1983    

Legend:
Removed from v.1038  
changed lines
  Added in v.1481

  ViewVC Help
Powered by ViewVC