46 |
ResetControllers(); |
ResetControllers(); |
47 |
PortamentoMode = false; |
PortamentoMode = false; |
48 |
PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT; |
PortamentoTime = CONFIG_PORTAMENTO_TIME_DEFAULT; |
49 |
pScriptEvents = NULL; |
pScript = NULL; |
50 |
} |
} |
51 |
|
|
52 |
AbstractEngineChannel::~AbstractEngineChannel() { |
AbstractEngineChannel::~AbstractEngineChannel() { |
53 |
unloadCurrentInstrumentScript(); |
if (pScript) pScript->resetAll(); // unloads script (in case one is loaded) |
|
if (pScriptEvents) delete pScriptEvents; |
|
54 |
delete pEventQueue; |
delete pEventQueue; |
55 |
DeleteGroupEventLists(); |
DeleteGroupEventLists(); |
56 |
RemoveAllFxSends(); |
RemoveAllFxSends(); |
144 |
} |
} |
145 |
|
|
146 |
/** |
/** |
|
* Loads the real-time instrument script given by @a text on this engine |
|
|
* channel. A resource manager is used to allocate and share equivalent |
|
|
* scripts on multiple engine channels. |
|
|
* |
|
|
* @param text - source code of script |
|
|
*/ |
|
|
void AbstractEngineChannel::loadInstrumentScript(const String& text) { |
|
|
dmsg(1,("Loading real-time instrument script ... ")); |
|
|
|
|
|
// hand back old script reference and VM execution contexts |
|
|
// (if not done already) |
|
|
unloadCurrentInstrumentScript(); |
|
|
|
|
|
// get new script reference |
|
|
script.parserContext = pEngine->scripts.Borrow(text, this); |
|
|
if (!script.parserContext->errors().empty()) { |
|
|
std::vector<ParserIssue> errors = script.parserContext->errors(); |
|
|
std::cerr << "[ScriptVM] Could not load instrument script, there were " |
|
|
<< errors.size() << " parser errors:\n"; |
|
|
for (int i = 0; i < errors.size(); ++i) |
|
|
errors[i].dump(); |
|
|
return; // stop here if there were any parser errors |
|
|
} |
|
|
|
|
|
script.handlerInit = script.parserContext->eventHandlerByName("init"); |
|
|
script.handlerNote = script.parserContext->eventHandlerByName("note"); |
|
|
script.handlerRelease = script.parserContext->eventHandlerByName("release"); |
|
|
script.handlerController = script.parserContext->eventHandlerByName("controller"); |
|
|
script.bHasValidScript = |
|
|
script.handlerInit || script.handlerNote || script.handlerRelease || |
|
|
script.handlerController; |
|
|
|
|
|
// amount of script handlers each script event has to execute |
|
|
int handlerExecCount = 0; |
|
|
if (script.handlerInit) handlerExecCount++; // "init" handler is always executed before the actual event handler |
|
|
if (script.handlerNote || script.handlerRelease || script.handlerController) // only one of these are executed after "init" handler |
|
|
handlerExecCount++; |
|
|
|
|
|
// create script event pool (if it doesn't exist already) |
|
|
if (!pScriptEvents) |
|
|
pScriptEvents = new Pool<ScriptEvent>(CONFIG_MAX_EVENTS_PER_FRAGMENT); |
|
|
|
|
|
// create new VM execution contexts for new script |
|
|
while (!pScriptEvents->poolIsEmpty()) { |
|
|
RTList<ScriptEvent>::Iterator it = pScriptEvents->allocAppend(); |
|
|
it->execCtx = pEngine->pScriptVM->createExecContext( |
|
|
script.parserContext |
|
|
); |
|
|
it->handlers = new VMEventHandler*[handlerExecCount+1]; |
|
|
} |
|
|
pScriptEvents->clear(); |
|
|
|
|
|
dmsg(1,("Done\n")); |
|
|
} |
|
|
|
|
|
/** |
|
|
* Unloads the currently used real-time instrument script on this sampler |
|
|
* channel. A resource manager is used to share equivalent scripts among |
|
|
* multiple sampler channels, and to deallocate the parsed script once not |
|
|
* used on any engine channel anymore. |
|
|
*/ |
|
|
void AbstractEngineChannel::unloadCurrentInstrumentScript() { |
|
|
if (script.parserContext) |
|
|
dmsg(1,("Unloading current instrument script.")); |
|
|
|
|
|
// free allocated VM execution contexts |
|
|
if (pScriptEvents) { |
|
|
pScriptEvents->clear(); |
|
|
while (!pScriptEvents->poolIsEmpty()) { |
|
|
RTList<ScriptEvent>::Iterator it = pScriptEvents->allocAppend(); |
|
|
if (it->execCtx) { |
|
|
// free VM execution context object |
|
|
delete it->execCtx; |
|
|
it->execCtx = NULL; |
|
|
// free C array of handler pointers |
|
|
delete [] it->handlers; |
|
|
} |
|
|
} |
|
|
pScriptEvents->clear(); |
|
|
} |
|
|
// hand back VM representation of script |
|
|
if (script.parserContext) { |
|
|
pEngine->scripts.HandBack(script.parserContext, this); |
|
|
script.parserContext = NULL; |
|
|
script.handlerInit = NULL; |
|
|
script.handlerNote = NULL; |
|
|
script.handlerRelease = NULL; |
|
|
script.handlerController = NULL; |
|
|
} |
|
|
script.bHasValidScript = false; |
|
|
} |
|
|
|
|
|
/** |
|
147 |
* Implementation of virtual method from abstract EngineChannel interface. |
* Implementation of virtual method from abstract EngineChannel interface. |
148 |
* This method will periodically be polled (e.g. by the LSCP server) to |
* This method will periodically be polled (e.g. by the LSCP server) to |
149 |
* check if some engine channel parameter has changed since the last |
* check if some engine channel parameter has changed since the last |
377 |
event.Param.Note.Key = Key; |
event.Param.Note.Key = Key; |
378 |
event.Param.Note.Velocity = Velocity; |
event.Param.Note.Velocity = Velocity; |
379 |
event.Param.Note.Channel = MidiChannel; |
event.Param.Note.Channel = MidiChannel; |
380 |
event.Format = {}; // init format specific stuff with zeroes |
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
381 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
382 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
383 |
else dmsg(1,("EngineChannel: Input event queue full!")); |
else dmsg(1,("EngineChannel: Input event queue full!")); |
419 |
event.Param.Note.Key = Key; |
event.Param.Note.Key = Key; |
420 |
event.Param.Note.Velocity = Velocity; |
event.Param.Note.Velocity = Velocity; |
421 |
event.Param.Note.Channel = MidiChannel; |
event.Param.Note.Channel = MidiChannel; |
422 |
event.Format = {}; // init format specific stuff with zeroes |
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
423 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
424 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
425 |
else dmsg(1,("EngineChannel: Input event queue full!")); |
else dmsg(1,("EngineChannel: Input event queue full!")); |
456 |
event.Param.Note.Key = Key; |
event.Param.Note.Key = Key; |
457 |
event.Param.Note.Velocity = Velocity; |
event.Param.Note.Velocity = Velocity; |
458 |
event.Param.Note.Channel = MidiChannel; |
event.Param.Note.Channel = MidiChannel; |
459 |
event.Format = {}; // init format specific stuff with zeroes |
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
460 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
461 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
462 |
else dmsg(1,("EngineChannel: Input event queue full!")); |
else dmsg(1,("EngineChannel: Input event queue full!")); |
498 |
event.Param.Note.Key = Key; |
event.Param.Note.Key = Key; |
499 |
event.Param.Note.Velocity = Velocity; |
event.Param.Note.Velocity = Velocity; |
500 |
event.Param.Note.Channel = MidiChannel; |
event.Param.Note.Channel = MidiChannel; |
501 |
event.Format = {}; // init format specific stuff with zeroes |
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
502 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
503 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
504 |
else dmsg(1,("EngineChannel: Input event queue full!")); |
else dmsg(1,("EngineChannel: Input event queue full!")); |
533 |
event.Type = Event::type_pitchbend; |
event.Type = Event::type_pitchbend; |
534 |
event.Param.Pitch.Pitch = Pitch; |
event.Param.Pitch.Pitch = Pitch; |
535 |
event.Param.Pitch.Channel = MidiChannel; |
event.Param.Pitch.Channel = MidiChannel; |
536 |
event.Format = {}; // init format specific stuff with zeroes |
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
537 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
538 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
539 |
else dmsg(1,("EngineChannel: Input event queue full!")); |
else dmsg(1,("EngineChannel: Input event queue full!")); |
563 |
event.Type = Event::type_pitchbend; |
event.Type = Event::type_pitchbend; |
564 |
event.Param.Pitch.Pitch = Pitch; |
event.Param.Pitch.Pitch = Pitch; |
565 |
event.Param.Pitch.Channel = MidiChannel; |
event.Param.Pitch.Channel = MidiChannel; |
566 |
event.Format = {}; // init format specific stuff with zeroes |
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
567 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
568 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
569 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
590 |
event.Param.CC.Controller = Controller; |
event.Param.CC.Controller = Controller; |
591 |
event.Param.CC.Value = Value; |
event.Param.CC.Value = Value; |
592 |
event.Param.CC.Channel = MidiChannel; |
event.Param.CC.Channel = MidiChannel; |
593 |
event.Format = {}; // init format specific stuff with zeroes |
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
594 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
595 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
596 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
622 |
event.Param.CC.Controller = Controller; |
event.Param.CC.Controller = Controller; |
623 |
event.Param.CC.Value = Value; |
event.Param.CC.Value = Value; |
624 |
event.Param.CC.Channel = MidiChannel; |
event.Param.CC.Channel = MidiChannel; |
625 |
event.Format = {}; // init format specific stuff with zeroes |
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
626 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
627 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
628 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
637 |
|
|
638 |
Event event = pEngine->pEventGenerator->CreateEvent(); |
Event event = pEngine->pEventGenerator->CreateEvent(); |
639 |
event.Type = Event::type_channel_pressure; |
event.Type = Event::type_channel_pressure; |
640 |
|
event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts |
641 |
event.Param.ChannelPressure.Value = Value; |
event.Param.ChannelPressure.Value = Value; |
642 |
event.Param.ChannelPressure.Channel = MidiChannel; |
event.Param.ChannelPressure.Channel = MidiChannel; |
643 |
event.Format = {}; // init format specific stuff with zeroes |
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
644 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
645 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
646 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
655 |
|
|
656 |
Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos); |
Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos); |
657 |
event.Type = Event::type_channel_pressure; |
event.Type = Event::type_channel_pressure; |
658 |
|
event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts |
659 |
event.Param.ChannelPressure.Value = Value; |
event.Param.ChannelPressure.Value = Value; |
660 |
event.Param.ChannelPressure.Channel = MidiChannel; |
event.Param.ChannelPressure.Channel = MidiChannel; |
661 |
event.Format = {}; // init format specific stuff with zeroes |
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
662 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
663 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
664 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
676 |
event.Param.NotePressure.Key = Key; |
event.Param.NotePressure.Key = Key; |
677 |
event.Param.NotePressure.Value = Value; |
event.Param.NotePressure.Value = Value; |
678 |
event.Param.NotePressure.Channel = MidiChannel; |
event.Param.NotePressure.Channel = MidiChannel; |
679 |
event.Format = {}; // init format specific stuff with zeroes |
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
680 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
681 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
682 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
694 |
event.Param.NotePressure.Key = Key; |
event.Param.NotePressure.Key = Key; |
695 |
event.Param.NotePressure.Value = Value; |
event.Param.NotePressure.Value = Value; |
696 |
event.Param.NotePressure.Channel = MidiChannel; |
event.Param.NotePressure.Channel = MidiChannel; |
697 |
event.Format = {}; // init format specific stuff with zeroes |
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
698 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
699 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
700 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |