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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 244 by schoenebeck, Fri Sep 17 01:01:11 2004 UTC revision 3316 by schoenebeck, Thu Jul 20 12:05:53 2017 UTC
# Line 3  Line 3 
3   *   LinuxSampler - modular, streaming capable sampler                     *   *   LinuxSampler - modular, streaming capable sampler                     *
4   *                                                                         *   *                                                                         *
5   *   Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck   *   *   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  *   *   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  *   *   it under the terms of the GNU General Public License as published by  *
# Line 24  Line 25 
25  #define __LS_EVENT_H__  #define __LS_EVENT_H__
26    
27  #include "../../common/global.h"  #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 {  namespace LinuxSampler {
35    
36      // just symbol prototyping      // just symbol prototyping
37      class Event;      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       * Generates Event objects and is responsible for resolving the position
# Line 38  namespace LinuxSampler { Line 58  namespace LinuxSampler {
58          public:          public:
59              EventGenerator(uint SampleRate);              EventGenerator(uint SampleRate);
60              void UpdateFragmentTime(uint SamplesToProcess);              void UpdateFragmentTime(uint SamplesToProcess);
61                void SetSampleRate(uint SampleRate);
62              Event CreateEvent();              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:          protected:
88              typedef uint32_t time_stamp_t; ///< We read the processor's cycle count register as a reference for the real time. These are of course only abstract values with arbitrary time entity, but that's not a problem as we calculate relatively.              typedef RTMath::time_stamp_t time_stamp_t;
89              inline uint ToFragmentPos(time_stamp_t TimeStamp) {              inline int32_t ToFragmentPos(time_stamp_t TimeStamp) {
90                  return uint ((TimeStamp - FragmentTime.begin) * FragmentTime.sample_ratio);                  return int32_t (int32_t(TimeStamp - FragmentTime.begin) * FragmentTime.sample_ratio);
91              }              }
92              friend class Event;              friend class Event;
93          private:          private:
# Line 53  namespace LinuxSampler { Line 98  namespace LinuxSampler {
98                  time_stamp_t end;          ///< Real time stamp of the end of this audio fragment cycle.                  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)                  float        sample_ratio; ///< (Samples per cycle) / (Real time duration of cycle)
100              } FragmentTime;              } FragmentTime;
101              time_stamp_t CreateTimeStamp();              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       * Events are usually caused by a MIDI source or an internal modulation
149       * controller like LFO or EG. An event can only be created by an       * controller like LFO or EG. An event should only be created by an
150       * EventGenerator.       * EventGenerator!
151       *       *
152       * @see EventGenerator       * @see EventGenerator, ScriptEvent
153       */       */
154      class Event {      class Event {
155          public:          public:
156              Event(){}              Event(){}
157              enum type_t {              enum type_t {
158                  type_note_on,                  type_note_on, ///< (real) MIDI note-on event
159                  type_note_off,                  type_note_off, ///< (real) MIDI note-off event
160                  type_pitchbend,                  type_pitchbend, ///< MIDI pitch bend wheel change event
161                  type_control_change,                  type_control_change, ///< MIDI CC event
162                  type_sysex,           ///< MIDI system exclusive message                  type_sysex,           ///< MIDI system exclusive message
163                  type_cancel_release,  ///< transformed either from a note-on or sustain-pedal-down event                  type_cancel_release_key, ///< transformed either from a (real) MIDI note-on or sustain-pedal-down event
164                  type_release          ///< transformed either from a note-off or sustain-pedal-up event                  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;              } Type;
173              enum destination_t {              enum synth_param_t {
174                  destination_vca,   ///< Volume level                  synth_param_volume,
175                  destination_vco,   ///< Pitch depth                  synth_param_volume_time,
176                  destination_vcfc,  ///< Filter curoff frequency                  synth_param_volume_curve,
177                  destination_vcfr,  ///< Filter resonance                  synth_param_pitch,
178                  destination_count  ///< Total number of modulation destinations (this has to stay the last element in the enum)                  synth_param_pitch_time,
179              };                  synth_param_pitch_curve,
180              union {                  synth_param_pan,
181                  uint8_t Key;          ///< MIDI key number for note-on and note-off events.                  synth_param_cutoff,
182                  uint8_t Controller;   ///< MIDI controller number for control change events.                  synth_param_resonance,
183              };                  synth_param_attack,
184              union {                  synth_param_decay,
185                  uint8_t Velocity;     ///< Trigger or release velocity for note-on or note-off events.                  synth_param_sustain,
186                  uint8_t Value;        ///< Value for control change events.                  synth_param_release,
187                    synth_param_amp_lfo_depth,
188                    synth_param_amp_lfo_freq,
189                    synth_param_pitch_lfo_depth,
190                    synth_param_pitch_lfo_freq,
191              };              };
192              union {              union {
193                  int16_t Pitch;        ///< Pitch value for pitchbend events.                  /// Note-on and note-off event specifics
194                  uint    Size;         ///< Data length (in bytes) for MIDI system exclusive messages.                  struct _Note {
195              };                      uint8_t Channel;     ///< MIDI channel (0..15)
196                        uint8_t Key;         ///< MIDI key number of note-on / note-off event.
197                        uint8_t Velocity;    ///< Trigger or release velocity of note-on / note-off event.
198                        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).
199                        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).
200                        note_id_t ID;        ///< Unique numeric ID of the @c Note object associated with this note event.
201                        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.
202                        void*   pRegion;     ///< Engine specific pointer to instrument region
203                    } Note;
204                    /// Control change event specifics
205                    struct _CC {
206                        uint8_t Channel;     ///< MIDI channel (0..15)
207                        uint8_t Controller;  ///< MIDI controller number of control change event.
208                        uint8_t Value;       ///< Controller Value of control change event.
209                    } CC;
210                    /// Pitchbend event specifics
211                    struct _Pitch {
212                        uint8_t Channel;     ///< MIDI channel (0..15)
213                        int16_t Pitch;       ///< Pitch value of pitchbend event.
214                    } Pitch;
215                    /// MIDI system exclusive event specifics
216                    struct _Sysex {
217                        uint Size;           ///< Data length (in bytes) of MIDI system exclusive message.
218                    } Sysex;
219                    /// Channel Pressure (aftertouch) event specifics
220                    struct _ChannelPressure {
221                        uint8_t Channel; ///< MIDI channel (0..15)
222                        uint8_t Controller; ///< Should always be assigned to CTRL_TABLE_IDX_AFTERTOUCH.
223                        uint8_t Value;   ///< New aftertouch / pressure value for keys on that channel.
224                    } ChannelPressure;
225                    /// Polyphonic Note Pressure (aftertouch) event specifics
226                    struct _NotePressure {
227                        uint8_t Channel; ///< MIDI channel (0..15)
228                        uint8_t Key;     ///< MIDI note number where key pressure (polyphonic aftertouch) changed.
229                        uint8_t Value;   ///< New pressure value for note.
230                    } NotePressure;
231                    ///< Note synthesis parameter change event's specifics (used for real-time instrument script built-in functions which may alter synthesis parameters on note level).
232                    struct _NoteSynthParam {
233                        note_id_t     NoteID;   ///< ID of Note whose voices shall be modified.
234                        synth_param_t Type;     ///< Synthesis parameter which is to be changed.
235                        float         Delta;    ///< The value change that should be applied against the note's current synthesis parameter value.
236                        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).
237                        float         AbsValue; ///< New current absolute value of synthesis parameter (that is after @c Delta being applied).
238                    } NoteSynthParam;
239                } Param;
240                EngineChannel* pEngineChannel; ///< Pointer to the EngineChannel where this event occured on, NULL means Engine global event (e.g. SysEx message).
241                MidiInputPort* pMidiInputPort; ///< Pointer to the MIDI input port on which this event occured (NOTE: currently only for global events, that is SysEx messages)
242    
243              inline uint FragmentPos() {              inline void Init() {
244                  if (iFragmentPos >= 0) return (uint) iFragmentPos;                  Param.Note.ID = 0;
245                  return (uint) (iFragmentPos = pEventGenerator->ToFragmentPos(TimeStamp));                  Param.Note.ParentNoteID = 0;
246                    Param.NoteSynthParam.NoteID = 0;
247                }
248                inline int32_t FragmentPos() {
249                    if (iFragmentPos >= 0) return iFragmentPos;
250                    iFragmentPos = pEventGenerator->ToFragmentPos(TimeStamp);
251                    if (iFragmentPos < 0) iFragmentPos = 0; // if event arrived shortly before the beginning of current fragment
252                    return iFragmentPos;
253                }
254                inline void ResetFragmentPos() {
255                    iFragmentPos = -1;
256                }
257                inline void CopyTimeFrom(const Event& other) {
258                    TimeStamp = other.TimeStamp;
259                    iFragmentPos = other.iFragmentPos;
260                }
261                inline sched_time_t SchedTime() {
262                    return pEventGenerator->schedTimeAtCurrentFragmentStart() + FragmentPos();
263              }              }
264          protected:          protected:
265              typedef EventGenerator::time_stamp_t time_stamp_t;              typedef EventGenerator::time_stamp_t time_stamp_t;
266              Event(EventGenerator* pGenerator, EventGenerator::time_stamp_t Time);              Event(EventGenerator* pGenerator, EventGenerator::time_stamp_t Time);
267                Event(EventGenerator* pGenerator, int32_t FragmentPos);
268              friend class EventGenerator;              friend class EventGenerator;
269          private:          private:
270              EventGenerator* pEventGenerator; ///< Creator of the event.              EventGenerator* pEventGenerator; ///< Creator of the event.
271              time_stamp_t    TimeStamp;       ///< Time stamp of the event's occurence.              time_stamp_t    TimeStamp;       ///< Time stamp of the event's occurence.
272              int             iFragmentPos;    ///< Position in the current fragment this event refers to.              int32_t         iFragmentPos;    ///< Position in the current fragment this event refers to.
273        };
274    
275        /**
276         * Used to sort timing relevant objects (i.e. events) into timing/scheduler
277         * queue. This class is just intended as base class and should be derived
278         * for its actual purpose (for the precise data type being scheduled).
279         */
280        class SchedulerNode : public RTAVLNode {
281        public:
282            using RTAVLNode::reset; // make reset() method public
283    
284            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.
285    
286            /// Required operator implementation for RTAVLTree class.
287            inline bool operator==(const SchedulerNode& other) const {
288                return this->scheduleTime == other.scheduleTime;
289            }
290    
291            /// Required operator implementation for RTAVLTree class.
292            inline bool operator<(const SchedulerNode& other) const {
293                return this->scheduleTime < other.scheduleTime;
294            }
295    
296            /// This is actually just for code readability.
297            inline RTAVLTreeBase* currentSchedulerQueue() const { return rtavlTree(); }
298        };
299    
300        /**
301         * Used to sort delayed MIDI events into a timing/scheduler queue. This
302         * object just contains the timing informations, the actual MIDI event is
303         * pointed by member variable @c itEvent.
304         */
305        class ScheduledEvent : public SchedulerNode {
306        public:
307            Pool<Event>::Iterator itEvent; ///< Points to the actual Event object being scheduled.
308        };
309    
310        class VMEventHandler;
311        class VMExecContext;
312    
313        /**
314         * Maximum amount of child script handler instances one script handler is
315         * allowed to create by calling built-in script function fork().
316         */
317        #define MAX_FORK_PER_SCRIPT_HANDLER 8
318    
319        /** @brief Real-time instrument script event.
320         *
321         * Encapsulates one execution instance of a real-time instrument script for
322         * exactly one script event handler (script event callback).
323         *
324         * This class derives from SchedulerNode for being able to be sorted efficiently
325         * by the script scheduler if the script was either a) calling the wait()
326         * script function or b) the script was auto suspended by the ScriptVM
327         * because the script was executing for too long. In both cases the
328         * scheduler has to sort the ScriptEvents in its execution queue according
329         * to the precise time the respective script execution instance needs to be
330         * resumed.
331         */
332        class ScriptEvent : public SchedulerNode {
333        public:
334            Event cause; ///< Copy of original external @c Event that triggered this script event (i.e. MIDI note on event, MIDI CC event, etc.).
335            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.
336            VMEventHandler** handlers; ///< The script's event handlers (callbacks) to be processed (NULL terminated list).
337            VMExecContext* execCtx; ///< Script's current execution state (polyphonic variables and execution stack).
338            int currentHandler; ///< Current index in 'handlers' list above.
339            int executionSlices; ///< Amount of times this script event has been executed by the ScriptVM runner class.
340            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()).
341            VMEventHandlerType_t handlerType; ///< Native representation of built-in script variable $NI_CALLBACK_TYPE, reflecting the script event type of this script event.
342            script_callback_id_t parentHandlerID; ///< Only in case this script handler instance was created by calling built-in script function fork(): callback ID of the parent event handler instance which created this child. For regular event handler instances which were not created by fork(), this variable reflects 0 (which is always considered an invalid handler ID).
343            script_callback_id_t childHandlerID[MAX_FORK_PER_SCRIPT_HANDLER+1]; ///< In case built-in script function fork() was called by this script handler instance: A zero terminated ID list of all child event handler instances (note: children will not vanish from this list after they terminated).
344            bool autoAbortByParent; ///< Only if this is a child event handler created by calling fork(): if this is true then this child will automatically aborted if the parent event handler terminates.
345            int forkIndex; ///< Only for fork() calls: distinguishment feature which is 0 for parent, 1 for 1st child, 2 for 2nd child, etc.
346    
347            void forkTo(ScriptEvent* e, bool bAutoAbort) const;
348            int countChildHandlers() const;
349            void addChildHandlerID(script_callback_id_t childID);
350      };      };
351    
352        /**
353         * Insert given @a node into the supplied timing @a queue with a scheduled
354         * timing position given by @a fragmentPosBase and @a microseconds, where
355         * @a microseconds reflects the amount of microseconds in future from "now"
356         * where the node shall be scheduled, and @a fragmentPos identifies the
357         * sample point within the current audio fragment cycle which shall be
358         * interpreted by this method to be "now".
359         *
360         * The meaning of @a fragmentPosBase becomes more important the larger
361         * the audio fragment size, and vice versa it becomes less important the
362         * smaller the audio fragment size.
363         *
364         * @param queue - destination scheduler queue
365         * @param node - node (i.e. event) to be inserted into the queue
366         * @param fragmentPosBase - sample point in current audio fragment to be "now"
367         * @param microseconds - timing of node from "now" (in microseconds)
368         */
369        template<typename T>
370        void EventGenerator::scheduleAheadMicroSec(RTAVLTree<T>& queue, T& node, int32_t fragmentPosBase, uint64_t microseconds) {
371            // round up (+1) if microseconds is not zero (i.e. because 44.1 kHz and
372            // 1 us would yield in < 1 and thus would be offset == 0)
373            const sched_time_t offset =
374                (microseconds != 0LL) ?
375                    1.f + (float(uiSampleRate) * (float(microseconds) / 1000000.f))
376                    : 0.f;
377            node.scheduleTime = uiTotalSamplesProcessed + fragmentPosBase + offset;
378            queue.insert(node);
379        }
380    
381  } // namespace LinuxSampler  } // namespace LinuxSampler
382    
383  #endif // __LS_EVENT_H__  #endif // __LS_EVENT_H__

Legend:
Removed from v.244  
changed lines
  Added in v.3316

  ViewVC Help
Powered by ViewVC