/[svn]/linuxsampler/trunk/src/engines/common/Event.cpp
ViewVC logotype

Contents of /linuxsampler/trunk/src/engines/common/Event.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3845 - (show annotations) (download)
Tue Jan 5 20:42:32 2021 UTC (3 years, 3 months ago) by schoenebeck
File size: 11768 byte(s)
* ScriptVM: Fixed incorrect polyphonic data transfer from wrong "note"
  handler to "release" handler; which also fixes no "release" handler
  being executed sometimes, and due to the latter it also fixes potential
  crashes as some polyphonic script events were never released and the
  engine hence was running out of free script events.

* Bumped version (2.1.1.svn68).

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 */
34 EventGenerator::EventGenerator(uint SampleRate) {
35 uiSampleRate = SampleRate;
36 uiSamplesProcessed = 0;
37 FragmentTime.end = RTMath::CreateTimeStamp();
38 uiTotalSamplesProcessed = 0;
39 }
40
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
198 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 */
229 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 */
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

  ViewVC Help
Powered by ViewVC