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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3283 - (show annotations) (download) (as text)
Wed Jun 21 20:59:06 2017 UTC (6 years, 9 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 20607 byte(s)
* RT Instrument Scripts: Fixed potential memory access bug
  and potential undefined behavior of "init" event handlers.
* Bumped version (2.0.0.svn62).

1 /***************************************************************************
2 * *
3 * LinuxSampler - modular, streaming capable sampler *
4 * *
5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck *
6 * Copyright (C) 2005 - 2017 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 #ifndef __LS_EVENT_H__
25 #define __LS_EVENT_H__
26
27 #include "../../common/global.h"
28 #include "../../common/RTMath.h"
29 #include "../../common/RTAVLTree.h"
30 #include "../../common/Pool.h"
31 #include "../EngineChannel.h"
32 #include "../../scriptvm/common.h"
33
34 namespace LinuxSampler {
35
36 // just symbol prototyping
37 class Event;
38 class SchedulerNode;
39 class ScriptEvent;
40 class ScheduledEvent;
41
42 /**
43 * Data type used to schedule events sample point accurately both within, as
44 * well as beyond the scope of the current audio fragment cycle. The timing
45 * reflected by this data type is consecutively running for a very long
46 * time. Even with a sample rate of 96 kHz a scheduler time of this data
47 * type will not wrap before 6 million years. So in practice such time
48 * stamps are unique and will not repeat (unless the EventGenerator is
49 * reset).
50 */
51 typedef uint64_t sched_time_t;
52
53 /**
54 * Generates Event objects and is responsible for resolving the position
55 * in the current audio fragment each Event actually belongs to.
56 */
57 class EventGenerator {
58 public:
59 EventGenerator(uint SampleRate);
60 void UpdateFragmentTime(uint SamplesToProcess);
61 void SetSampleRate(uint SampleRate);
62 Event CreateEvent();
63 Event CreateEvent(int32_t FragmentPos);
64
65 template<typename T>
66 void scheduleAheadMicroSec(RTAVLTree<T>& queue, T& node, int32_t fragmentPosBase, uint64_t microseconds);
67
68 RTList<ScheduledEvent>::Iterator popNextScheduledEvent(RTAVLTree<ScheduledEvent>& queue, Pool<ScheduledEvent>& pool, sched_time_t end);
69 RTList<ScriptEvent>::Iterator popNextScheduledScriptEvent(RTAVLTree<ScriptEvent>& queue, Pool<ScriptEvent>& pool, sched_time_t end);
70
71 /**
72 * Returns the scheduler time for the first sample point of the
73 * current audio fragment cycle.
74 */
75 sched_time_t schedTimeAtCurrentFragmentStart() const {
76 return uiTotalSamplesProcessed;
77 }
78
79 /**
80 * Returns the scheduler time for the first sample point of the next
81 * audio fragment cycle.
82 */
83 sched_time_t schedTimeAtCurrentFragmentEnd() const {
84 return uiTotalSamplesProcessed + uiSamplesProcessed;
85 }
86
87 protected:
88 typedef RTMath::time_stamp_t time_stamp_t;
89 inline int32_t ToFragmentPos(time_stamp_t TimeStamp) {
90 return int32_t (int32_t(TimeStamp - FragmentTime.begin) * FragmentTime.sample_ratio);
91 }
92 friend class Event;
93 private:
94 uint uiSampleRate;
95 uint uiSamplesProcessed;
96 struct __FragmentTime__ {
97 time_stamp_t begin; ///< Real time stamp of the beginning of this audio fragment cycle.
98 time_stamp_t end; ///< Real time stamp of the end of this audio fragment cycle.
99 float sample_ratio; ///< (Samples per cycle) / (Real time duration of cycle)
100 } FragmentTime;
101 sched_time_t uiTotalSamplesProcessed; ///< Total amount of sample points that have been processed since this EventGenerator object has been created. This is used to schedule instrument script events long time ahead in future (that is beyond the scope of the current audio fragment).
102 };
103
104 /**
105 * Unique numeric ID of an event which can be used to retrieve access to
106 * the actual @c Event object. Once the event associated with a certain ID
107 * was released (back to its event pool), this numeric ID becomes invalid
108 * and Pool< Event >::fromID() will detect this circumstance and will
109 * return an invalid Iterator, and thus will prevent you from misusing an
110 * event which no longer "exists".
111 *
112 * Note that an @c Event object usually just "exists" for exactly on audio
113 * fragment cycle: that is it exists right from the beginning of the audio
114 * fragment cycle where it was caused (i.e. where its MIDI data was
115 * received by the respective engine channel) and will disappear
116 * automatically at the end of that audio fragment cycle.
117 */
118 typedef pool_element_id_t event_id_t;
119
120 /**
121 * Unique numeric ID of a note which can be used to retrieve access to the
122 * actual @c Note object. Once the note associated with a certain ID was
123 * released (back to its note pool), this numeric ID becomes invalid and
124 * Pool< Note >::fromID() will detect this circumstance and will return
125 * an invalid Iterator, and thus will prevent you from misusing a note
126 * which no longer is "alive".
127 *
128 * A @c Note object exists right when the respective MIDI note-on event
129 * was received by the respective engine channel, and remains existent
130 * until the caused note and all its voices were finally freed (which might
131 * even be long time after the respective note-off event was received,
132 * depending on the duration of the voice's release stages etc.).
133 */
134 typedef pool_element_id_t note_id_t;
135
136 /**
137 * Unique numeric ID of a script callback ID instance which can be used to
138 * retrieve access to the actual @c ScriptEvent object. Once the script
139 * callback instance associated with a certain ID stopped its execution
140 * (that is completely stopped, not just suspended) then this numeric ID
141 * becomes invalid and Pool< ScriptEvent >::fromID() will detect this
142 * circumstance and will return an invalid Iterator, and thus will prevent
143 * you from misusing a script callback instance which no longer "exists".
144 */
145 typedef pool_element_id_t script_callback_id_t;
146
147 /**
148 * Events are usually caused by a MIDI source or an internal modulation
149 * controller like LFO or EG. An event should only be created by an
150 * EventGenerator!
151 *
152 * @see EventGenerator, ScriptEvent
153 */
154 class Event {
155 public:
156 Event(){}
157 enum type_t {
158 type_note_on, ///< (real) MIDI note-on event
159 type_note_off, ///< (real) MIDI note-off event
160 type_pitchbend, ///< MIDI pitch bend wheel change event
161 type_control_change, ///< MIDI CC event
162 type_sysex, ///< MIDI system exclusive message
163 type_cancel_release_key, ///< transformed either from a (real) MIDI note-on or sustain-pedal-down event
164 type_release_key, ///< transformed either from a (real) MIDI note-off or sustain-pedal-up event
165 type_release_note, ///< transformed from a type_stop_note event
166 type_channel_pressure, ///< a.k.a. aftertouch
167 type_note_pressure, ///< polyphonic key pressure (aftertouch)
168 type_play_note, ///< caused by a call to built-in instrument script function play_note()
169 type_stop_note, ///< caused by a call to built-in instrument script function note_off()
170 type_kill_note, ///< caused by a call to built-in instrument script function fade_out()
171 type_note_synth_param, ///< change a note's synthesis parameters (upon real-time instrument script function calls, i.e. change_vol(), change_tune(), change_pan(), etc.)
172 } Type;
173 enum synth_param_t {
174 synth_param_volume,
175 synth_param_volume_time,
176 synth_param_volume_curve,
177 synth_param_pitch,
178 synth_param_pitch_time,
179 synth_param_pitch_curve,
180 synth_param_pan,
181 synth_param_cutoff,
182 synth_param_resonance,
183 synth_param_attack,
184 synth_param_decay,
185 synth_param_release,
186 synth_param_amp_lfo_depth,
187 synth_param_amp_lfo_freq,
188 synth_param_pitch_lfo_depth,
189 synth_param_pitch_lfo_freq,
190 };
191 union {
192 /// Note-on and note-off event specifics
193 struct _Note {
194 uint8_t Channel; ///< MIDI channel (0..15)
195 uint8_t Key; ///< MIDI key number of note-on / note-off event.
196 uint8_t Velocity; ///< Trigger or release velocity of note-on / note-off event.
197 int8_t Layer; ///< Layer index (usually only used if a note-on event has to be postponed, e.g. due to shortage of free voices).
198 int8_t ReleaseTrigger; ///< If new voice should be a release triggered voice (actually boolean field and usually only used if a note-on event has to be postponed, e.g. due to shortage of free voices).
199 note_id_t ID; ///< Unique numeric ID of the @c Note object associated with this note event.
200 note_id_t ParentNoteID; ///< If not zero: Unique numeric ID of the parent @c Note object that shall become parent of resulting new Note object of this Event. So this is used to associate a new note with a previous note, i.e. to release the new note once the parent note was released.
201 void* pRegion; ///< Engine specific pointer to instrument region
202 } Note;
203 /// Control change event specifics
204 struct _CC {
205 uint8_t Channel; ///< MIDI channel (0..15)
206 uint8_t Controller; ///< MIDI controller number of control change event.
207 uint8_t Value; ///< Controller Value of control change event.
208 } CC;
209 /// Pitchbend event specifics
210 struct _Pitch {
211 uint8_t Channel; ///< MIDI channel (0..15)
212 int16_t Pitch; ///< Pitch value of pitchbend event.
213 } Pitch;
214 /// MIDI system exclusive event specifics
215 struct _Sysex {
216 uint Size; ///< Data length (in bytes) of MIDI system exclusive message.
217 } Sysex;
218 /// Channel Pressure (aftertouch) event specifics
219 struct _ChannelPressure {
220 uint8_t Channel; ///< MIDI channel (0..15)
221 uint8_t Controller; ///< Should always be assigned to CTRL_TABLE_IDX_AFTERTOUCH.
222 uint8_t Value; ///< New aftertouch / pressure value for keys on that channel.
223 } ChannelPressure;
224 /// Polyphonic Note Pressure (aftertouch) event specifics
225 struct _NotePressure {
226 uint8_t Channel; ///< MIDI channel (0..15)
227 uint8_t Key; ///< MIDI note number where key pressure (polyphonic aftertouch) changed.
228 uint8_t Value; ///< New pressure value for note.
229 } NotePressure;
230 ///< Note synthesis parameter change event's specifics (used for real-time instrument script built-in functions which may alter synthesis parameters on note level).
231 struct _NoteSynthParam {
232 note_id_t NoteID; ///< ID of Note whose voices shall be modified.
233 synth_param_t Type; ///< Synthesis parameter which is to be changed.
234 float Delta; ///< The value change that should be applied against the note's current synthesis parameter value.
235 bool Relative; ///< Whether @c Delta should be applied relatively against the note's current synthesis parameter value (false means the paramter's current value is simply replaced by Delta).
236 float AbsValue; ///< New current absolute value of synthesis parameter (that is after @c Delta being applied).
237 } NoteSynthParam;
238 } Param;
239 EngineChannel* pEngineChannel; ///< Pointer to the EngineChannel where this event occured on, NULL means Engine global event (e.g. SysEx message).
240 MidiInputPort* pMidiInputPort; ///< Pointer to the MIDI input port on which this event occured (NOTE: currently only for global events, that is SysEx messages)
241
242 inline void Init() {
243 Param.Note.ID = 0;
244 Param.Note.ParentNoteID = 0;
245 Param.NoteSynthParam.NoteID = 0;
246 }
247 inline int32_t FragmentPos() {
248 if (iFragmentPos >= 0) return iFragmentPos;
249 iFragmentPos = pEventGenerator->ToFragmentPos(TimeStamp);
250 if (iFragmentPos < 0) iFragmentPos = 0; // if event arrived shortly before the beginning of current fragment
251 return iFragmentPos;
252 }
253 inline void ResetFragmentPos() {
254 iFragmentPos = -1;
255 }
256 inline void CopyTimeFrom(const Event& other) {
257 TimeStamp = other.TimeStamp;
258 iFragmentPos = other.iFragmentPos;
259 }
260 inline sched_time_t SchedTime() {
261 return pEventGenerator->schedTimeAtCurrentFragmentStart() + FragmentPos();
262 }
263 protected:
264 typedef EventGenerator::time_stamp_t time_stamp_t;
265 Event(EventGenerator* pGenerator, EventGenerator::time_stamp_t Time);
266 Event(EventGenerator* pGenerator, int32_t FragmentPos);
267 friend class EventGenerator;
268 private:
269 EventGenerator* pEventGenerator; ///< Creator of the event.
270 time_stamp_t TimeStamp; ///< Time stamp of the event's occurence.
271 int32_t iFragmentPos; ///< Position in the current fragment this event refers to.
272 };
273
274 /**
275 * Used to sort timing relevant objects (i.e. events) into timing/scheduler
276 * queue. This class is just intended as base class and should be derived
277 * for its actual purpose (for the precise data type being scheduled).
278 */
279 class SchedulerNode : public RTAVLNode {
280 public:
281 using RTAVLNode::reset; // make reset() method public
282
283 sched_time_t scheduleTime; ///< Time ahead in future (in sample points) when this object shall be processed. This value is compared with EventGenerator's uiTotalSamplesProcessed member variable.
284
285 /// Required operator implementation for RTAVLTree class.
286 inline bool operator==(const SchedulerNode& other) const {
287 return this->scheduleTime == other.scheduleTime;
288 }
289
290 /// Required operator implementation for RTAVLTree class.
291 inline bool operator<(const SchedulerNode& other) const {
292 return this->scheduleTime < other.scheduleTime;
293 }
294
295 /// This is actually just for code readability.
296 inline RTAVLTreeBase* currentSchedulerQueue() const { return rtavlTree(); }
297 };
298
299 /**
300 * Used to sort delayed MIDI events into a timing/scheduler queue. This
301 * object just contains the timing informations, the actual MIDI event is
302 * pointed by member variable @c itEvent.
303 */
304 class ScheduledEvent : public SchedulerNode {
305 public:
306 Pool<Event>::Iterator itEvent; ///< Points to the actual Event object being scheduled.
307 };
308
309 class VMEventHandler;
310 class VMExecContext;
311
312 /** @brief Real-time instrument script event.
313 *
314 * Encapsulates one execution instance of a real-time instrument script for
315 * exactly one script event handler (script event callback).
316 *
317 * This class derives from SchedulerNode for being able to be sorted efficiently
318 * by the script scheduler if the script was either a) calling the wait()
319 * script function or b) the script was auto suspended by the ScriptVM
320 * because the script was executing for too long. In both cases the
321 * scheduler has to sort the ScriptEvents in its execution queue according
322 * to the precise time the respective script execution instance needs to be
323 * resumed.
324 */
325 class ScriptEvent : public SchedulerNode {
326 public:
327 Event cause; ///< Copy of original external @c Event that triggered this script event (i.e. MIDI note on event, MIDI CC event, etc.).
328 pool_element_id_t id; ///< Native representation of built-in script variable $EVENT_ID. For scripts' "note" event handler this will reflect the unique ID of the @c Note object, for all other event handlers the unique ID of the original external @c Event object that triggered this script event.
329 VMEventHandler** handlers; ///< The script's event handlers (callbacks) to be processed (NULL terminated list).
330 VMExecContext* execCtx; ///< Script's current execution state (polyphonic variables and execution stack).
331 int currentHandler; ///< Current index in 'handlers' list above.
332 int executionSlices; ///< Amount of times this script event has been executed by the ScriptVM runner class.
333 bool ignoreAllWaitCalls; ///< If true: calling any built-in wait*() script function should be ignored (this variable may be set with the 2nd argument of built-in script function stop_wait()).
334 VMEventHandlerType_t handlerType; ///< Native representation of built-in script variable $NI_CALLBACK_TYPE, reflecting the script event type of this script event.
335 };
336
337 /**
338 * Insert given @a node into the supplied timing @a queue with a scheduled
339 * timing position given by @a fragmentPosBase and @a microseconds, where
340 * @a microseconds reflects the amount of microseconds in future from "now"
341 * where the node shall be scheduled, and @a fragmentPos identifies the
342 * sample point within the current audio fragment cycle which shall be
343 * interpreted by this method to be "now".
344 *
345 * The meaning of @a fragmentPosBase becomes more important the larger
346 * the audio fragment size, and vice versa it bcomes less important the
347 * smaller the audio fragment size.
348 *
349 * @param queue - destination scheduler queue
350 * @param node - node (i.e. event) to be inserted into the queue
351 * @param fragmentPosBase - sample point in current audio fragment to be "now"
352 * @param microseconds - timing of node from "now" (in microseconds)
353 */
354 template<typename T>
355 void EventGenerator::scheduleAheadMicroSec(RTAVLTree<T>& queue, T& node, int32_t fragmentPosBase, uint64_t microseconds) {
356 // round up (+1) if microseconds is not zero (i.e. because 44.1 kHz and
357 // 1 us would yield in < 1 and thus would be offset == 0)
358 const sched_time_t offset =
359 (microseconds != 0LL) ?
360 1.f + (float(uiSampleRate) * (float(microseconds) / 1000000.f))
361 : 0.f;
362 node.scheduleTime = uiTotalSamplesProcessed + fragmentPosBase + offset;
363 queue.insert(node);
364 }
365
366 } // namespace LinuxSampler
367
368 #endif // __LS_EVENT_H__

  ViewVC Help
Powered by ViewVC