/[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 2871 by schoenebeck, Sun Apr 10 18:22:23 2016 UTC revision 3565 by schoenebeck, Sat Aug 24 11:22:52 2019 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 - 2016 Christian Schoenebeck                       *   *   Copyright (C) 2005 - 2019 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 29  Line 29 
29  #include "../../common/RTAVLTree.h"  #include "../../common/RTAVLTree.h"
30  #include "../../common/Pool.h"  #include "../../common/Pool.h"
31  #include "../EngineChannel.h"  #include "../EngineChannel.h"
32    #include "../../scriptvm/common.h"
33    
34    // On Windows RELATIVE might be defined as macro in wingdi.h, which would
35    // cause a compiler error of the same token used in this header file below.
36    // So we undefine that macro here for now (if present).
37    #ifdef RELATIVE
38    # warning Preprocessor conflict detected: Macro RELATIVE was declared by system headers; undefining it here.
39    # undef RELATIVE
40    #endif
41    
42  namespace LinuxSampler {  namespace LinuxSampler {
43    
# Line 57  namespace LinuxSampler { Line 66  namespace LinuxSampler {
66          public:          public:
67              EventGenerator(uint SampleRate);              EventGenerator(uint SampleRate);
68              void UpdateFragmentTime(uint SamplesToProcess);              void UpdateFragmentTime(uint SamplesToProcess);
69                void SetSampleRate(uint SampleRate);
70              Event CreateEvent();              Event CreateEvent();
71              Event CreateEvent(int32_t FragmentPos);              Event CreateEvent(int32_t FragmentPos);
72    
# Line 67  namespace LinuxSampler { Line 77  namespace LinuxSampler {
77              RTList<ScriptEvent>::Iterator popNextScheduledScriptEvent(RTAVLTree<ScriptEvent>& queue, Pool<ScriptEvent>& pool, sched_time_t end);              RTList<ScriptEvent>::Iterator popNextScheduledScriptEvent(RTAVLTree<ScriptEvent>& queue, Pool<ScriptEvent>& pool, sched_time_t end);
78    
79              /**              /**
80                 * Returns the scheduler time for the first sample point of the
81                 * current audio fragment cycle.
82                 */
83                sched_time_t schedTimeAtCurrentFragmentStart() const {
84                    return uiTotalSamplesProcessed;
85                }
86    
87                /**
88               * Returns the scheduler time for the first sample point of the next               * Returns the scheduler time for the first sample point of the next
89               * audio fragment cycle.               * audio fragment cycle.
90               */               */
# Line 92  namespace LinuxSampler { Line 110  namespace LinuxSampler {
110      };      };
111    
112      /**      /**
113         * Unique numeric ID of an event which can be used to retrieve access to
114         * the actual @c Event object. Once the event associated with a certain ID
115         * was released (back to its event pool), this numeric ID becomes invalid
116         * and Pool< Event >::fromID() will detect this circumstance and will
117         * return an invalid Iterator, and thus will prevent you from misusing an
118         * event which no longer "exists".
119         *
120         * Note that an @c Event object usually just "exists" for exactly on audio
121         * fragment cycle: that is it exists right from the beginning of the audio
122         * fragment cycle where it was caused (i.e. where its MIDI data was
123         * received by the respective engine channel) and will disappear
124         * automatically at the end of that audio fragment cycle.
125         */
126        typedef pool_element_id_t event_id_t;
127    
128        /**
129         * Unique numeric ID of a note which can be used to retrieve access to the
130         * actual @c Note object. Once the note associated with a certain ID was
131         * released (back to its note pool), this numeric ID becomes invalid and
132         * Pool< Note >::fromID() will detect this circumstance and will return
133         * an invalid Iterator, and thus will prevent you from misusing a note
134         * which no longer is "alive".
135         *
136         * A @c Note object exists right when the respective MIDI note-on event
137         * was received by the respective engine channel, and remains existent
138         * until the caused note and all its voices were finally freed (which might
139         * even be long time after the respective note-off event was received,
140         * depending on the duration of the voice's release stages etc.).
141         */
142        typedef pool_element_id_t note_id_t;
143    
144        /**
145         * Unique numeric ID of a script callback ID instance which can be used to
146         * retrieve access to the actual @c ScriptEvent object. Once the script
147         * callback instance associated with a certain ID stopped its execution
148         * (that is completely stopped, not just suspended) then this numeric ID
149         * becomes invalid and Pool< ScriptEvent >::fromID() will detect this
150         * circumstance and will return an invalid Iterator, and thus will prevent
151         * you from misusing a script callback instance which no longer "exists".
152         */
153        typedef pool_element_id_t script_callback_id_t;
154    
155        /**
156       * Events are usually caused by a MIDI source or an internal modulation       * Events are usually caused by a MIDI source or an internal modulation
157       * controller like LFO or EG. An event should only be created by an       * controller like LFO or EG. An event should only be created by an
158       * EventGenerator!       * EventGenerator!
# Line 102  namespace LinuxSampler { Line 163  namespace LinuxSampler {
163          public:          public:
164              Event(){}              Event(){}
165              enum type_t {              enum type_t {
166                  type_note_on,                  type_note_on, ///< (real) MIDI note-on event
167                  type_note_off,                  type_note_off, ///< (real) MIDI note-off event
168                  type_pitchbend,                  type_pitchbend, ///< MIDI pitch bend wheel change event
169                  type_control_change,                  type_control_change, ///< MIDI CC event
170                  type_sysex,           ///< MIDI system exclusive message                  type_sysex,           ///< MIDI system exclusive message
171                  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
172                  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
173                    type_release_note,    ///< transformed from a type_stop_note event
174                  type_channel_pressure, ///< a.k.a. aftertouch                  type_channel_pressure, ///< a.k.a. aftertouch
175                  type_note_pressure, ///< polyphonic key pressure (aftertouch)                  type_note_pressure, ///< polyphonic key pressure (aftertouch)
176                    type_play_note, ///< caused by a call to built-in instrument script function play_note()
177                    type_stop_note, ///< caused by a call to built-in instrument script function note_off()
178                    type_kill_note, ///< caused by a call to built-in instrument script function fade_out()
179                    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.)
180              } Type;              } Type;
181                enum synth_param_t {
182                    synth_param_volume,
183                    synth_param_volume_time,
184                    synth_param_volume_curve,
185                    synth_param_pitch,
186                    synth_param_pitch_time,
187                    synth_param_pitch_curve,
188                    synth_param_pan,
189                    synth_param_pan_time,
190                    synth_param_pan_curve,
191                    synth_param_cutoff,
192                    synth_param_resonance,
193                    synth_param_attack,
194                    synth_param_decay,
195                    synth_param_sustain,
196                    synth_param_release,
197                    synth_param_cutoff_attack,
198                    synth_param_cutoff_decay,
199                    synth_param_cutoff_sustain,
200                    synth_param_cutoff_release,
201                    synth_param_amp_lfo_depth,
202                    synth_param_amp_lfo_freq,
203                    synth_param_cutoff_lfo_depth,
204                    synth_param_cutoff_lfo_freq,
205                    synth_param_pitch_lfo_depth,
206                    synth_param_pitch_lfo_freq,
207                };
208                enum class ValueScope : unsigned char {
209                    /**
210                     * The new synthesis parameter value should be applied
211                     * relatively to itself (as normalized value range), and then
212                     * applied relatively against other sources (i.e. LFOs, EGs)
213                     * for the same synthesis parameter.
214                     */
215                    SELF_RELATIVE = 1,
216                    /**
217                     * The new synthesis paramater value of itself should be
218                     * replaced, and then applied relatively to other sources
219                     * (i.e. LFOs, EGs) for the same synthesis parameter.
220                     */
221                    RELATIVE = 0, //IMPORANT: must remain 0 because of the union structure below which would otherwise i.e. assign invalid pointers/IDs to Param.Note structure in Init()
222                    /**
223                     * The new synthesis parameter value should be applied
224                     * relatively to itself (as normalized value range), and then
225                     * applied directly (as normalized value range) as final value
226                     * of this synthesis chain, thus all other sources (i.e. LFOs,
227                     * EGs) should entirely be ignored.
228                     */
229                    FINAL_SELF_RELATIVE = 2,
230                    /**
231                     * The new synthesis parameter value of itself should be
232                     * replaced, and then applied directly (as normalized value
233                     * range) as final value of this synthesis chain, thus all other
234                     * sources (i.e. LFOs, EGs) should entirely be ignored.
235                     */
236                    FINAL_NORM = 3,
237                    /**
238                     * Same as @c FINAL_NORM, but this one is already in the native
239                     * unit (i.e. seconds, Hz) of this synthesis parameter.
240                     */
241                    FINAL_NATIVE = 4,
242                };
243              union {              union {
244                  /// Note-on and note-off event specifics                  /// Note-on and note-off event specifics
245                  struct _Note {                  struct _Note {
# Line 120  namespace LinuxSampler { Line 248  namespace LinuxSampler {
248                      uint8_t Velocity;    ///< Trigger or release velocity of note-on / note-off event.                      uint8_t Velocity;    ///< Trigger or release velocity of note-on / note-off event.
249                      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).                      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).
250                      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).                      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).
251                        note_id_t ID;        ///< Unique numeric ID of the @c Note object associated with this note event.
252                        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.
253                      void*   pRegion;     ///< Engine specific pointer to instrument region                      void*   pRegion;     ///< Engine specific pointer to instrument region
254                  } Note;                  } Note;
255                  /// Control change event specifics                  /// Control change event specifics
# Line 149  namespace LinuxSampler { Line 279  namespace LinuxSampler {
279                      uint8_t Key;     ///< MIDI note number where key pressure (polyphonic aftertouch) changed.                      uint8_t Key;     ///< MIDI note number where key pressure (polyphonic aftertouch) changed.
280                      uint8_t Value;   ///< New pressure value for note.                      uint8_t Value;   ///< New pressure value for note.
281                  } NotePressure;                  } NotePressure;
282                    ///< Note synthesis parameter change event's specifics (used for real-time instrument script built-in functions which may alter synthesis parameters on note level).
283                    struct _NoteSynthParam {
284                        note_id_t     NoteID;   ///< ID of Note whose voices shall be modified.
285                        synth_param_t Type;     ///< Synthesis parameter which is to be changed.
286                        float         Delta;    ///< The value change that should be applied against the note's current synthesis parameter value.
287                        float         AbsValue; ///< New current absolute value of synthesis parameter (that is after @c Delta being applied).
288                        ValueScope    Scope;    ///< How @c Delta should be applied against @c AbsValue, and how @c AbsValue should then actually be applied to the synthesis chain.
289    
290                        inline bool isFinal() const { return Scope >= ValueScope::FINAL_SELF_RELATIVE; }
291                    } NoteSynthParam;
292              } Param;              } Param;
             /// Sampler format specific informations and variables.  
             union {  
                 /// Gigasampler/GigaStudio format specifics.  
                 struct _Gig {  
                     uint8_t DimMask; ///< May be used to override the Dimension zone to be selected for a new voice: each 1 bit means that respective bit shall be overridden by taking the respective bit from DimBits instead.  
                     uint8_t DimBits; ///< Used only in conjunction with DimMask: Dimension bits that shall be selected.  
                 } Gig;  
             } Format;  
293              EngineChannel* pEngineChannel; ///< Pointer to the EngineChannel where this event occured on, NULL means Engine global event (e.g. SysEx message).              EngineChannel* pEngineChannel; ///< Pointer to the EngineChannel where this event occured on, NULL means Engine global event (e.g. SysEx message).
294              MidiInputPort* pMidiInputPort; ///< Pointer to the MIDI input port on which this event occured (NOTE: currently only for global events, that is SysEx messages)              MidiInputPort* pMidiInputPort; ///< Pointer to the MIDI input port on which this event occured (NOTE: currently only for global events, that is SysEx messages)
295    
296                inline void Init() {
297                    //FIXME: probably we should memset() zero entire structure here, due to potential union initialization conflicts (see comment on ValueScope::RELATIVE)
298                    Param.Note.ID = 0;
299                    Param.Note.ParentNoteID = 0;
300                    Param.NoteSynthParam.NoteID = 0;
301                    Param.NoteSynthParam.Scope = ValueScope::RELATIVE;
302                }
303              inline int32_t FragmentPos() {              inline int32_t FragmentPos() {
304                  if (iFragmentPos >= 0) return iFragmentPos;                  if (iFragmentPos >= 0) return iFragmentPos;
305                  iFragmentPos = pEventGenerator->ToFragmentPos(TimeStamp);                  iFragmentPos = pEventGenerator->ToFragmentPos(TimeStamp);
# Line 170  namespace LinuxSampler { Line 309  namespace LinuxSampler {
309              inline void ResetFragmentPos() {              inline void ResetFragmentPos() {
310                  iFragmentPos = -1;                  iFragmentPos = -1;
311              }              }
312                inline void CopyTimeFrom(const Event& other) {
313                    TimeStamp = other.TimeStamp;
314                    iFragmentPos = other.iFragmentPos;
315                }
316                inline sched_time_t SchedTime() {
317                    return pEventGenerator->schedTimeAtCurrentFragmentStart() + FragmentPos();
318                }
319                inline static ValueScope scopeBy_FinalRelativeUnit(bool bFinal, bool bRelative, bool bNativeUnit) {
320                    if (!bFinal && bRelative)
321                        return ValueScope::SELF_RELATIVE;
322                    if (!bFinal)
323                        return ValueScope::RELATIVE;
324                    if (bRelative)
325                        return ValueScope::FINAL_SELF_RELATIVE;
326                    if (bNativeUnit)
327                        return ValueScope::FINAL_NATIVE;
328                    return ValueScope::FINAL_NORM;
329                }
330          protected:          protected:
331              typedef EventGenerator::time_stamp_t time_stamp_t;              typedef EventGenerator::time_stamp_t time_stamp_t;
332              Event(EventGenerator* pGenerator, EventGenerator::time_stamp_t Time);              Event(EventGenerator* pGenerator, EventGenerator::time_stamp_t Time);
# Line 188  namespace LinuxSampler { Line 345  namespace LinuxSampler {
345       */       */
346      class SchedulerNode : public RTAVLNode {      class SchedulerNode : public RTAVLNode {
347      public:      public:
348            using RTAVLNode::reset; // make reset() method public
349    
350          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.          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.
351    
352          /// Required operator implementation for RTAVLTree class.          /// Required operator implementation for RTAVLTree class.
# Line 199  namespace LinuxSampler { Line 358  namespace LinuxSampler {
358          inline bool operator<(const SchedulerNode& other) const {          inline bool operator<(const SchedulerNode& other) const {
359              return this->scheduleTime < other.scheduleTime;              return this->scheduleTime < other.scheduleTime;
360          }          }
361    
362            /// This is actually just for code readability.
363            inline RTAVLTreeBase* currentSchedulerQueue() const { return rtavlTree(); }
364      };      };
365    
366      /**      /**
# Line 214  namespace LinuxSampler { Line 376  namespace LinuxSampler {
376      class VMEventHandler;      class VMEventHandler;
377      class VMExecContext;      class VMExecContext;
378    
379        /**
380         * Maximum amount of child script handler instances one script handler is
381         * allowed to create by calling built-in script function fork().
382         */
383        #define MAX_FORK_PER_SCRIPT_HANDLER 8
384    
385      /** @brief Real-time instrument script event.      /** @brief Real-time instrument script event.
386       *       *
387       * Encapsulates one execution instance of a real-time instrument script for       * Encapsulates one execution instance of a real-time instrument script for
# Line 229  namespace LinuxSampler { Line 397  namespace LinuxSampler {
397       */       */
398      class ScriptEvent : public SchedulerNode {      class ScriptEvent : public SchedulerNode {
399      public:      public:
400          Event cause; ///< Original external event that triggered this script event (i.e. MIDI note on event, MIDI CC event, etc.).          Event cause; ///< Copy of original external @c Event that triggered this script event (i.e. MIDI note on event, MIDI CC event, etc.).
401          int id; ///< Unique ID of the external event that triggered this script event.          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.
402          VMEventHandler** handlers; ///< The script's event handlers (callbacks) to be processed (NULL terminated list).          VMEventHandler** handlers; ///< The script's event handlers (callbacks) to be processed (NULL terminated list).
403          VMExecContext* execCtx; ///< Script's current execution state (polyphonic variables and execution stack).          VMExecContext* execCtx; ///< Script's current execution state (polyphonic variables and execution stack).
404          int currentHandler; ///< Current index in 'handlers' list above.          int currentHandler; ///< Current index in 'handlers' list above.
405          int executionSlices; ///< Amount of times this script event has been executed by the ScriptVM runner class.          int executionSlices; ///< Amount of times this script event has been executed by the ScriptVM runner class.
406            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()).
407            VMEventHandlerType_t handlerType; ///< Native representation of built-in script variable $NI_CALLBACK_TYPE, reflecting the script event type of this script event.
408            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).
409            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).
410            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.
411            int forkIndex; ///< Only for fork() calls: distinguishment feature which is 0 for parent, 1 for 1st child, 2 for 2nd child, etc.
412    
413            void forkTo(ScriptEvent* e, bool bAutoAbort) const;
414            int countChildHandlers() const;
415            void addChildHandlerID(script_callback_id_t childID);
416      };      };
417    
418      /**      /**
419       * Insert given @a node into the supplied timing @a queue with a scheduled       * Insert given @a node into the supplied timing @a queue with a scheduled
420       * timing position given by @a fragmentPosBase and @a microseconds, where       * timing position given by @a fragmentPosBase and @a microseconds, where
421       * @a microseconds reflects the amount microseconds in future from "now"       * @a microseconds reflects the amount of microseconds in future from "now"
422       * where the node shall be scheduled, and @a fragmentPos identifies the       * where the node shall be scheduled, and @a fragmentPos identifies the
423       * sample point within the current audio fragment cycle which shall be       * sample point within the current audio fragment cycle which shall be
424       * interpreted by this method to be "now".       * interpreted by this method to be "now".
425       *       *
426       * The meaning of @a fragmentPosBase becomes more important the larger       * The meaning of @a fragmentPosBase becomes more important the larger
427       * the audio fragment size, and vice versa it bcomes less important the       * the audio fragment size, and vice versa it becomes less important the
428       * smaller the audio fragment size.       * smaller the audio fragment size.
429       *       *
430       * @param queue - destination scheduler queue       * @param queue - destination scheduler queue
# Line 256  namespace LinuxSampler { Line 434  namespace LinuxSampler {
434       */       */
435      template<typename T>      template<typename T>
436      void EventGenerator::scheduleAheadMicroSec(RTAVLTree<T>& queue, T& node, int32_t fragmentPosBase, uint64_t microseconds) {      void EventGenerator::scheduleAheadMicroSec(RTAVLTree<T>& queue, T& node, int32_t fragmentPosBase, uint64_t microseconds) {
437          node.scheduleTime = uiTotalSamplesProcessed + fragmentPosBase + float(uiSampleRate) * (float(microseconds) / 1000000.f);          // round up (+1) if microseconds is not zero (i.e. because 44.1 kHz and
438            // 1 us would yield in < 1 and thus would be offset == 0)
439            const sched_time_t offset =
440                (microseconds != 0LL) ?
441                    1.f + (float(uiSampleRate) * (float(microseconds) / 1000000.f))
442                    : 0.f;
443            node.scheduleTime = uiTotalSamplesProcessed + fragmentPosBase + offset;
444          queue.insert(node);          queue.insert(node);
445      }      }
446    

Legend:
Removed from v.2871  
changed lines
  Added in v.3565

  ViewVC Help
Powered by ViewVC