383 |
event.Param.Note.Key = Key; |
event.Param.Note.Key = Key; |
384 |
event.Param.Note.Velocity = Velocity; |
event.Param.Note.Velocity = Velocity; |
385 |
event.Param.Note.Channel = MidiChannel; |
event.Param.Note.Channel = MidiChannel; |
|
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
|
386 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
387 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
388 |
else dmsg(1,("EngineChannel: Input event queue full!")); |
else dmsg(1,("EngineChannel: Input event queue full!")); |
424 |
event.Param.Note.Key = Key; |
event.Param.Note.Key = Key; |
425 |
event.Param.Note.Velocity = Velocity; |
event.Param.Note.Velocity = Velocity; |
426 |
event.Param.Note.Channel = MidiChannel; |
event.Param.Note.Channel = MidiChannel; |
|
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
|
427 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
428 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
429 |
else dmsg(1,("EngineChannel: Input event queue full!")); |
else dmsg(1,("EngineChannel: Input event queue full!")); |
460 |
event.Param.Note.Key = Key; |
event.Param.Note.Key = Key; |
461 |
event.Param.Note.Velocity = Velocity; |
event.Param.Note.Velocity = Velocity; |
462 |
event.Param.Note.Channel = MidiChannel; |
event.Param.Note.Channel = MidiChannel; |
|
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
|
463 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
464 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
465 |
else dmsg(1,("EngineChannel: Input event queue full!")); |
else dmsg(1,("EngineChannel: Input event queue full!")); |
501 |
event.Param.Note.Key = Key; |
event.Param.Note.Key = Key; |
502 |
event.Param.Note.Velocity = Velocity; |
event.Param.Note.Velocity = Velocity; |
503 |
event.Param.Note.Channel = MidiChannel; |
event.Param.Note.Channel = MidiChannel; |
|
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
|
504 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
505 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
506 |
else dmsg(1,("EngineChannel: Input event queue full!")); |
else dmsg(1,("EngineChannel: Input event queue full!")); |
535 |
event.Type = Event::type_pitchbend; |
event.Type = Event::type_pitchbend; |
536 |
event.Param.Pitch.Pitch = Pitch; |
event.Param.Pitch.Pitch = Pitch; |
537 |
event.Param.Pitch.Channel = MidiChannel; |
event.Param.Pitch.Channel = MidiChannel; |
|
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
|
538 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
539 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
540 |
else dmsg(1,("EngineChannel: Input event queue full!")); |
else dmsg(1,("EngineChannel: Input event queue full!")); |
564 |
event.Type = Event::type_pitchbend; |
event.Type = Event::type_pitchbend; |
565 |
event.Param.Pitch.Pitch = Pitch; |
event.Param.Pitch.Pitch = Pitch; |
566 |
event.Param.Pitch.Channel = MidiChannel; |
event.Param.Pitch.Channel = MidiChannel; |
|
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; |
|
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
|
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!")); |
621 |
event.Param.CC.Controller = Controller; |
event.Param.CC.Controller = Controller; |
622 |
event.Param.CC.Value = Value; |
event.Param.CC.Value = Value; |
623 |
event.Param.CC.Channel = MidiChannel; |
event.Param.CC.Channel = MidiChannel; |
|
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
|
624 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
625 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
626 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
638 |
event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts |
event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts |
639 |
event.Param.ChannelPressure.Value = Value; |
event.Param.ChannelPressure.Value = Value; |
640 |
event.Param.ChannelPressure.Channel = MidiChannel; |
event.Param.ChannelPressure.Channel = MidiChannel; |
|
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
|
641 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
642 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
643 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
655 |
event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts |
event.Param.ChannelPressure.Controller = CTRL_TABLE_IDX_AFTERTOUCH; // required for instrument scripts |
656 |
event.Param.ChannelPressure.Value = Value; |
event.Param.ChannelPressure.Value = Value; |
657 |
event.Param.ChannelPressure.Channel = MidiChannel; |
event.Param.ChannelPressure.Channel = MidiChannel; |
|
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
|
658 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
659 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
660 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
672 |
event.Param.NotePressure.Key = Key; |
event.Param.NotePressure.Key = Key; |
673 |
event.Param.NotePressure.Value = Value; |
event.Param.NotePressure.Value = Value; |
674 |
event.Param.NotePressure.Channel = MidiChannel; |
event.Param.NotePressure.Channel = MidiChannel; |
|
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
|
675 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
676 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
677 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
689 |
event.Param.NotePressure.Key = Key; |
event.Param.NotePressure.Key = Key; |
690 |
event.Param.NotePressure.Value = Value; |
event.Param.NotePressure.Value = Value; |
691 |
event.Param.NotePressure.Channel = MidiChannel; |
event.Param.NotePressure.Channel = MidiChannel; |
|
memset(&event.Format, 0, sizeof(event.Format)); // init format speific stuff with zeroes |
|
692 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
693 |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
if (this->pEventQueue->write_space() > 0) this->pEventQueue->push(&event); |
694 |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
else dmsg(1,("AbstractEngineChannel: Input event queue full!")); |
695 |
} |
} |
696 |
} |
} |
697 |
|
|
698 |
|
bool AbstractEngineChannel::applyTranspose(Event* event) { |
699 |
|
if (event->Type != Event::type_note_on && event->Type != Event::type_note_off) |
700 |
|
return true; // event OK (not a note event, nothing to do with it here) |
701 |
|
|
702 |
|
//HACK: we should better add the transpose value only to the most mandatory places (like for retrieving the region and calculating the tuning), because otherwise voices will unintendedly survive when changing transpose while playing |
703 |
|
const int k = event->Param.Note.Key + GlobalTranspose; |
704 |
|
if (k < 0 || k > 127) |
705 |
|
return false; // bad event, drop it |
706 |
|
|
707 |
|
event->Param.Note.Key = k; |
708 |
|
|
709 |
|
return true; // event OK |
710 |
|
} |
711 |
|
|
712 |
/** |
/** |
713 |
* Copy all events from the engine channel's input event queue buffer to |
* Copy all events from the engine channel's input event queue buffer to |
714 |
* the internal event list. This will be done at the beginning of each |
* the internal event list. This will be done at the beginning of each |
745 |
event.Param.Note.Key = devEvent.Arg1; |
event.Param.Note.Key = devEvent.Arg1; |
746 |
event.Param.Note.Velocity = devEvent.Arg2; |
event.Param.Note.Velocity = devEvent.Arg2; |
747 |
event.Param.Note.Channel = channel; |
event.Param.Note.Channel = channel; |
748 |
|
// apply transpose setting to (note on/off) event |
749 |
|
if (!applyTranspose(&event)) |
750 |
|
continue; // note value is out of range, so drop this event |
751 |
|
// assign a new note to this note-on event |
752 |
|
if (!pEngine->LaunchNewNote(this, &event)) |
753 |
|
continue; // failed launching new note, so drop this event |
754 |
break; |
break; |
755 |
case VirtualMidiDevice::EVENT_TYPE_NOTEOFF: |
case VirtualMidiDevice::EVENT_TYPE_NOTEOFF: |
756 |
event.Type = Event::type_note_off; |
event.Type = Event::type_note_off; |
757 |
event.Param.Note.Key = devEvent.Arg1; |
event.Param.Note.Key = devEvent.Arg1; |
758 |
event.Param.Note.Velocity = devEvent.Arg2; |
event.Param.Note.Velocity = devEvent.Arg2; |
759 |
event.Param.Note.Channel = channel; |
event.Param.Note.Channel = channel; |
760 |
|
if (!applyTranspose(&event)) |
761 |
|
continue; // note value is out of range, so drop this event |
762 |
break; |
break; |
763 |
case VirtualMidiDevice::EVENT_TYPE_CC: |
case VirtualMidiDevice::EVENT_TYPE_CC: |
764 |
switch (devEvent.Arg1) { |
switch (devEvent.Arg1) { |
788 |
<< devEvent.Type << "). This is a bug!"; |
<< devEvent.Type << "). This is a bug!"; |
789 |
continue; |
continue; |
790 |
} |
} |
|
memset(&event.Format, 0, sizeof(event.Format)); // init format specific stuff with zeroes |
|
791 |
event.pEngineChannel = this; |
event.pEngineChannel = this; |
792 |
// copy event to internal event list |
// copy event to internal event list |
793 |
if (pEvents->poolIsEmpty()) { |
if (pEvents->poolIsEmpty()) { |
814 |
pEvent->ResetFragmentPos(); |
pEvent->ResetFragmentPos(); |
815 |
break; |
break; |
816 |
} |
} |
|
// copy event to internal event list |
|
817 |
if (pEvents->poolIsEmpty()) { |
if (pEvents->poolIsEmpty()) { |
818 |
dmsg(1,("Event pool emtpy!\n")); |
dmsg(1,("Event pool emtpy!\n")); |
819 |
break; |
break; |
820 |
} |
} |
821 |
|
// apply transpose setting to (note on/off) event |
822 |
|
if (!applyTranspose(pEvent)) |
823 |
|
continue; // it's a note event which has a note value out of range, so drop this event |
824 |
|
// assign a new note to this event (if its a note-on event) |
825 |
|
if (pEvent->Type == Event::type_note_on) |
826 |
|
if (!pEngine->LaunchNewNote(this, pEvent)) |
827 |
|
continue; // failed launching new note, so drop this event |
828 |
|
// copy event to internal event list |
829 |
*pEvents->allocAppend() = *pEvent; |
*pEvents->allocAppend() = *pEvent; |
830 |
} |
} |
831 |
eventQueueReader.free(); // free all copied events from input queue |
eventQueueReader.free(); // free all copied events from input queue |
846 |
* |
* |
847 |
* @param pEvent - event to be scheduled in future (event data will be copied) |
* @param pEvent - event to be scheduled in future (event data will be copied) |
848 |
* @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 |
849 |
* @returns unique event ID of scheduled new event, or a negative number on error |
* @returns unique event ID of scheduled new event, or NULL on error |
850 |
*/ |
*/ |
851 |
int AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int delay) { |
event_id_t AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int delay) { |
852 |
dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%d)\n", pEvent->Type, delay)); |
dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%d)\n", pEvent->Type, delay)); |
853 |
RTList<Event>::Iterator itEvent = pEvents->allocAppend(); |
RTList<Event>::Iterator itEvent = pEvents->allocAppend(); |
854 |
if (!itEvent) { |
if (!itEvent) { |
855 |
dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n")); |
dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n")); |
856 |
return -1; |
return 0; |
857 |
} |
} |
858 |
RTList<ScheduledEvent>::Iterator itNode = delayedEvents.schedulerNodes.allocAppend(); |
RTList<ScheduledEvent>::Iterator itNode = delayedEvents.schedulerNodes.allocAppend(); |
859 |
if (!itNode) { // scheduler node pool empty ... |
if (!itNode) { // scheduler node pool empty ... |
860 |
dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): ScheduledEvent pool empty!\n")); |
dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): ScheduledEvent pool empty!\n")); |
861 |
pEvents->free(itEvent); |
pEvents->free(itEvent); |
862 |
return -1; |
return 0; |
863 |
} |
} |
864 |
// copy passed event |
// copy passed event |
865 |
*itEvent = *pEvent; |
*itEvent = *pEvent; |
880 |
* reflected by given event ID. The event will be freed immediately to its |
* reflected by given event ID. The event will be freed immediately to its |
881 |
* pool and cannot be dereferenced by its old ID anymore. Even if its |
* pool and cannot be dereferenced by its old ID anymore. Even if its |
882 |
* allocated back from the Pool later on, it will have a different ID. |
* allocated back from the Pool later on, it will have a different ID. |
883 |
|
* |
884 |
|
* @param id - unique ID of event to be dropped |
885 |
*/ |
*/ |
886 |
void AbstractEngineChannel::IgnoreEvent(int id) { |
void AbstractEngineChannel::IgnoreEvent(event_id_t id) { |
887 |
RTList<Event>::Iterator it = pEvents->fromID(id); |
RTList<Event>::Iterator it = pEvents->fromID(id); |
888 |
if (it) pEvents->free(it); |
if (it) pEvents->free(it); |
889 |
} |
} |
890 |
|
|
891 |
|
/** |
892 |
|
* Called by real-time instrument script functions to ignore the note |
893 |
|
* reflected by given note ID. The note's event will be freed immediately |
894 |
|
* to its event pool and this will prevent voices to be launched for the |
895 |
|
* note. |
896 |
|
* |
897 |
|
* NOTE: preventing a note by calling this method works only if the note |
898 |
|
* was launched within the current audio fragment cycle. |
899 |
|
* |
900 |
|
* @param id - unique ID of note to be dropped |
901 |
|
*/ |
902 |
|
void AbstractEngineChannel::IgnoreNote(note_id_t id) { |
903 |
|
NoteBase* pNote = pEngine->NoteByID(id); |
904 |
|
if (!pNote) return; |
905 |
|
IgnoreEvent(pNote->eventID); |
906 |
|
} |
907 |
|
|
908 |
|
/** @brief Drop the requested event. |
909 |
|
* |
910 |
|
* Called by real-time instrument script functions to ignore the event |
911 |
|
* reflected by the given event @a id. This method detects whether the |
912 |
|
* passed ID is actually a @c Note ID or a regular @c Event ID and act |
913 |
|
* accordingly. |
914 |
|
* |
915 |
|
* @param id - event id (from script scope) |
916 |
|
* @see ScriptID |
917 |
|
*/ |
918 |
|
void AbstractEngineChannel::IgnoreEventByScriptID(const ScriptID& id) { |
919 |
|
switch (id.type()) { |
920 |
|
case ScriptID::EVENT: |
921 |
|
IgnoreEvent( id.eventID() ); |
922 |
|
break; |
923 |
|
case ScriptID::NOTE: |
924 |
|
IgnoreNote( id.noteID() ); |
925 |
|
break; |
926 |
|
} |
927 |
|
} |
928 |
|
|
929 |
FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) { |
FxSend* AbstractEngineChannel::AddFxSend(uint8_t MidiCtrl, String Name) throw (Exception) { |
930 |
if (pEngine) pEngine->DisableAndLock(); |
if (pEngine) pEngine->DisableAndLock(); |
931 |
FxSend* pFxSend = new FxSend(this, MidiCtrl, Name); |
FxSend* pFxSend = new FxSend(this, MidiCtrl, Name); |