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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3845 - (hide 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 schoenebeck 53 /***************************************************************************
2     * *
3     * LinuxSampler - modular, streaming capable sampler *
4     * *
5 schoenebeck 56 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 schoenebeck 3845 * Copyright (C) 2005 - 2021 Christian Schoenebeck *
7 schoenebeck 53 * *
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 schoenebeck 328 FragmentTime.end = RTMath::CreateTimeStamp();
38 schoenebeck 2871 uiTotalSamplesProcessed = 0;
39 schoenebeck 53 }
40    
41 schoenebeck 3283 void EventGenerator::SetSampleRate(uint SampleRate) {
42     uiSampleRate = SampleRate;
43     }
44    
45 schoenebeck 53 /**
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 schoenebeck 2871 // update total amount of sample points being processed since this object was created
55     uiTotalSamplesProcessed += uiSamplesProcessed;
56 schoenebeck 53 // update time stamp for this audio fragment cycle
57     FragmentTime.begin = FragmentTime.end;
58 schoenebeck 328 FragmentTime.end = RTMath::CreateTimeStamp();
59 schoenebeck 53 // 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 schoenebeck 2871
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 schoenebeck 53
94 schoenebeck 2871 // update position of this event in the current audio fragment
95     // (since calling scheduleAheadMicroSec() will relate to this)
96 schoenebeck 3054 itEvent->itEvent->iFragmentPos = int32_t( uiSamplesProcessed - (end - itEvent->scheduleTime) );
97 schoenebeck 2871 // 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 schoenebeck 53 /**
107 schoenebeck 2871 * 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 schoenebeck 3054 itEvent->cause.iFragmentPos = int32_t( uiSamplesProcessed - (end - itEvent->scheduleTime) );
133 schoenebeck 2871 // 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 schoenebeck 53 * Create a new event with the current time as time stamp.
144     */
145     Event EventGenerator::CreateEvent() {
146 schoenebeck 328 return Event(this, RTMath::CreateTimeStamp());
147 schoenebeck 53 }
148    
149     /**
150 schoenebeck 906 * 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 schoenebeck 53 * Will be called by an EventGenerator to create a new Event.
162 schoenebeck 906 * 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 schoenebeck 53 */
169     Event::Event(EventGenerator* pGenerator, time_stamp_t Time) {
170 schoenebeck 2879 Init();
171 schoenebeck 53 pEventGenerator = pGenerator;
172     TimeStamp = Time;
173     iFragmentPos = -1;
174     }
175    
176 schoenebeck 906 /**
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 schoenebeck 2879 Init();
187 schoenebeck 906 pEventGenerator = pGenerator;
188     iFragmentPos = FragmentPos;
189     }
190    
191 schoenebeck 3293 /**
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 schoenebeck 3845 e->releaseMatched = true; // this is not the original: never match a release handler with a forked note handler instance
210 schoenebeck 3293 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 schoenebeck 53 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC