/[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 2121 by schoenebeck, Tue Sep 14 17:09:08 2010 UTC revision 2837 by persson, Sun Aug 23 06:14:00 2015 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-2010 Christian Schoenebeck and Grigor Iliev        *   *   Copyright (C) 2009-2015 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 190  namespace LinuxSampler { Line 194  namespace LinuxSampler {
194                  // been deleted by the disk thread                  // been deleted by the disk thread
195                  if (iPendingStreamDeletions) ProcessPendingStreamDeletions();                  if (iPendingStreamDeletions) ProcessPendingStreamDeletions();
196    
197                    // Release the instrument change command. (This has to
198                    // be done after all voices have been rendered and not
199                    // in HandleInstrumentChanges, as the RegionsInUse
200                    // list has been built up by the voice renderers.)
201                    for (int i = 0; i < engineChannels.size(); i++) {
202                        EngineChannelBase<V, R, I>* channel =
203                            static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
204                        channel->InstrumentChangeCommandReader.Unlock();
205                    }
206                  FrameTime += Samples;                  FrameTime += Samples;
207    
208                  EngineDisabled.RttDone();                  EngineDisabled.RttDone();
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 234  namespace LinuxSampler { Line 247  namespace LinuxSampler {
247                  }                  }
248                  pVoicePool->clear();                  pVoicePool->clear();
249    
250                    PostSetMaxVoices(iVoices);
251                  ResumeAll();                  ResumeAll();
252              }              }
253                
254                /** Called after the new max number of voices is set and before resuming the engine. */
255                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 256  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 269  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 299  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 332  namespace LinuxSampler { Line 349  namespace LinuxSampler {
349                  pDiskThread->StartThread();                  pDiskThread->StartThread();
350                  dmsg(1,("OK\n"));                  dmsg(1,("OK\n"));
351    
352                    bool printEqInfo = true;
353                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {                  for (VoiceIterator iterVoice = pVoicePool->allocAppend(); iterVoice == pVoicePool->last(); iterVoice = pVoicePool->allocAppend()) {
354                      if (!iterVoice->pDiskThread) {                      if (!iterVoice->pDiskThread) {
355                          dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));                          dmsg(0,("Engine -> voice::trigger: !pDiskThread\n"));
356                          exit(EXIT_FAILURE);                          exit(EXIT_FAILURE);
357                      }                      }
358                        
359                        iterVoice->CreateEq();
360                        
361                        if(printEqInfo) {
362                            iterVoice->PrintEqInfo();
363                            printEqInfo = false;
364                        }
365                  }                  }
366                  pVoicePool->clear();                  pVoicePool->clear();
367                                    
# Line 347  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 400  namespace LinuxSampler { Line 432  namespace LinuxSampler {
432               * @param pRegion - region the engine shall stop using               * @param pRegion - region the engine shall stop using
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 %p ...\n",(void*)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                  dmsg(2,("EngineBase: Region %x suspended.",pRegion));                  }
442                    dmsg(2,("EngineBase: Region %p suspended.",(void*)pRegion));
443              }              }
444    
445              /**              /**
# Line 416  namespace LinuxSampler { Line 449  namespace LinuxSampler {
449               * @param pRegion - region the engine shall be allowed to use again               * @param pRegion - region the engine shall be allowed to use again
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 %p ...\n",(void*)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                  dmsg(2,("EngineBase: Region %x resumed.\n",pRegion));                  }
459                    dmsg(2,("EngineBase: Region %p resumed.\n",(void*)pRegion));
460              }              }
461    
462              virtual void ResetSuspendedRegions() {              virtual void ResetSuspendedRegions() {
# Line 537  namespace LinuxSampler { Line 571  namespace LinuxSampler {
571    
572              //friend class EngineChannelBase<V, R, I>;              //friend class EngineChannelBase<V, R, I>;
573    
574                static IM instruments;
575    
576          protected:          protected:
577              class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {              class SuspensionVoiceHandler : public MidiKeyboardManager<V>::VoiceHandler {
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 555  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 565  namespace LinuxSampler { Line 602  namespace LinuxSampler {
602                  }                  }
603              };              };
604    
             static IM instruments;  
   
605              Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.              Pool<R*>* pRegionPool[2]; ///< Double buffered pool, used by the engine channels to keep track of regions in use.
606              int       MinFadeOutSamples;     ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.              int       MinFadeOutSamples;     ///< The number of samples needed to make an instant fade out (e.g. for voice stealing) without leading to clicks.
607              D*        pDiskThread;              D*        pDiskThread;
# Line 596  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) {
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 614  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 630  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                    const int key = itEvent->Param.Note.Key; // even if this is not a note on/off event, accessing it does not mean any harm
727                    // check if polyphonic data is passed from "note" to "release"
728                    // script event handlers
729                    if (pEventHandler == pChannel->pScript->handlerRelease &&
730                        pChannel->pScript->handlerNote &&
731                        pChannel->pScript->handlerNote->isPolyphonic() &&
732                        pChannel->pScript->handlerRelease->isPolyphonic() &&
733                        !pChannel->pScript->pKeyEvents[key]->isEmpty())
734                    {
735                        // polyphonic variable data is used/passed from "note" to
736                        // "release" script callback, so we have to recycle the
737                        // original "note on" script event(s)
738                        RTList<ScriptEvent>::Iterator it  = pChannel->pScript->pKeyEvents[key]->first();
739                        RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end();
740                        for (; it != end; ++it) {
741                            ProcessScriptEvent(
742                                pChannel, itEvent, pEventHandler, it
743                            );
744                        }
745                    } else {
746                        // no polyphonic data is used/passed from "note" to
747                        // "release" script callback, so just use a new fresh
748                        // script event object
749                        RTList<ScriptEvent>::Iterator itScriptEvent =
750                            pChannel->pScript->pEvents->allocAppend();
751                        ProcessScriptEvent(
752                            pChannel, itEvent, pEventHandler, itScriptEvent
753                        );
754                    }
755                }
756    
757                void ProcessScriptEvent(AbstractEngineChannel* pChannel, RTList<Event>::Iterator& itEvent, VMEventHandler* pEventHandler, RTList<ScriptEvent>::Iterator& itScriptEvent) {
758                    if (!itScriptEvent) return; // not a valid script event (i.e. because no free script event was left in the script event pool)
759    
760                    // fill the list of script handlers to be executed by this event
761                    int i = 0;
762                    itScriptEvent->handlers[i++] = pEventHandler; // actual event handler (i.e. note, controller)
763                    itScriptEvent->handlers[i] = NULL; // NULL termination of list
764    
765                    // initialize/reset other members
766                    itScriptEvent->cause = *itEvent;
767                    itScriptEvent->id = pEventPool->getID(itEvent);
768                    itScriptEvent->currentHandler = 0;
769                    itScriptEvent->executionSlices = 0;
770    
771                    // run script handler(s)
772                    VMExecStatus_t res = pScriptVM->exec(
773                        pChannel->pScript->parserContext, &*itScriptEvent
774                    );
775    
776                    // in case the script was suspended, keep it on the allocated
777                    // ScriptEvent list to be continued on the next audio cycle
778                    if (!(res & VM_EXEC_SUSPENDED)) { // script execution has finished without 'suspended' status ...
779                        // if "polyphonic" variable data is passed from script's
780                        // "note" event handler to its "release" event handler, then
781                        // the script event must be kept and recycled for the later
782                        // occuring "release" script event ...
783                        if (pEventHandler == pChannel->pScript->handlerNote &&
784                            pChannel->pScript->handlerRelease &&
785                            pChannel->pScript->handlerNote->isPolyphonic() &&
786                            pChannel->pScript->handlerRelease->isPolyphonic())
787                        {
788                            const int key = itEvent->Param.Note.Key;
789                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
790                        } else {
791                            // ... otherwise if no polyphonic data is passed and
792                            // script's execution has finished without suspension
793                            // status, then free the script event for a new future
794                            // script event to be triggered from start
795                            pChannel->pScript->pEvents->free(itScriptEvent);
796                        }
797                    }
798                }
799    
800                /** @brief Resume execution of instrument script.
801                 *
802                 * Will be called to resume execution of a real-time instrument
803                 * script event which has been suspended in a previous audio
804                 * fragment cycle.
805                 *
806                 * Script execution might be suspended for various reasons. Usually
807                 * a script will be suspended if the script called the built-in
808                 * "wait()" function, but it might also be suspended automatically
809                 * if the script took too much execution time in an audio fragment
810                 * cycle. So in the latter case automatic suspension is performed in
811                 * order to avoid harm for the sampler's overall real-time
812                 * requirements.
813                 *
814                 * @param pChannel - engine channel this script is running for
815                 * @param itScriptEvent - script execution that shall be resumed
816                 */
817                void ResumeScriptEvent(AbstractEngineChannel* pChannel, RTList<ScriptEvent>::Iterator& itScriptEvent) {
818                    VMEventHandler* handler = itScriptEvent->handlers[itScriptEvent->currentHandler];
819    
820                    // run script
821                    VMExecStatus_t res = pScriptVM->exec(
822                        pChannel->pScript->parserContext, &*itScriptEvent
823                    );
824    
825                    // in case the script was suspended, keep it on the allocated
826                    // ScriptEvent list to be continued on the next audio cycle
827                    if (!(res & VM_EXEC_SUSPENDED)) { // script execution has finished without 'suspended' status ...
828                        // if "polyphonic" variable data is passed from script's
829                        // "note" event handler to its "release" event handler, then
830                        // the script event must be kept and recycled for the later
831                        // occuring "release" script event ...
832                        if (handler && handler == pChannel->pScript->handlerNote &&
833                            pChannel->pScript->handlerRelease &&
834                            pChannel->pScript->handlerNote->isPolyphonic() &&
835                            pChannel->pScript->handlerRelease->isPolyphonic())
836                        {
837                            const int key = itScriptEvent->cause.Param.Note.Key;
838                            itScriptEvent.moveToEndOf(pChannel->pScript->pKeyEvents[key & 127]);
839                        } else {
840                            // ... otherwise if no polyphonic data is passed and
841                            // script's execution has finished without suspension
842                            // status, then free the script event for a new future
843                            // script event to be triggered from start
844                            pChannel->pScript->pEvents->free(itScriptEvent);
845                        }
846                    }
847                }
848    
849              /**              /**
850               *  Will be called by LaunchVoice() method in case there are no free               *  Will be called by LaunchVoice() method in case there are no free
851               *  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 762  namespace LinuxSampler { Line 978  namespace LinuxSampler {
978                          dmsg(5,("Engine: instrument change command received\n"));                          dmsg(5,("Engine: instrument change command received\n"));
979                          cmd.bChangeInstrument = false;                          cmd.bChangeInstrument = false;
980                          pEngineChannel->pInstrument = cmd.pInstrument;                          pEngineChannel->pInstrument = cmd.pInstrument;
981                            pEngineChannel->pScript =
982                                cmd.pScript->bHasValidScript ? cmd.pScript : NULL;
983                          instrumentChanged = true;                          instrumentChanged = true;
984    
985                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
986    
987                            // the script's "init" event handler is only executed
988                            // once (when the script is loaded or reloaded)
989                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
990                                RTList<ScriptEvent>::Iterator itScriptEvent =
991                                    pEngineChannel->pScript->pEvents->allocAppend();
992    
993                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
994                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
995                                itScriptEvent->handlers[1] = NULL;
996    
997                                VMExecStatus_t res = pScriptVM->exec(
998                                    pEngineChannel->pScript->parserContext, &*itScriptEvent
999                                );
1000    
1001                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
1002                            }
1003                      }                      }
1004                  }                  }
1005    
# Line 772  namespace LinuxSampler { Line 1007  namespace LinuxSampler {
1007                      //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                      //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
1008                      ResetSuspendedRegions();                      ResetSuspendedRegions();
1009                  }                  }
   
                 for (int i = 0; i < engineChannels.size(); i++) {  
                     EngineChannelBase<V, R, I>* channel =  
                         static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);  
                     channel->InstrumentChangeCommandReader.Unlock();  
                 }  
1010              }              }
1011    
1012              /**              /**
# Line 926  namespace LinuxSampler { Line 1155  namespace LinuxSampler {
1155                                  case 0x1d: { // reverb send of note (Roland GS NRPN)                                  case 0x1d: { // reverb send of note (Roland GS NRPN)
1156                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1157                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float reverb = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1158                                      dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%d).\n", note, reverb));                                      dmsg(4,("Note Reverb Send NRPN received (note=%d,send=%f).\n", note, reverb));
1159                                      if (note < 128)                                      if (note < 128)
1160                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;                                          pChannel->pMIDIKeyInfo[note].ReverbSend = reverb;
1161                                      break;                                      break;
# Line 934  namespace LinuxSampler { Line 1163  namespace LinuxSampler {
1163                                  case 0x1e: { // chorus send of note (Roland GS NRPN)                                  case 0x1e: { // chorus send of note (Roland GS NRPN)
1164                                      const uint note = NrpnCtrlLSB;                                      const uint note = NrpnCtrlLSB;
1165                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;                                      const float chorus = float(itControlChangeEvent->Param.CC.Value) / 127.0f;
1166                                      dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%d).\n", note, chorus));                                      dmsg(4,("Note Chorus Send NRPN received (note=%d,send=%f).\n", note, chorus));
1167                                      if (note < 128)                                      if (note < 128)
1168                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;                                          pChannel->pMIDIKeyInfo[note].ChorusSend = chorus;
1169                                      break;                                      break;
# Line 953  namespace LinuxSampler { Line 1182  namespace LinuxSampler {
1182                      }                      }
1183                      case 10: { // panpot                      case 10: { // panpot
1184                          //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];  
1185                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;                          pChannel->iLastPanRequest = itControlChangeEvent->Param.CC.Value;
1186                          break;                          break;
1187                      }                      }
# Line 1150  namespace LinuxSampler { Line 1377  namespace LinuxSampler {
1377                  pChannel->ProcessKeySwitchChange(key);                  pChannel->ProcessKeySwitchChange(key);
1378    
1379                  pKey->KeyPressed = true; // the MIDI key was now pressed down                  pKey->KeyPressed = true; // the MIDI key was now pressed down
1380                    pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1381                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1382                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1383    
# Line 1226  namespace LinuxSampler { Line 1454  namespace LinuxSampler {
1454                  #endif                  #endif
1455    
1456                  pKey->KeyPressed = false; // the MIDI key was now released                  pKey->KeyPressed = false; // the MIDI key was now released
1457                    pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1458    
1459                  // move event to the key's own event list                  // move event to the key's own event list
1460                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);
# Line 1305  namespace LinuxSampler { Line 1534  namespace LinuxSampler {
1534               *  control and status variables. This method is protected by a mutex.               *  control and status variables. This method is protected by a mutex.
1535               */               */
1536              virtual void ResetInternal() {              virtual void ResetInternal() {
1537                  ResetInternalMutex.Lock();                  LockGuard lock(ResetInternalMutex);
1538    
1539                  // make sure that the engine does not get any sysex messages                  // make sure that the engine does not get any sysex messages
1540                  // while it's reseting                  // while it's reseting
# Line 1334  namespace LinuxSampler { Line 1563  namespace LinuxSampler {
1563                  pEventQueue->init();                  pEventQueue->init();
1564                  pSysexBuffer->init();                  pSysexBuffer->init();
1565                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);                  if (sysexDisabled) MidiInputPort::AddSysexListener(this);
                 ResetInternalMutex.Unlock();  
1566              }              }
1567    
1568              /**              /**
# Line 1430  namespace LinuxSampler { Line 1658  namespace LinuxSampler {
1658    
1659                  return -1;                  return -1;
1660              }              }
1661                
1662                /**
1663                 * Checks whether scale tuning setting has been changed since last
1664                 * time this method was called, if yes, it recalculates the pitch
1665                 * for all active voices.
1666                 */
1667                void ProcessScaleTuningChange() {
1668                    const bool changed = ScaleTuningChanged.readAndReset();
1669                    if (!changed) return;
1670                    
1671                    for (int i = 0; i < engineChannels.size(); i++) {
1672                        EngineChannelBase<V, R, I>* channel =
1673                            static_cast<EngineChannelBase<V, R, I>*>(engineChannels[i]);
1674                        channel->OnScaleTuningChanged();
1675                    }
1676                }
1677    
1678          private:          private:
1679              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.              Pool<V>*    pVoicePool;            ///< Contains all voices that can be activated.

Legend:
Removed from v.2121  
changed lines
  Added in v.2837

  ViewVC Help
Powered by ViewVC