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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3118 - (hide annotations) (download) (as text)
Fri Apr 21 13:33:03 2017 UTC (7 years ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 20018 byte(s)
* NKSP: Fixed crash when using built-in script array variable "%ALL_EVENTS".
* NKSP: Added built-in function "change_amp_lfo_depth()".
* NKSP: Added built-in function "change_amp_lfo_freq()".
* NKSP: Added built-in function "change_pitch_lfo_depth()".
* NKSP: Added built-in function "change_pitch_lfo_freq()".
* Bumped version (2.0.0.svn44).

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

  ViewVC Help
Powered by ViewVC