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-2008 Christian Schoenebeck * |
* Copyright (C) 2005-2021 Christian Schoenebeck * |
7 |
* Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev * |
* Copyright (C) 2009-2012 Grigor Iliev * |
8 |
* Copyright (C) 2012-2016 Christian Schoenebeck and Andreas Persson * |
* Copyright (C) 2012-2017 Andreas Persson * |
9 |
* * |
* * |
10 |
* This program is free software; you can redistribute it and/or modify * |
* This program is free software; you can redistribute it and/or modify * |
11 |
* 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 * |
276 |
|
|
277 |
uint AbstractEngineChannel::GetMidiInputPortCount() { |
uint AbstractEngineChannel::GetMidiInputPortCount() { |
278 |
Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back(); |
Sync< ArrayList<MidiInputPort*> > connections = midiInputs.back(); |
279 |
return connections->size(); |
return (uint) connections->size(); |
280 |
} |
} |
281 |
|
|
282 |
MidiInputPort* AbstractEngineChannel::GetMidiInputPort(uint index) { |
MidiInputPort* AbstractEngineChannel::GetMidiInputPort(uint index) { |
593 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
594 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
595 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
596 |
|
// inform connected virtual MIDI devices if any ... |
597 |
|
// (e.g. slider / knob in instrument editor(s)) |
598 |
|
ArrayList<VirtualMidiDevice*>& devices = |
599 |
|
const_cast<ArrayList<VirtualMidiDevice*>&>( |
600 |
|
virtualMidiDevicesReader_MidiThread.Lock() |
601 |
|
); |
602 |
|
for (int i = 0; i < devices.size(); i++) { |
603 |
|
devices[i]->SendCCToDevice(Controller, Value); |
604 |
|
} |
605 |
|
virtualMidiDevicesReader_MidiThread.Unlock(); |
606 |
} |
} |
607 |
} |
} |
608 |
|
|
634 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
635 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
636 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
637 |
|
// inform connected virtual MIDI devices if any ... |
638 |
|
// (e.g. slider / knob in instrument editor(s)) |
639 |
|
ArrayList<VirtualMidiDevice*>& devices = |
640 |
|
const_cast<ArrayList<VirtualMidiDevice*>&>( |
641 |
|
virtualMidiDevicesReader_MidiThread.Lock() |
642 |
|
); |
643 |
|
for (int i = 0; i < devices.size(); i++) { |
644 |
|
devices[i]->SendCCToDevice(Controller, Value); |
645 |
|
} |
646 |
|
virtualMidiDevicesReader_MidiThread.Unlock(); |
647 |
} |
} |
648 |
} |
} |
649 |
|
|
748 |
{ |
{ |
749 |
const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel(); |
const uint8_t channel = MidiChannel() == midi_chan_all ? 0 : MidiChannel(); |
750 |
const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices |
const int FragmentPos = 0; // randomly chosen, we don't care about jitter for virtual MIDI devices |
751 |
Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos); |
const Event event = pEngine->pEventGenerator->CreateEvent(FragmentPos); |
752 |
VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device |
VirtualMidiDevice::event_t devEvent; // the event format we get from the virtual MIDI device |
753 |
// as we're going to (carefully) write some status to the |
// as we're going to (carefully) write some status to the |
754 |
// synchronized struct, we cast away the const |
// synchronized struct, we cast away the const |
759 |
VirtualMidiDevice* pDev = devices[i]; |
VirtualMidiDevice* pDev = devices[i]; |
760 |
// I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-) |
// I think we can simply flush the whole FIFO(s), the user shouldn't be so fast ;-) |
761 |
while (pDev->GetMidiEventFromDevice(devEvent)) { |
while (pDev->GetMidiEventFromDevice(devEvent)) { |
762 |
|
if (pEvents->poolIsEmpty()) { |
763 |
|
dmsg(1,("Event pool emtpy!\n")); |
764 |
|
goto exitVirtualDevicesLoop; |
765 |
|
} |
766 |
|
|
767 |
|
// copy event to internal event list (this is already |
768 |
|
// required here, because the LaunchNewNote() call below |
769 |
|
// requires the event to be from the internal event pool for |
770 |
|
// being able to generate a valid event ID) |
771 |
|
RTList<Event>::Iterator itEvent = pEvents->allocAppend(); |
772 |
|
*itEvent = event; |
773 |
|
|
774 |
|
itEvent->pEngineChannel = this; |
775 |
|
|
776 |
switch (devEvent.Type) { |
switch (devEvent.Type) { |
777 |
case VirtualMidiDevice::EVENT_TYPE_NOTEON: |
case VirtualMidiDevice::EVENT_TYPE_NOTEON: |
778 |
event.Type = Event::type_note_on; |
itEvent->Type = Event::type_note_on; |
779 |
event.Param.Note.Key = devEvent.Arg1; |
itEvent->Param.Note.Key = devEvent.Arg1; |
780 |
event.Param.Note.Velocity = devEvent.Arg2; |
itEvent->Param.Note.Velocity = devEvent.Arg2; |
781 |
event.Param.Note.Channel = channel; |
itEvent->Param.Note.Channel = channel; |
782 |
// apply transpose setting to (note on/off) event |
// apply transpose setting to (note on/off) event |
783 |
if (!applyTranspose(&event)) |
if (!applyTranspose(&*itEvent)) { |
784 |
continue; // note value is out of range, so drop this event |
// note value is out of range, so drop this event |
785 |
|
pEvents->free(itEvent); |
786 |
|
continue; |
787 |
|
} |
788 |
// assign a new note to this note-on event |
// assign a new note to this note-on event |
789 |
if (!pEngine->LaunchNewNote(this, &event)) |
if (!pEngine->LaunchNewNote(this, itEvent)) { |
790 |
continue; // failed launching new note, so drop this event |
// failed launching new note, so drop this event |
791 |
|
pEvents->free(itEvent); |
792 |
|
continue; |
793 |
|
} |
794 |
break; |
break; |
795 |
case VirtualMidiDevice::EVENT_TYPE_NOTEOFF: |
case VirtualMidiDevice::EVENT_TYPE_NOTEOFF: |
796 |
event.Type = Event::type_note_off; |
itEvent->Type = Event::type_note_off; |
797 |
event.Param.Note.Key = devEvent.Arg1; |
itEvent->Param.Note.Key = devEvent.Arg1; |
798 |
event.Param.Note.Velocity = devEvent.Arg2; |
itEvent->Param.Note.Velocity = devEvent.Arg2; |
799 |
event.Param.Note.Channel = channel; |
itEvent->Param.Note.Channel = channel; |
800 |
if (!applyTranspose(&event)) |
if (!applyTranspose(&*itEvent)) { |
801 |
continue; // note value is out of range, so drop this event |
// note value is out of range, so drop this event |
802 |
|
pEvents->free(itEvent); |
803 |
|
continue; |
804 |
|
} |
805 |
break; |
break; |
806 |
case VirtualMidiDevice::EVENT_TYPE_CC: |
case VirtualMidiDevice::EVENT_TYPE_CC: |
807 |
switch (devEvent.Arg1) { |
switch (devEvent.Arg1) { |
808 |
case 0: // bank select MSB ... |
case 0: // bank select MSB ... |
809 |
SetMidiBankMsb(devEvent.Arg2); |
SetMidiBankMsb(devEvent.Arg2); |
810 |
continue; // don't push this event into FIFO |
// don't push this event into FIFO |
811 |
|
pEvents->free(itEvent); |
812 |
|
continue; |
813 |
case 32: // bank select LSB ... |
case 32: // bank select LSB ... |
814 |
SetMidiBankLsb(devEvent.Arg2); |
SetMidiBankLsb(devEvent.Arg2); |
815 |
continue; // don't push this event into FIFO |
// don't push this event into FIFO |
816 |
|
pEvents->free(itEvent); |
817 |
|
continue; |
818 |
default: // regular MIDI CC ... |
default: // regular MIDI CC ... |
819 |
event.Type = Event::type_control_change; |
itEvent->Type = Event::type_control_change; |
820 |
event.Param.CC.Controller = devEvent.Arg1; |
itEvent->Param.CC.Controller = devEvent.Arg1; |
821 |
event.Param.CC.Value = devEvent.Arg2; |
itEvent->Param.CC.Value = devEvent.Arg2; |
822 |
event.Param.CC.Channel = channel; |
itEvent->Param.CC.Channel = channel; |
823 |
} |
} |
824 |
break; |
break; |
825 |
case VirtualMidiDevice::EVENT_TYPE_PITCHBEND: |
case VirtualMidiDevice::EVENT_TYPE_PITCHBEND: |
826 |
event.Type = Event::type_pitchbend; |
itEvent->Type = Event::type_pitchbend; |
827 |
event.Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192; |
itEvent->Param.Pitch.Pitch = int(devEvent.Arg2 << 7 | devEvent.Arg1) - 8192; |
828 |
event.Param.Pitch.Channel = channel; |
itEvent->Param.Pitch.Channel = channel; |
829 |
break; |
break; |
830 |
case VirtualMidiDevice::EVENT_TYPE_PROGRAM: |
case VirtualMidiDevice::EVENT_TYPE_PROGRAM: |
831 |
SendProgramChange(devEvent.Arg1); |
SendProgramChange(devEvent.Arg1); |
832 |
continue; // don't push this event into FIFO |
// don't push this event into FIFO |
833 |
|
pEvents->free(itEvent); |
834 |
|
continue; |
835 |
case VirtualMidiDevice::EVENT_TYPE_CHPRESSURE: |
case VirtualMidiDevice::EVENT_TYPE_CHPRESSURE: |
836 |
event.Type = Event::type_channel_pressure; |
itEvent->Type = Event::type_channel_pressure; |
837 |
event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; |
itEvent->Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; |
838 |
event.Param.ChannelPressure.Value = devEvent.Arg2; |
itEvent->Param.ChannelPressure.Value = devEvent.Arg2; |
839 |
event.Param.ChannelPressure.Channel = channel; |
itEvent->Param.ChannelPressure.Channel = channel; |
840 |
break; |
break; |
841 |
default: |
default: |
842 |
std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type (" |
std::cerr << "AbstractEngineChannel::ImportEvents() ERROR: unknown event type (" |
843 |
<< devEvent.Type << "). This is a bug!"; |
<< devEvent.Type << "). This is a bug!"; |
844 |
|
pEvents->free(itEvent); // drop event |
845 |
continue; |
continue; |
846 |
} |
} |
|
event.pEngineChannel = this; |
|
|
// copy event to internal event list |
|
|
if (pEvents->poolIsEmpty()) { |
|
|
dmsg(1,("Event pool emtpy!\n")); |
|
|
goto exitVirtualDevicesLoop; |
|
|
} |
|
|
*pEvents->allocAppend() = event; |
|
847 |
} |
} |
848 |
} |
} |
849 |
} |
} |
867 |
dmsg(1,("Event pool emtpy!\n")); |
dmsg(1,("Event pool emtpy!\n")); |
868 |
break; |
break; |
869 |
} |
} |
870 |
|
|
871 |
|
// copy event to internal event list |
872 |
|
// (required already because LaunchNewNote() relies on it, see |
873 |
|
// comment about it above) |
874 |
|
RTList<Event>::Iterator itEvent = pEvents->allocAppend(); |
875 |
|
*itEvent = *pEvent; |
876 |
|
|
877 |
// apply transpose setting to (note on/off) event |
// apply transpose setting to (note on/off) event |
878 |
if (!applyTranspose(pEvent)) |
if (!applyTranspose(&*itEvent)) { |
879 |
continue; // it's a note event which has a note value out of range, so drop this event |
// it's a note event which has a note value out of range, so drop this event |
880 |
|
pEvents->free(itEvent); |
881 |
|
continue; |
882 |
|
} |
883 |
// assign a new note to this event (if its a note-on event) |
// assign a new note to this event (if its a note-on event) |
884 |
if (pEvent->Type == Event::type_note_on) |
if (itEvent->Type == Event::type_note_on) { |
885 |
if (!pEngine->LaunchNewNote(this, pEvent)) |
if (!pEngine->LaunchNewNote(this, itEvent)) { |
886 |
continue; // failed launching new note, so drop this event |
// failed launching new note, so drop this event |
887 |
// copy event to internal event list |
pEvents->free(itEvent); |
888 |
*pEvents->allocAppend() = *pEvent; |
continue; |
889 |
|
} |
890 |
|
} |
891 |
|
|
892 |
} |
} |
893 |
eventQueueReader.free(); // free all copied events from input queue |
eventQueueReader.free(); // free all copied events from input queue |
894 |
} |
} |
910 |
* @param delay - amount of microseconds in future (from now) when event shall be processed |
* @param delay - amount of microseconds in future (from now) when event shall be processed |
911 |
* @returns unique event ID of scheduled new event, or NULL on error |
* @returns unique event ID of scheduled new event, or NULL on error |
912 |
*/ |
*/ |
913 |
event_id_t AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int delay) { |
event_id_t AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int64_t delay) { |
914 |
dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%d)\n", pEvent->Type, delay)); |
dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%" PRId64 ")\n", pEvent->Type, delay)); |
915 |
RTList<Event>::Iterator itEvent = pEvents->allocAppend(); |
RTList<Event>::Iterator itEvent = pEvents->allocAppend(); |
916 |
if (!itEvent) { |
if (!itEvent) { |
917 |
dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n")); |
dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n")); |
1004 |
pScript->suspendedEvents.insert(*pCallback); |
pScript->suspendedEvents.insert(*pCallback); |
1005 |
} |
} |
1006 |
|
|
1007 |
|
/** @brief Fork the given script execution instance. |
1008 |
|
* |
1009 |
|
* Called by real-time instrument script function fork() to create a new |
1010 |
|
* script execution instance (child) of the script execution instance |
1011 |
|
* (parent) that was calling fork(). This is essentially like creating a |
1012 |
|
* new thread for a script handler being executing. The entire execution |
1013 |
|
* state of parent is copied to the "forked" child. |
1014 |
|
* |
1015 |
|
* @param parent - original active script callback instance from which the |
1016 |
|
* new child shall be forked from |
1017 |
|
* @param bAutoAbort - whether the forked child shall automatically be |
1018 |
|
* terminated as soon as parent terminates |
1019 |
|
* @returns forked new child execution instance |
1020 |
|
*/ |
1021 |
|
RTList<ScriptEvent>::Iterator AbstractEngineChannel::forkScriptCallback(ScriptEvent* parent, bool bAutoAbort) { |
1022 |
|
// check if the max. amount of child forks for this parent event handler |
1023 |
|
// instance have not been exceeded yet |
1024 |
|
if (parent->countChildHandlers() >= MAX_FORK_PER_SCRIPT_HANDLER) |
1025 |
|
return RTList<ScriptEvent>::Iterator(); |
1026 |
|
|
1027 |
|
// allocate a new script callback instance for child to be forked |
1028 |
|
RTList<ScriptEvent>::Iterator itChild = pScript->pEvents->allocAppend(); |
1029 |
|
if (!itChild) return itChild; |
1030 |
|
|
1031 |
|
// copy entire script handler state from parent to forked child |
1032 |
|
parent->forkTo(&*itChild, bAutoAbort); |
1033 |
|
|
1034 |
|
// stick the parent ID and child ID respectively to each other |
1035 |
|
itChild->parentHandlerID = GetScriptCallbackID(parent); |
1036 |
|
parent->addChildHandlerID( GetScriptCallbackID(&*itChild) ); |
1037 |
|
|
1038 |
|
// insert newly created (forked) child event handler instance to the |
1039 |
|
// scheduler queue for being executed soon |
1040 |
|
pEngine->pEventGenerator->scheduleAheadMicroSec( |
1041 |
|
pScript->suspendedEvents, // scheduler queue |
1042 |
|
*itChild, // script event |
1043 |
|
parent->cause.FragmentPos(), // current time of script event (basis for its next execution) |
1044 |
|
0 // "resume" new child script callback instance ASAP |
1045 |
|
); |
1046 |
|
|
1047 |
|
return itChild; |
1048 |
|
} |
1049 |
|
|
1050 |
FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) { |
FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) { |
1051 |
if (pEngine) pEngine->DisableAndLock(); |
if (pEngine) pEngine->DisableAndLock(); |
1052 |
FxSend* pFxSend = new FxSend(this, MidiCtrl, Name); |
FxSend* pFxSend = new FxSend(this, MidiCtrl, Name); |
1074 |
} |
} |
1075 |
|
|
1076 |
uint AbstractEngineChannel::GetFxSendCount() { |
uint AbstractEngineChannel::GetFxSendCount() { |
1077 |
return fxSends.size(); |
return (uint)fxSends.size(); |
1078 |
} |
} |
1079 |
|
|
1080 |
void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) { |
void AbstractEngineChannel::RemoveFxSend(FxSend* pFxSend) { |
1154 |
*/ |
*/ |
1155 |
void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) { |
void AbstractEngineChannel::HandleKeyGroupConflicts(uint KeyGroup, Pool<Event>::Iterator& itNoteOnEvent) { |
1156 |
dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup)); |
dmsg(4,("HandelKeyGroupConflicts KeyGroup=%d\n", KeyGroup)); |
1157 |
if (KeyGroup) { |
// when editing key groups with an instrument editor while sound was |
1158 |
|
// already loaded, ActiveKeyGroups may not have the KeyGroup in question |
1159 |
|
// so check for that to prevent a crash while editing instruments |
1160 |
|
if (KeyGroup && ActiveKeyGroups.count(KeyGroup)) { |
1161 |
// send a release event to all active voices in the group |
// send a release event to all active voices in the group |
1162 |
RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool); |
RTList<Event>::Iterator itEvent = ActiveKeyGroups[KeyGroup]->allocAppend(pEngine->pEventPool); |
1163 |
*itEvent = *itNoteOnEvent; |
*itEvent = *itNoteOnEvent; |