1 /*************************************************************************** 2 * * 3 * LinuxSampler - modular, streaming capable sampler * 4 * * 5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * 6 * Copyright (C) 2005 - 2021 Christian Schoenebeck * 7 * * 8 * This program is free software; you can redistribute it and/or modify * 9 * it under the terms of the GNU General Public License as published by * 10 * the Free Software Foundation; either version 2 of the License, or * 11 * (at your option) any later version. * 12 * * 13 * This program is distributed in the hope that it will be useful, * 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 16 * GNU General Public License for more details. * 17 * * 18 * You should have received a copy of the GNU General Public License * 19 * along with this program; if not, write to the Free Software * 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * 21 * MA 02111-1307 USA * 22 ***************************************************************************/ 23 24 #include "Event.h" 25 26 namespace LinuxSampler { 27 28 /** 29 * Create an EventGenerator. 30 * 31 * @param SampleRate - sample rate of the sampler engine's audio output 32 * signal (in Hz) 33 */ EventGenerator(uint SampleRate)34 EventGenerator::EventGenerator(uint SampleRate) { 35 uiSampleRate = SampleRate; 36 uiSamplesProcessed = 0; 37 FragmentTime.end = RTMath::CreateTimeStamp(); 38 uiTotalSamplesProcessed = 0; 39 } 40 SetSampleRate(uint SampleRate)41 void EventGenerator::SetSampleRate(uint SampleRate) { 42 uiSampleRate = SampleRate; 43 } 44 45 /** 46 * Updates the time stamps for the beginning and end of the current audio 47 * fragment. This is needed to be able to calculate the respective sample 48 * point later to which an event belongs to. 49 * 50 * @param SamplesToProcess - number of sample points to process in this 51 * audio fragment cycle 52 */ UpdateFragmentTime(uint SamplesToProcess)53 void EventGenerator::UpdateFragmentTime(uint SamplesToProcess) { 54 // update total amount of sample points being processed since this object was created 55 uiTotalSamplesProcessed += uiSamplesProcessed; 56 // update time stamp for this audio fragment cycle 57 FragmentTime.begin = FragmentTime.end; 58 FragmentTime.end = RTMath::CreateTimeStamp(); 59 // recalculate sample ratio for this audio fragment 60 time_stamp_t fragmentDuration = FragmentTime.end - FragmentTime.begin; 61 FragmentTime.sample_ratio = (float) uiSamplesProcessed / (float) fragmentDuration; 62 // store amount of samples to process for the next cycle 63 uiSamplesProcessed = SamplesToProcess; 64 } 65 66 /** 67 * Get the next scheduled MIDI event (the one with the lowest time value) 68 * for the current audio fragment cycle and remove it from the queue. This 69 * method will not return any event scheduled past the current audio 70 * fragment boundary. 71 * 72 * @param queue - where the MIDI events are scheduled on 73 * @param pool - used to allocate and deallocate ScheduledEvent objects 74 * @param end - you @b MUST always pass EventGenerator::schedTimeAtCurrentFragmentEnd() 75 * here reflecting the current audio fragment's scheduler end time 76 */ popNextScheduledEvent(RTAVLTree<ScheduledEvent> & queue,Pool<ScheduledEvent> & pool,sched_time_t end)77 RTList<ScheduledEvent>::Iterator EventGenerator::popNextScheduledEvent(RTAVLTree<ScheduledEvent>& queue, Pool<ScheduledEvent>& pool, sched_time_t end) { 78 if (queue.isEmpty()) 79 return RTList<ScheduledEvent>::Iterator(); // return invalid iterator 80 ScheduledEvent& e = queue.lowest(); 81 if (e.scheduleTime >= end) 82 return RTList<ScheduledEvent>::Iterator(); // no event scheduled before 'end' 83 RTList<ScheduledEvent>::Iterator itEvent = pool.fromPtr(&e); 84 queue.erase(e); 85 if (!itEvent || !itEvent->itEvent) { 86 dmsg(1,("EventGenerator::popNextScheduledEvent(): !itEvent\n")); 87 return itEvent; // should never happen at this point, but just to be sure 88 } 89 if (!itEvent->itEvent) { 90 dmsg(1,("EventGenerator::popNextScheduledEvent(): !itEvent->itEvent\n")); 91 return itEvent; // should never happen at this point, but just to be sure 92 } 93 94 // update position of this event in the current audio fragment 95 // (since calling scheduleAheadMicroSec() will relate to this) 96 itEvent->itEvent->iFragmentPos = int32_t( uiSamplesProcessed - (end - itEvent->scheduleTime) ); 97 // safety first: fragment boundary sanity checks 98 if (itEvent->itEvent->iFragmentPos < 0) 99 itEvent->itEvent->iFragmentPos = 0; 100 if (itEvent->itEvent->iFragmentPos >= uiSamplesProcessed) 101 itEvent->itEvent->iFragmentPos = uiSamplesProcessed - 1; 102 103 return itEvent; 104 } 105 106 /** 107 * Get the next instrument script event (the one with the lowest time value) 108 * for the current audio fragment cycle and remove it from the queue. This 109 * method will not return any event scheduled past the current audio 110 * fragment boundary. 111 * 112 * @param queue - where the instrument script events are scheduled on 113 * @param pool - used to allocate and deallocate ScriptEvent objects 114 * @param end - you @b MUST always pass EventGenerator::schedTimeAtCurrentFragmentEnd() 115 * here reflecting the current audio fragment's scheduler end time 116 */ popNextScheduledScriptEvent(RTAVLTree<ScriptEvent> & queue,Pool<ScriptEvent> & pool,sched_time_t end)117 RTList<ScriptEvent>::Iterator EventGenerator::popNextScheduledScriptEvent(RTAVLTree<ScriptEvent>& queue, Pool<ScriptEvent>& pool, sched_time_t end) { 118 if (queue.isEmpty()) 119 return RTList<ScriptEvent>::Iterator(); // return invalid iterator 120 ScriptEvent& e = queue.lowest(); 121 if (e.scheduleTime >= end) 122 return RTList<ScriptEvent>::Iterator(); // no event scheduled before 'end' 123 RTList<ScriptEvent>::Iterator itEvent = pool.fromPtr(&e); 124 queue.erase(e); 125 if (!itEvent) { // should never happen at this point, but just to be sure 126 dmsg(1,("EventGenerator::popNextScheduledScriptEvent(): !itEvent\n")); 127 return itEvent; 128 } 129 130 // update position of this event in the current audio fragment 131 // (since calling scheduleAheadMicroSec() will relate to this) 132 itEvent->cause.iFragmentPos = int32_t( uiSamplesProcessed - (end - itEvent->scheduleTime) ); 133 // safety first: fragment boundary sanity checks 134 if (itEvent->cause.iFragmentPos < 0) 135 itEvent->cause.iFragmentPos = 0; 136 if (itEvent->cause.iFragmentPos >= uiSamplesProcessed) 137 itEvent->cause.iFragmentPos = uiSamplesProcessed - 1; 138 139 return itEvent; 140 } 141 142 /** 143 * Create a new event with the current time as time stamp. 144 */ CreateEvent()145 Event EventGenerator::CreateEvent() { 146 return Event(this, RTMath::CreateTimeStamp()); 147 } 148 149 /** 150 * Create a new event for the given sample point position in the current 151 * audio fragment. 152 * 153 * @param FragmentPos - actual sample point position in the current 154 * audio fragment to which the new event belongs to 155 */ CreateEvent(int32_t FragmentPos)156 Event EventGenerator::CreateEvent(int32_t FragmentPos) { 157 return Event(this, FragmentPos); 158 } 159 160 /** 161 * Will be called by an EventGenerator to create a new Event. 162 * This Constructor expects a time stamp. The actual sample point 163 * position to which this event belongs to will be calculated later 164 * when FragmentPos() was called the first time. 165 * 166 * @param pGenerator - creator of this event 167 * @param Time - time stamp on which this event occured 168 */ Event(EventGenerator * pGenerator,time_stamp_t Time)169 Event::Event(EventGenerator* pGenerator, time_stamp_t Time) { 170 Init(); 171 pEventGenerator = pGenerator; 172 TimeStamp = Time; 173 iFragmentPos = -1; 174 } 175 176 /** 177 * Will be called by an EventGenerator to create a new Event. 178 * This constructor expects the final sample point position to which 179 * this event belongs to. 180 * 181 * @param pGenerator - creator of this event 182 * @param FragmentPos - actual sample point position in the current 183 * audio fragment to which this event belongs to 184 */ Event(EventGenerator * pGenerator,int32_t FragmentPos)185 Event::Event(EventGenerator* pGenerator, int32_t FragmentPos) { 186 Init(); 187 pEventGenerator = pGenerator; 188 iFragmentPos = FragmentPos; 189 } 190 191 /** 192 * Implements fork() behavior, that is it copies the current state of this 193 * script event handler to the new event handler @a e with entire execution 194 * state and polyphonic data. 195 * 196 * After calling this method, addChildHandler() should be called as well. 197 */ forkTo(ScriptEvent * e,bool bAutoAbort) const198 void ScriptEvent::forkTo(ScriptEvent* e, bool bAutoAbort) const { 199 e->scheduleTime = scheduleTime; 200 e->cause = cause; 201 e->id = id; 202 // forked script shall only run the current event handler of parent, 203 // no other potentially chained handlers 204 e->handlers[0] = handlers[currentHandler]; 205 e->handlers[1] = NULL; // NULL termination of list 206 e->currentHandler = 0; 207 e->executionSlices = 0; 208 e->ignoreAllWaitCalls = ignoreAllWaitCalls; 209 e->releaseMatched = true; // this is not the original: never match a release handler with a forked note handler instance 210 e->handlerType = handlerType; 211 e->parentHandlerID = 0; // just an arbitrary init value, must still be set later! 212 e->childHandlerID[0] = 0; 213 e->autoAbortByParent = bAutoAbort; 214 e->forkIndex = 1; // just an arbitrary init value, must still be set later! 215 216 execCtx->forkTo(e->execCtx); 217 } 218 219 /** 220 * Returns amount of child event handlers that have been created so far 221 * during the entire life time of this event handler instance by calls of 222 * this event handler instace to the built-in script function fork(). 223 * 224 * To make this clear: this number does never decrease during the entire 225 * life time of an event handler instance! It may only increase, i.e. by 226 * additional calls to fork(). Consequently even if child event handler 227 * instances already terminated, this will not decrease this count. 228 */ countChildHandlers() const229 int ScriptEvent::countChildHandlers() const { 230 int n = 0; 231 for (int i = 0; i < MAX_FORK_PER_SCRIPT_HANDLER && childHandlerID[i]; ++i) 232 ++n; 233 return n; 234 } 235 236 /** 237 * This must be called after calling forkTo() to stick the script callback 238 * ID of the newly forked child execution instance to the parent execution 239 * instance. 240 * 241 * @param childID - script callback ID of the newly forked child handler 242 */ addChildHandlerID(script_callback_id_t childID)243 void ScriptEvent::addChildHandlerID(script_callback_id_t childID) { 244 const int n = countChildHandlers(); 245 if (n >= MAX_FORK_PER_SCRIPT_HANDLER) { 246 dmsg(1,("ScriptEvent::addChildHandlerID(): MAX_FORK_PER_SCRIPT_HANDLER exceeded, this is a bug!\n")); 247 return; 248 } 249 childHandlerID[n] = childID; 250 childHandlerID[n+1] = 0; // zero termination of list 251 } 252 253 } // namespace LinuxSampler 254