/[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 3293 - (hide annotations) (download)
Tue Jun 27 22:19:19 2017 UTC (6 years, 10 months ago) by schoenebeck
File size: 11639 byte(s)
* NKSP: Added built-in script function "fork()".
* NKSP: Added built-in array variable %NKSP_CALLBACK_CHILD_ID[].
* NKSP: Added built-in variable $NKSP_CALLBACK_PARENT_ID.
* NKSP: Fixed potential crash when accessing dynamic built-in
  array variables.
* Bumped version (2.0.0.svn65).

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 3293 * Copyright (C) 2005 - 2017 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     e->handlerType = handlerType;
210     e->parentHandlerID = 0; // just an arbitrary init value, must still be set later!
211     e->childHandlerID[0] = 0;
212     e->autoAbortByParent = bAutoAbort;
213     e->forkIndex = 1; // just an arbitrary init value, must still be set later!
214    
215     execCtx->forkTo(e->execCtx);
216     }
217    
218     /**
219     * Returns amount of child event handlers that have been created so far
220     * during the entire life time of this event handler instance by calls of
221     * this event handler instace to the built-in script function fork().
222     *
223     * To make this clear: this number does never decrease during the entire
224     * life time of an event handler instance! It may only increase, i.e. by
225     * additional calls to fork(). Consequently even if child event handler
226     * instances already terminated, this will not decrease this count.
227     */
228     int ScriptEvent::countChildHandlers() const {
229     int n = 0;
230     for (int i = 0; i < MAX_FORK_PER_SCRIPT_HANDLER && childHandlerID[i]; ++i)
231     ++n;
232     return n;
233     }
234    
235     /**
236     * This must be called after calling forkTo() to stick the script callback
237     * ID of the newly forked child execution instance to the parent execution
238     * instance.
239     *
240     * @param childID - script callback ID of the newly forked child handler
241     */
242     void ScriptEvent::addChildHandlerID(script_callback_id_t childID) {
243     const int n = countChildHandlers();
244     if (n >= MAX_FORK_PER_SCRIPT_HANDLER) {
245     dmsg(1,("ScriptEvent::addChildHandlerID(): MAX_FORK_PER_SCRIPT_HANDLER exceeded, this is a bug!\n"));
246     return;
247     }
248     childHandlerID[n] = childID;
249     childHandlerID[n+1] = 0; // zero termination of list
250     }
251    
252 schoenebeck 53 } // namespace LinuxSampler

  ViewVC Help
Powered by ViewVC