/[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 2559 by schoenebeck, Sun May 18 17:38:25 2014 UTC revision 2645 by schoenebeck, Wed Jun 18 00:14:57 2014 UTC
# Line 631  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 673  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 805  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 = cmd.pScript;
982                          instrumentChanged = true;                          instrumentChanged = true;
983    
984                          pEngineChannel->MarkAllActiveVoicesAsOrphans();                          pEngineChannel->MarkAllActiveVoicesAsOrphans();
985    
986                            // the script's "init" event handler is only executed
987                            // once (when the script is loaded or reloaded)
988                            if (pEngineChannel->pScript && pEngineChannel->pScript->handlerInit) {
989                                RTList<ScriptEvent>::Iterator itScriptEvent =
990                                    pEngineChannel->pScript->pEvents->allocAppend();
991    
992                                itScriptEvent->cause.pEngineChannel = pEngineChannel;
993                                itScriptEvent->handlers[0] = pEngineChannel->pScript->handlerInit;
994                                itScriptEvent->handlers[1] = NULL;
995    
996                                VMExecStatus_t res = pScriptVM->exec(
997                                    pEngineChannel->pScript->parserContext, &*itScriptEvent
998                                );
999    
1000                                pEngineChannel->pScript->pEvents->free(itScriptEvent);
1001                            }
1002                      }                      }
1003                  }                  }
1004    
# Line 1185  namespace LinuxSampler { Line 1376  namespace LinuxSampler {
1376                  pChannel->ProcessKeySwitchChange(key);                  pChannel->ProcessKeySwitchChange(key);
1377    
1378                  pKey->KeyPressed = true; // the MIDI key was now pressed down                  pKey->KeyPressed = true; // the MIDI key was now pressed down
1379                    pChannel->KeyDown[key] = true; // just used as built-in %KEY_DOWN script variable
1380                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;                  pKey->Velocity   = itNoteOnEventOnKeyList->Param.Note.Velocity;
1381                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length                  pKey->NoteOnTime = FrameTime + itNoteOnEventOnKeyList->FragmentPos(); // will be used to calculate note length
1382    
# Line 1261  namespace LinuxSampler { Line 1453  namespace LinuxSampler {
1453                  #endif                  #endif
1454    
1455                  pKey->KeyPressed = false; // the MIDI key was now released                  pKey->KeyPressed = false; // the MIDI key was now released
1456                    pChannel->KeyDown[iKey] = false; // just used as built-in %KEY_DOWN script variable
1457    
1458                  // move event to the key's own event list                  // move event to the key's own event list
1459                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);                  RTList<Event>::Iterator itNoteOffEventOnKeyList = itNoteOffEvent.moveToEndOf(pKey->pEvents);

Legend:
Removed from v.2559  
changed lines
  Added in v.2645

  ViewVC Help
Powered by ViewVC