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(); |
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); |
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 |
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 |
|
VMExecStatus_t res = pScriptVM->exec( |
929 |
|
pEngineChannel->pScript->parserContext, &*itScriptEvent |
930 |
|
); |
931 |
|
|
932 |
|
pEngineChannel->pScript->pEvents->free(itScriptEvent); |
933 |
|
} |
934 |
} |
} |
935 |
} |
} |
936 |
|
|