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-2008 Christian Schoenebeck * |
7 |
* Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev * |
* Copyright (C) 2009-2012 Christian Schoenebeck and Grigor Iliev * |
8 |
* Copyright (C) 2013-2014 Christian Schoenebeck and Andreas Persson * |
* Copyright (C) 2012-2016 Christian Schoenebeck and 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 * |
35 |
{ |
{ |
36 |
pEngine = NULL; |
pEngine = NULL; |
37 |
pEvents = NULL; // we allocate when we retrieve the right Engine object |
pEvents = NULL; // we allocate when we retrieve the right Engine object |
38 |
|
delayedEvents.pList = NULL; |
39 |
pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0); |
pEventQueue = new RingBuffer<Event,false>(CONFIG_MAX_EVENTS_PER_FRAGMENT, 0); |
40 |
InstrumentIdx = -1; |
InstrumentIdx = -1; |
41 |
InstrumentStat = -1; |
InstrumentStat = -1; |
102 |
|
|
103 |
void AbstractEngineChannel::Reset() { |
void AbstractEngineChannel::Reset() { |
104 |
if (pEngine) pEngine->DisableAndLock(); |
if (pEngine) pEngine->DisableAndLock(); |
105 |
ResetInternal(); |
ResetInternal(false/*don't reset engine*/); |
106 |
ResetControllers(); |
ResetControllers(); |
107 |
if (pEngine) { |
if (pEngine) { |
108 |
pEngine->Enable(); |
pEngine->Enable(); |
130 |
/** |
/** |
131 |
* This method is not thread safe! |
* This method is not thread safe! |
132 |
*/ |
*/ |
133 |
void AbstractEngineChannel::ResetInternal() { |
void AbstractEngineChannel::ResetInternal(bool bResetEngine) { |
134 |
CurrentKeyDimension = 0; |
CurrentKeyDimension = 0; |
135 |
PortamentoPos = -1.0f; // no portamento active yet |
PortamentoPos = -1.0f; // no portamento active yet |
136 |
|
|
137 |
|
// delete all active instrument script events |
138 |
|
if (pScript) pScript->resetEvents(); |
139 |
|
|
140 |
|
// free all delayed MIDI events |
141 |
|
delayedEvents.clear(); |
142 |
|
|
143 |
// delete all input events |
// delete all input events |
144 |
pEventQueue->init(); |
pEventQueue->init(); |
145 |
|
|
146 |
if (pEngine) pEngine->ResetInternal(); |
if (bResetEngine && pEngine) pEngine->ResetInternal(); |
147 |
|
|
148 |
// status of engine channel has changed, so set notify flag |
// status of engine channel has changed, so set notify flag |
149 |
bStatusChanged = true; |
bStatusChanged = true; |
817 |
|
|
818 |
/** |
/** |
819 |
* Called by real-time instrument script functions to schedule a new event |
* Called by real-time instrument script functions to schedule a new event |
820 |
* somewhere in future. |
* @a delay microseconds in future. |
821 |
* |
* |
822 |
* @returns unique event ID of scheduled new event |
* @b IMPORTANT: for the supplied @a delay to be scheduled correctly, the |
823 |
|
* passed @a pEvent must be assigned a valid fragment time within the |
824 |
|
* current audio fragment boundaries. That fragment time will be used by |
825 |
|
* this method as basis for interpreting what "now" acutally is, and thus |
826 |
|
* it will be used as basis for calculating the precise scheduling time |
827 |
|
* for @a delay. The easiest way to achieve this is by copying a recent |
828 |
|
* event which happened within the current audio fragment cycle: i.e. the |
829 |
|
* original event which caused calling this method here. |
830 |
|
* |
831 |
|
* @param pEvent - event to be scheduled in future (event data will be copied) |
832 |
|
* @param delay - amount of microseconds in future (from now) when event shall be processed |
833 |
|
* @returns unique event ID of scheduled new event, or a negative number on error |
834 |
*/ |
*/ |
835 |
int AbstractEngineChannel::ScheduleEvent(const Event* pEvent, int delay) { //TODO: delay not implemented yet |
int AbstractEngineChannel::ScheduleEventMicroSec(const Event* pEvent, int delay) { |
836 |
// since delay is not implemented yet, we simply add the new event |
dmsg(3,("AbstractEngineChannel::ScheduleEventMicroSec(Event.Type=%d,delay=%d)\n", pEvent->Type, delay)); |
|
// to the event list of the current audio fragmet cycle for now |
|
837 |
RTList<Event>::Iterator itEvent = pEvents->allocAppend(); |
RTList<Event>::Iterator itEvent = pEvents->allocAppend(); |
838 |
if (itEvent) *itEvent = *pEvent; // copy event |
if (!itEvent) { |
839 |
|
dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): Event pool emtpy!\n")); |
840 |
|
return -1; |
841 |
|
} |
842 |
|
RTList<ScheduledEvent>::Iterator itNode = delayedEvents.schedulerNodes.allocAppend(); |
843 |
|
if (!itNode) { // scheduler node pool empty ... |
844 |
|
dmsg(1,("AbstractEngineChannel::ScheduleEventMicroSec(): ScheduledEvent pool empty!\n")); |
845 |
|
pEvents->free(itEvent); |
846 |
|
return -1; |
847 |
|
} |
848 |
|
// copy passed event |
849 |
|
*itEvent = *pEvent; |
850 |
|
// move copied event to list of delayed events |
851 |
|
itEvent = itEvent.moveToEndOf(delayedEvents.pList); |
852 |
|
// connect scheduler node with the copied event |
853 |
|
itNode->itEvent = itEvent; |
854 |
|
// add entry to time sorted scheduler queue for copied event |
855 |
|
pEngine->pEventGenerator->scheduleAheadMicroSec( |
856 |
|
delayedEvents.queue, *itNode, itEvent->FragmentPos(), delay |
857 |
|
); |
858 |
|
//dmsg(5,("ScheduledEvent queue size: %d\n", delayedEvents.queue.size())); |
859 |
return pEvents->getID(itEvent); |
return pEvents->getID(itEvent); |
860 |
} |
} |
861 |
|
|