/[svn]/linuxsampler/trunk/src/engines/EngineBase.h
ViewVC logotype

Diff of /linuxsampler/trunk/src/engines/EngineBase.h

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

revision 2298 by iliev, Fri Dec 9 17:04:24 2011 UTC revision 2618 by schoenebeck, Wed Jun 11 11:39:44 2014 UTC
# Line 4  Line 4 
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *   *   Copyright (C) 2003,2004 by Benno Senoner and Christian Schoenebeck    *
6   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *   *   Copyright (C) 2005-2008 Christian Schoenebeck                         *
7   *   Copyright (C) 2009-2011 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2013 Christian Schoenebeck and Grigor Iliev        *
8   *                                                                         *   *                                                                         *
9   *   This program is free software; you can redistribute it and/or modify  *   *   This program is free software; you can redistribute it and/or modify  *
10   *   it under the terms of the GNU General Public License as published by  *   *   it under the terms of the GNU General Public License as published by  *
# Line 104  namespace LinuxSampler { Line 104  namespace LinuxSampler {
104               *  @param Samples - number of sample points to be rendered               *  @param Samples - number of sample points to be rendered
105               *  @returns       0 on success               *  @returns       0 on success
106               */               */
107              virtual int RenderAudio(uint Samples) {              virtual int RenderAudio(uint Samples) OVERRIDE {
108                  dmsg(8,("RenderAudio(Samples=%d)\n", Samples));                  dmsg(8,("RenderAudio(Samples=%d)\n", Samples));
109    
110                  // return if engine disabled                  // return if engine disabled
# Line 143  namespace LinuxSampler { Line 143  namespace LinuxSampler {
143                          }                          }
144                      }                      }
145                  }                  }
146                    
147                    // In case scale tuning has been changed, recalculate pitch for
148                    // all active voices.
149                    ProcessScaleTuningChange();
150    
151                  // reset internal voice counter (just for statistic of active voices)                  // reset internal voice counter (just for statistic of active voices)
152                  ActiveVoiceCountTemp = 0;                  ActiveVoiceCountTemp = 0;
# Line 205  namespace LinuxSampler { Line 209  namespace LinuxSampler {
209                  return 0;                  return 0;
210              }              }
211    
212              virtual int MaxVoices() { return pVoicePool->poolSize(); }              virtual int MaxVoices() OVERRIDE { return pVoicePool->poolSize(); }
213    
214              virtual void SetMaxVoices(int iVoices) throw (Exception) {              virtual void SetMaxVoices(int iVoices) throw (Exception) OVERRIDE {
215                  if (iVoices < 1)                  if (iVoices < 1)
216                      throw Exception("Maximum voices for an engine cannot be set lower than 1");                      throw Exception("Maximum voices for an engine cannot be set lower than 1");
217    
# Line 250  namespace LinuxSampler { Line 254  namespace LinuxSampler {
254              /** Called after the new max number of voices is set and before resuming the engine. */              /** Called after the new max number of voices is set and before resuming the engine. */
255              virtual void PostSetMaxVoices(int iVoices) { }              virtual void PostSetMaxVoices(int iVoices) { }
256    
257              virtual uint DiskStreamCount() { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }              virtual uint DiskStreamCount() OVERRIDE { return (pDiskThread) ? pDiskThread->GetActiveStreamCount() : 0; }
258              virtual uint DiskStreamCountMax() { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }              virtual uint DiskStreamCountMax() OVERRIDE { return (pDiskThread) ? pDiskThread->ActiveStreamCountMax : 0; }
259              virtual int  MaxDiskStreams() { return iMaxDiskStreams; }              virtual int  MaxDiskStreams() OVERRIDE { return iMaxDiskStreams; }
260    
261              virtual void SetMaxDiskStreams(int iStreams) throw (Exception) {              virtual void SetMaxDiskStreams(int iStreams) throw (Exception) OVERRIDE {
262                  if (iStreams < 0)                  if (iStreams < 0)
263                      throw Exception("Maximum disk streams for an engine cannot be set lower than 0");                      throw Exception("Maximum disk streams for an engine cannot be set lower than 0");
264    
# Line 269  namespace LinuxSampler { Line 273  namespace LinuxSampler {
273                  ResumeAll();                  ResumeAll();
274              }              }
275    
276              virtual String DiskStreamBufferFillBytes() { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }              virtual String DiskStreamBufferFillBytes() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillBytes() : ""; }
277              virtual String DiskStreamBufferFillPercentage() { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }              virtual String DiskStreamBufferFillPercentage() OVERRIDE { return (pDiskThread) ? pDiskThread->GetBufferFillPercentage() : ""; }
278              virtual InstrumentManager* GetInstrumentManager() { return &instruments; }              virtual InstrumentManager* GetInstrumentManager() OVERRIDE { return &instruments; }
279    
280              /**              /**
281               * Connect this engine instance with the given audio output device.               * Connect this engine instance with the given audio output device.
# Line 282  namespace LinuxSampler { Line 286  namespace LinuxSampler {
286               *               *
287               * @param pAudioOut - audio output device to connect to               * @param pAudioOut - audio output device to connect to
288               */               */
289              virtual void Connect(AudioOutputDevice* pAudioOut) {              virtual void Connect(AudioOutputDevice* pAudioOut) OVERRIDE {
290                  // caution: don't ignore if connecting to the same device here,                  // caution: don't ignore if connecting to the same device here,
291                  // because otherwise SetMaxDiskStreams() implementation won't work anymore!                  // because otherwise SetMaxDiskStreams() implementation won't work anymore!
292    
# Line 312  namespace LinuxSampler { Line 316  namespace LinuxSampler {
316                      // lower minimum release time                      // lower minimum release time
317                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;                      const float minReleaseTime = (float) MaxSamplesPerCycle / (float) SampleRate;
318                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                      for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
319                          iterVoice->pEG1->CalculateFadeOutCoeff(minReleaseTime, SampleRate);                          iterVoice->CalculateFadeOutCoeff(minReleaseTime, SampleRate);
320                      }                      }
321                      pVoicePool->clear();                      pVoicePool->clear();
322                  }                  }
# Line 368  namespace LinuxSampler { Line 372  namespace LinuxSampler {
372                  pDedicatedVoiceChannelLeft  = new AudioChannel(0, MaxSamplesPerCycle);                  pDedicatedVoiceChannelLeft  = new AudioChannel(0, MaxSamplesPerCycle);
373                  pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);                  pDedicatedVoiceChannelRight = new AudioChannel(1, MaxSamplesPerCycle);
374              }              }
375            
376                // Implementattion for abstract method derived from Engine.
377                virtual void ReconnectAudioOutputDevice() OVERRIDE {
378                    SuspendAll();
379                    if (pAudioOutputDevice) Connect(pAudioOutputDevice);
380                    ResumeAll();
381                }
382    
383              /**              /**
384               * Similar to @c Disable() but this method additionally kills all voices               * Similar to @c Disable() but this method additionally kills all voices
# Line 422  namespace LinuxSampler { Line 433  namespace LinuxSampler {
433               */               */
434              virtual void Suspend(RR* pRegion) {              virtual void Suspend(RR* pRegion) {
435                  dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Suspending Region %x ...\n",pRegion));
436                  SuspendedRegionsMutex.Lock();                  {
437                  SuspensionChangeOngoing.Set(true);                      LockGuard lock(SuspendedRegionsMutex);
438                  pPendingRegionSuspension = pRegion;                      SuspensionChangeOngoing.Set(true);
439                  SuspensionChangeOngoing.WaitAndUnlockIf(true);                      pPendingRegionSuspension = pRegion;
440                  SuspendedRegionsMutex.Unlock();                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
441                    }
442                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));
443              }              }
444    
# Line 438  namespace LinuxSampler { Line 450  namespace LinuxSampler {
450               */               */
451              virtual void Resume(RR* pRegion) {              virtual void Resume(RR* pRegion) {
452                  dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));                  dmsg(2,("EngineBase: Resuming Region %x ...\n",pRegion));
453                  SuspendedRegionsMutex.Lock();                  {
454                  SuspensionChangeOngoing.Set(true);                      LockGuard lock(SuspendedRegionsMutex);
455                  pPendingRegionResumption = pRegion;                      SuspensionChangeOngoing.Set(true);
456                  SuspensionChangeOngoing.WaitAndUnlockIf(true);                      pPendingRegionResumption = pRegion;
457                  SuspendedRegionsMutex.Unlock();                      SuspensionChangeOngoing.WaitAndUnlockIf(true);
458                    }
459                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));
460              }              }
461    
# Line 565  namespace LinuxSampler { Line 578  namespace LinuxSampler {
578              public:              public:
579                  int PendingStreamDeletions;                  int PendingStreamDeletions;
580                  RR* pPendingRegionSuspension;                  RR* pPendingRegionSuspension;
581    
582                  SuspensionVoiceHandler(RR* pPendingRegionSuspension) {                  SuspensionVoiceHandler(RR* pPendingRegionSuspension) {
583                      PendingStreamDeletions = 0;                      PendingStreamDeletions = 0;
584                      this->pPendingRegionSuspension = pPendingRegionSuspension;                      this->pPendingRegionSuspension = pPendingRegionSuspension;
585                  }                  }
586    
587                  virtual bool Process(MidiKey* pMidiKey) {                  virtual bool Process(MidiKey* pMidiKey) OVERRIDE {
588                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();                      VoiceIterator itVoice = pMidiKey->pActiveVoices->first();
589                      // if current key is not associated with this region, skip this key                      // if current key is not associated with this region, skip this key
590                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;                      if (itVoice->GetRegion()->GetParent() != pPendingRegionSuspension) return false;
# Line 578  namespace LinuxSampler { Line 592  namespace LinuxSampler {
592                      return true;                      return true;
593                  }                  }
594    
595                  virtual void Process(VoiceIterator& itVoice) {                  virtual void Process(VoiceIterator& itVoice) OVERRIDE {
596                      // request a notification from disk thread side for stream deletion                      // request a notification from disk thread side for stream deletion
597                      const Stream::Handle hStream = itVoice->KillImmediately(true);                      const Stream::Handle hStream = itVoice->KillImmediately(true);
598                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream                      if (hStream != Stream::INVALID_HANDLE) { // voice actually used a stream
# Line 617  namespace LinuxSampler { Line 631  namespace LinuxSampler {
631                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);                  AbstractEngineChannel* pChannel = static_cast<AbstractEngineChannel*>(pEngineChannel);
632                  pChannel->ImportEvents(Samples);                  pChannel->ImportEvents(Samples);
633    
634                  // process events                  // if a valid real-time instrument script is loaded, pre-process
635                    // the event list by running the script now, since the script
636                    // might filter events or add new ones for this cycle
637                    if (pChannel->pScript && pChannel->pScript->bHasValidScript) {
638                        // resume any suspended script executions still hanging
639                        // around of previous audio fragment cycles
640                        for (RTList<ScriptEvent>::Iterator itEvent = pChannel->pScript->pEvents->first(),
641                            end = pChannel->pScript->pEvents->end(); itEvent != end; ++itEvent)
642                        {
643                            ResumeScriptEvent(pChannel, itEvent); //TODO: implement support for actual suspension time (i.e. passed to a script's wait() function call)
644                        }
645    
646                        // spawn new script executions for the new MIDI events of
647                        // this audio fragment cycle
648                        for (RTList<Event>::Iterator itEvent = pChannel->pEvents->first(),
649                            end = pChannel->pEvents->end(); itEvent != end; ++itEvent)
650                        {
651                            switch (itEvent->Type) {
652                                case Event::type_note_on:
653                                    if (pChannel->pScript->handlerNote)
654                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerNote);
655                                    break;
656                                case Event::type_note_off:
657                                    if (pChannel->pScript->handlerRelease)
658                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerRelease);
659                                    break;
660                                case Event::type_control_change:
661                                case Event::type_channel_pressure:
662                                case Event::type_pitchbend:
663                                    if (pChannel->pScript->handlerController)
664                                        ProcessEventByScript(pChannel, itEvent, pChannel->pScript->handlerController);                            
665                                    break;
666                                case Event::type_note_pressure:
667                                    //TODO: ...
668                                    break;
669                            }
670                        }
671                    }
672    
673                    // now process all events regularly
674                  {                  {
675                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();                      RTList<Event>::Iterator itEvent = pChannel->pEvents->first();
676                      RTList<Event>::Iterator end     = pChannel->pEvents->end();                      RTList<Event>::Iterator end     = pChannel->pEvents->end();
# Line 635  namespace LinuxSampler { Line 688  namespace LinuxSampler {
688                                  dmsg(5,("Engine: MIDI CC received\n"));                                  dmsg(5,("Engine: MIDI CC received\n"));
689                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);                                  ProcessControlChange((EngineChannel*)itEvent->pEngineChannel, itEvent);
690                                  break;                                  break;
691                                case Event::type_channel_pressure:
692                                    dmsg(5,("Engine: MIDI Chan. Pressure received\n"));
693                                    ProcessChannelPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
694                                    break;
695                                case Event::type_note_pressure:
696                                    dmsg(5,("Engine: MIDI Note Pressure received\n"));
697                                    ProcessPolyphonicKeyPressure((EngineChannel*)itEvent->pEngineChannel, itEvent);
698                                    break;
699                              case Event::type_pitchbend:                              case Event::type_pitchbend:
700                                  dmsg(5,("Engine: Pitchbend received\n"));                                  dmsg(5,("Engine: Pitchbend received\n"));
701                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);                                  ProcessPitchbend(static_cast<AbstractEngineChannel*>(itEvent->pEngineChannel), itEvent);
# Line 651  namespace LinuxSampler { Line 712  namespace LinuxSampler {
712                  pLastStolenChannel        = NULL;                  pLastStolenChannel        = NULL;
713              }              }
714    
715                /** @brief Call instrument script's event handler for this event.
716                 *
717                 * Causes a new execution instance of the currently loaded real-time
718                 * instrument script's event handler (callback) to be spawned for
719                 * the given MIDI event.
720                 *
721                 * @param pChannel - engine channel on which the MIDI event occured
722                 * @param itEvent - MIDI event that causes this new script execution
723                 * @param pEventHandler - script's event handler to be executed
724                 */
725                void ProcessEventByScript(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler) {
726                    RTList<ScriptEvent>::Iterator itScriptEvent =
727                        pChannel->pScript->pEvents->allocAppend();
728    
729                    if (!itScriptEvent) return; // no free script event left for execution
730    
731                    // fill the list of script handlers to be executed by this event
732                    int i = 0;
733                    itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
734                    itScriptEvent->handlers[i] = NULL; // NULL termination of list
735    
736                    // initialize/reset other members
737                    itScriptEvent->cause = *itEvent;
738                    itScriptEvent->id = pEventPool->getID(itEvent);
739                    itScriptEvent->currentHandler = 0;
740                    itScriptEvent->executionSlices = 0;
741    
742                    // run script handler(s)
743                    VMExecStatus_t res = pScriptVM->exec(
744                        pChannel->pScript->parserContext, &*itScriptEvent
745                    );
746    
747                    // in case the script was suspended, keep it on the allocated
748                    // ScriptEvent list to be continued on the next audio cycle,
749                    // otherwise if execution has been finished, free it for a new
750                    // future script event to be triggered from start
751                    if (!(res & VM_EXEC_SUSPENDED))
752                        pChannel->pScript->pEvents->free(itScriptEvent);
753                }
754    
755                /** @brief Resume execution of instrument script.
756                 *
757                 * Will be called to resume execution of a real-time instrument
758                 * script event which has been suspended in a previous audio
759                 * fragment cycle.
760                 *
761                 * Script execution might be suspended for various reasons. Usually
762                 * a script will be suspended if the script called the built-in
763                 * "wait()" function, but it might also be suspended automatically
764                 * if the script took too much execution time in an audio fragment
765                 * cycle. So in the latter case automatic suspension is performed in
766                 * order to avoid harm for the sampler's overall real-time
767                 * requirements.
768                 *
769                 * @param pChannel - engine channel this script is running for
770                 * @param itScriptEvent - script execution that shall be resumed
771                 */
772                void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
773                    // run script
774                    VMExecStatus_t res = pScriptVM->exec(
775                        pChannel->pScript->parserContext, &*itScriptEvent
776                    );
777                    // in case the script was again suspended, keep it on the allocated
778                    // ScriptEvent list to be continued on the next audio cycle,
779                    // otherwise if execution has been finished, free it for a new
780                    // future script event to be triggered from start
781                    if (!(res & VM_EXEC_SUSPENDED))
782                        pChannel->pScript->pEvents->free(itScriptEvent);
783                }
784    
785              /**              /**
786               *  Will be called by LaunchVoice() method in case there are no free               *  Will be called by LaunchVoice() method in case there are no free
787               *  voices left. This method will select and kill one old voice for               *  voices left. This method will select and kill one old voice for
# Line 783  namespace LinuxSampler { Line 914  namespace LinuxSampler {
914                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
915                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
916                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
917                            pEngineChannel->pScript = cmd.pScript;
918                          instrumentChanged = true;                          instrumentChanged = true;
919    
920                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
921    
922                            // the script's "init" event handler is only executed
923                            // once (when the script is loaded or reloaded)
924                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
925                                RTList<ScriptEvent>::Iterator itScriptEvent =
926                                    pEngineChannel->pScript->pEvents->allocAppend();
927    
928                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
929                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
930                                itScriptEvent->handlers[1] = NULL;
931    
932                                VMExecStatus_t res = pScriptVM->exec(
933                                    pEngineChannel->pScript->parserContext, &*itScriptEvent
934                                );
935    
936                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
937                            }
938                      }                      }
939                  }                  }
940    
# Line 968  namespace LinuxSampler { Line 1117  namespace LinuxSampler {
1117                      }                      }
1118                      case 10: { // panpot                      case 10: { // panpot
1119                          //TODO: not sample accurate yet                          //TODO: not sample accurate yet
                         pChannel->GlobalPanLeft  = PanCurve[128 - itControlChangeEvent->Param.CC.Value];  
                         pChannel->GlobalPanRight = PanCurve[itControlChangeEvent->Param.CC.Value];  
1120                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1121                          break;                          break;
1122                      }                      }
# Line 1165  namespace LinuxSampler { Line 1312  namespace LinuxSampler {
1312                  pChannel->ProcessKeySwitchChange(key);                  pChannel->ProcessKeySwitchChange(key);
1313    
1314                  pKey->KeyPressed = true; // the MIDI key was now pressed down                  pKey->KeyPressed = true; // the MIDI key was now pressed down
1315                    pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1316                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1317                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1318    
# Line 1241  namespace LinuxSampler { Line 1389  namespace LinuxSampler {
1389                  #endif                  #endif
1390    
1391                  pKey->KeyPressed = false; // the MIDI key was now released                  pKey->KeyPressed = false; // the MIDI key was now released
1392                    pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1393    
1394                  // move event to the key's own event list                  // move event to the key's own event list
1395                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
# Line 1320  namespace LinuxSampler { Line 1469  namespace LinuxSampler {
1469               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
1470               */               */
1471              virtual void ResetInternal() {              virtual void ResetInternal() {
1472                  ResetInternalMutex.Lock();                  LockGuard lock(ResetInternalMutex);
1473    
1474                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
1475                  // while it's reseting                  // while it's reseting
# Line 1349  namespace LinuxSampler { Line 1498  namespace LinuxSampler {
1498                  pEventQueue->init();                  pEventQueue->init();
1499                  pSysexBuffer->init();                  pSysexBuffer->init();
1500                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);
                 ResetInternalMutex.Unlock();  
1501              }              }
1502    
1503              /**              /**
# Line 1445  namespace LinuxSampler { Line 1593  namespace LinuxSampler {
1593    
1594                  return -1;                  return -1;
1595              }              }
1596                
1597                /**
1598                 * Checks whether scale tuning setting has been changed since last
1599                 * time this method was called, if yes, it recalculates the pitch
1600                 * for all active voices.
1601                 */
1602                void ProcessScaleTuningChange() {
1603                    const bool changed = ScaleTuningChanged.readAndReset();
1604                    if (!changed) return;
1605                    
1606                    for (int i = 0; i < engineChannels.size(); i++) {
1607                        EngineChannelBase<V, R, I>* channel =
1608                            static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
1609                        channel->OnScaleTuningChanged();
1610                    }
1611                }
1612    
1613          private:          private:
1614              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.

Legend:
Removed from v.2298  
changed lines
  Added in v.2618

  ViewVC Help
Powered by ViewVC