3 |
* LinuxSampler - modular, streaming capable sampler * |
* LinuxSampler - modular, streaming capable sampler * |
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-2020 Christian Schoenebeck * |
* Copyright (C) 2005-2021 Christian Schoenebeck * |
7 |
* Copyright (C) 2009-2012 Grigor Iliev * |
* Copyright (C) 2009-2012 Grigor Iliev * |
8 |
* Copyright (C) 2012-2017 Andreas Persson * |
* Copyright (C) 2012-2017 Andreas Persson * |
9 |
* * |
* * |
1006 |
if (pEventHandler == pChannel->pScript->handlerRelease && |
if (pEventHandler == pChannel->pScript->handlerRelease && |
1007 |
pChannel->pScript->handlerNote && |
pChannel->pScript->handlerNote && |
1008 |
pChannel->pScript->handlerNote->isPolyphonic() && |
pChannel->pScript->handlerNote->isPolyphonic() && |
1009 |
pChannel->pScript->handlerRelease->isPolyphonic() && |
pChannel->pScript->handlerRelease->isPolyphonic()) |
|
!pChannel->pScript->pKeyEvents[key]->isEmpty()) |
|
1010 |
{ |
{ |
1011 |
// polyphonic variable data is used/passed from "note" to |
// polyphonic variable data is used/passed from "note" to |
1012 |
// "release" script callback, so we have to recycle the |
// "release" script callback; first assume the "note" script |
1013 |
// original "note on" script event |
// callback already finished execution and waits for being |
1014 |
|
// recycled for the "release" script handler ... |
1015 |
RTList<ScriptEvent>::Iterator it = pChannel->pScript->pKeyEvents[key]->first(); |
RTList<ScriptEvent>::Iterator it = pChannel->pScript->pKeyEvents[key]->first(); |
1016 |
RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end(); |
RTList<ScriptEvent>::Iterator end = pChannel->pScript->pKeyEvents[key]->end(); |
1017 |
for (; it != end; ++it) { |
for (; it != end; ++it) { |
1018 |
// Despite the loop, in fact we're just picking and |
// Despite the loop, in fact we're just picking and |
1019 |
// running EXACTLY ONE script event here and then leave |
// running EXACTLY ONE script event here and then leave |
1020 |
// the loop immediately. The following check, and with |
// the loop immediately. |
|
// it the loop itself is probably overkill/redundant, |
|
|
// because once we executed the script here, the chosen |
|
|
// script event will be moved away from the pKeyEvents |
|
|
// list. Which means we could probably drop the loop and |
|
|
// simply always pick the very first script event from |
|
|
// pKeyEvents here and that's it. |
|
1021 |
if (it->handlerType != VM_EVENT_HANDLER_NOTE) |
if (it->handlerType != VM_EVENT_HANDLER_NOTE) |
1022 |
continue; |
continue; |
1023 |
|
// Skip "note" script callbacks which have already been |
1024 |
|
// picked (in this loop) for a "release" callback |
1025 |
|
// before. This ensures that a "note" script callback is |
1026 |
|
// really just used once for a "release" callback. |
1027 |
|
if (it->releaseMatched) |
1028 |
|
continue; |
1029 |
|
it->releaseMatched = true; |
1030 |
|
// Now recycle the picked old "note" script callback for |
1031 |
|
// the "release" script callback. |
1032 |
ProcessScriptEvent( |
ProcessScriptEvent( |
1033 |
pChannel, itEvent, pEventHandler, it |
pChannel, itEvent, pEventHandler, it |
1034 |
); |
); |
1041 |
// might increment a script variable in the "note" |
// might increment a script variable in the "note" |
1042 |
// handler and decrement the variable in the "release" |
// handler and decrement the variable in the "release" |
1043 |
// handler to count the currently pressed down keys). |
// handler to count the currently pressed down keys). |
1044 |
break; |
return; |
1045 |
|
} |
1046 |
|
// If we're here then the original "note" script callback |
1047 |
|
// has not finished execution yet (i.e. it is currently |
1048 |
|
// suspended). This requires a more expensive solution: |
1049 |
|
// search on the list of all yet active script callbacks. |
1050 |
|
it = pChannel->pScript->pEvents->first(); |
1051 |
|
end = pChannel->pScript->pEvents->end(); |
1052 |
|
for (; it != end; ++it) { |
1053 |
|
if (it->handlerType != VM_EVENT_HANDLER_NOTE) |
1054 |
|
continue; |
1055 |
|
if (it->cause.Param.Note.Key != itEvent->Param.Note.Key) |
1056 |
|
continue; |
1057 |
|
if (it->releaseMatched) |
1058 |
|
continue; |
1059 |
|
it->releaseMatched = true; |
1060 |
|
// As the original "note" callback is still running, we |
1061 |
|
// cannot recycle it, instead we spawn a completely new |
1062 |
|
// script handler and just copy the "note" handler's |
1063 |
|
// polyphonic data. |
1064 |
|
RTList<ScriptEvent>::Iterator itScriptEvent = |
1065 |
|
pChannel->pScript->pEvents->allocAppend(); |
1066 |
|
itScriptEvent->execCtx->copyPolyphonicDataFrom(it->execCtx); |
1067 |
|
// Now run the new "release" handler with the polyphonic |
1068 |
|
// data copied from the original "note" handler. |
1069 |
|
ProcessScriptEvent( |
1070 |
|
pChannel, itEvent, pEventHandler, itScriptEvent |
1071 |
|
); |
1072 |
|
// Done. Matched exactly one note <-> release handler. |
1073 |
|
return; |
1074 |
} |
} |
1075 |
|
// This should never happen. Otherwise it's a bug. |
1076 |
|
dmsg(0,("[ScriptVM] WARNING: No matching previous \"note\" event handler found for polyphonic \"release\" event handler!\n")); |
1077 |
} else { |
} else { |
1078 |
// no polyphonic data is used/passed from "note" to |
// no polyphonic data is used/passed from "note" to |
1079 |
// "release" script callback, so just use a new fresh |
// "release" script callback, so just use a new fresh |
1120 |
itScriptEvent->currentHandler = 0; |
itScriptEvent->currentHandler = 0; |
1121 |
itScriptEvent->executionSlices = 0; |
itScriptEvent->executionSlices = 0; |
1122 |
itScriptEvent->ignoreAllWaitCalls = false; |
itScriptEvent->ignoreAllWaitCalls = false; |
1123 |
|
itScriptEvent->releaseMatched = false; |
1124 |
itScriptEvent->handlerType = pEventHandler->eventHandlerType(); |
itScriptEvent->handlerType = pEventHandler->eventHandlerType(); |
1125 |
itScriptEvent->parentHandlerID = 0; |
itScriptEvent->parentHandlerID = 0; |
1126 |
itScriptEvent->childHandlerID[0] = 0; |
itScriptEvent->childHandlerID[0] = 0; |
1412 |
itScriptEvent->currentHandler = 0; |
itScriptEvent->currentHandler = 0; |
1413 |
itScriptEvent->executionSlices = 0; |
itScriptEvent->executionSlices = 0; |
1414 |
itScriptEvent->ignoreAllWaitCalls = false; |
itScriptEvent->ignoreAllWaitCalls = false; |
1415 |
|
itScriptEvent->releaseMatched = false; // not relevant for init handler actually |
1416 |
itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT; |
itScriptEvent->handlerType = VM_EVENT_HANDLER_INIT; |
1417 |
itScriptEvent->parentHandlerID = 0; |
itScriptEvent->parentHandlerID = 0; |
1418 |
itScriptEvent->childHandlerID[0] = 0; |
itScriptEvent->childHandlerID[0] = 0; |