/[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 2879 - (hide annotations) (download) (as text)
Tue Apr 19 14:07:53 2016 UTC (7 years, 11 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 16244 byte(s)
* All engines: Active voices are now internally grouped to "Note" objects,
  instead of being directly assigned to a keyboard key. This allows more
  fine graded processing of voices, which is i.e. required for certain
  instrument script features.
* Built-in script function "play_note()": Added support for passing
  special value -1 for "duration-us" argument, which will cause the
  triggered note to be released once the original note was released.
* Bumped version (2.0.0.svn3).

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 2871 * Copyright (C) 2005 - 2016 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 53
33     namespace LinuxSampler {
34    
35     // just symbol prototyping
36     class Event;
37 schoenebeck 2871 class SchedulerNode;
38     class ScriptEvent;
39     class ScheduledEvent;
40 schoenebeck 53
41     /**
42 schoenebeck 2871 * Data type used to schedule events sample point accurately both within, as
43     * well as beyond the scope of the current audio fragment cycle. The timing
44     * reflected by this data type is consecutively running for a very long
45     * time. Even with a sample rate of 96 kHz a scheduler time of this data
46     * type will not wrap before 6 million years. So in practice such time
47     * stamps are unique and will not repeat (unless the EventGenerator is
48     * reset).
49     */
50     typedef uint64_t sched_time_t;
51    
52     /**
53 schoenebeck 53 * Generates Event objects and is responsible for resolving the position
54     * in the current audio fragment each Event actually belongs to.
55     */
56     class EventGenerator {
57     public:
58     EventGenerator(uint SampleRate);
59     void UpdateFragmentTime(uint SamplesToProcess);
60     Event CreateEvent();
61 schoenebeck 906 Event CreateEvent(int32_t FragmentPos);
62 schoenebeck 2871
63     template<typename T>
64     void scheduleAheadMicroSec(RTAVLTree<T>& queue, T& node, int32_t fragmentPosBase, uint64_t microseconds);
65    
66     RTList<ScheduledEvent>::Iterator popNextScheduledEvent(RTAVLTree<ScheduledEvent>& queue, Pool<ScheduledEvent>& pool, sched_time_t end);
67     RTList<ScriptEvent>::Iterator popNextScheduledScriptEvent(RTAVLTree<ScriptEvent>& queue, Pool<ScriptEvent>& pool, sched_time_t end);
68    
69     /**
70     * Returns the scheduler time for the first sample point of the next
71     * audio fragment cycle.
72     */
73     sched_time_t schedTimeAtCurrentFragmentEnd() const {
74     return uiTotalSamplesProcessed + uiSamplesProcessed;
75     }
76    
77 schoenebeck 53 protected:
78 schoenebeck 328 typedef RTMath::time_stamp_t time_stamp_t;
79 schoenebeck 293 inline int32_t ToFragmentPos(time_stamp_t TimeStamp) {
80     return int32_t (int32_t(TimeStamp - FragmentTime.begin) * FragmentTime.sample_ratio);
81 schoenebeck 53 }
82     friend class Event;
83     private:
84     uint uiSampleRate;
85     uint uiSamplesProcessed;
86     struct __FragmentTime__ {
87     time_stamp_t begin; ///< Real time stamp of the beginning of this audio fragment cycle.
88     time_stamp_t end; ///< Real time stamp of the end of this audio fragment cycle.
89     float sample_ratio; ///< (Samples per cycle) / (Real time duration of cycle)
90     } FragmentTime;
91 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).
92 schoenebeck 53 };
93    
94     /**
95 schoenebeck 2879 * Unique numeric ID of an event which can be used to retrieve access to
96     * the actual @c Event object. Once the event associated with a certain ID
97     * was released (back to its event pool), this numeric ID becomes invalid
98     * and Pool< Event >::fromID() will detect this circumstance and will
99     * return an invalid Iterator, and thus will prevent you from misusing an
100     * event which no longer "exists".
101     *
102     * Note that an @c Event object usually just "exists" for exactly on audio
103     * fragment cycle: that is it exists right from the beginning of the audio
104     * fragment cycle where it was caused (i.e. where its MIDI data was
105     * received by the respective engine channel) and will disappear
106     * automatically at the end of that audio fragment cycle.
107     */
108     typedef pool_element_id_t event_id_t;
109    
110     /**
111     * Unique numeric ID of a note which can be used to retrieve access to the
112     * actual @c Note object. Once the note associated with a certain ID was
113     * released (back to its note pool), this numeric ID becomes invalid and
114     * Pool< Note >::fromID() will detect this circumstance and will return
115     * an invalid Iterator, and thus will prevent you from misusing a note
116     * which no longer is "alive".
117     *
118     * A @c Note object exists right when the respective MIDI note-on event
119     * was received by the respective engine channel, and remains existent
120     * until the caused note and all its voices were finally freed (which might
121     * even be long time after the respective note-off event was received,
122     * depending on the duration of the voice's release stages etc.).
123     */
124     typedef pool_element_id_t note_id_t;
125    
126     /**
127 schoenebeck 53 * Events are usually caused by a MIDI source or an internal modulation
128 schoenebeck 906 * controller like LFO or EG. An event should only be created by an
129     * EventGenerator!
130 schoenebeck 53 *
131 schoenebeck 2594 * @see EventGenerator, ScriptEvent
132 schoenebeck 53 */
133     class Event {
134     public:
135     Event(){}
136     enum type_t {
137     type_note_on,
138     type_note_off,
139     type_pitchbend,
140     type_control_change,
141 schoenebeck 244 type_sysex, ///< MIDI system exclusive message
142 schoenebeck 53 type_cancel_release, ///< transformed either from a note-on or sustain-pedal-down event
143 schoenebeck 2559 type_release, ///< transformed either from a note-off or sustain-pedal-up event
144     type_channel_pressure, ///< a.k.a. aftertouch
145     type_note_pressure, ///< polyphonic key pressure (aftertouch)
146 schoenebeck 53 } Type;
147     union {
148 schoenebeck 246 /// Note-on and note-off event specifics
149     struct _Note {
150 schoenebeck 2600 uint8_t Channel; ///< MIDI channel (0..15)
151 schoenebeck 246 uint8_t Key; ///< MIDI key number of note-on / note-off event.
152     uint8_t Velocity; ///< Trigger or release velocity of note-on / note-off event.
153 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).
154     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).
155 schoenebeck 2879 note_id_t ID; ///< Unique numeric ID of the @c Note object associated with this note (on) event.
156     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.
157 persson 2101 void* pRegion; ///< Engine specific pointer to instrument region
158 schoenebeck 246 } Note;
159     /// Control change event specifics
160     struct _CC {
161 schoenebeck 2600 uint8_t Channel; ///< MIDI channel (0..15)
162 schoenebeck 246 uint8_t Controller; ///< MIDI controller number of control change event.
163     uint8_t Value; ///< Controller Value of control change event.
164     } CC;
165     /// Pitchbend event specifics
166     struct _Pitch {
167 schoenebeck 2600 uint8_t Channel; ///< MIDI channel (0..15)
168 schoenebeck 246 int16_t Pitch; ///< Pitch value of pitchbend event.
169     } Pitch;
170     /// MIDI system exclusive event specifics
171     struct _Sysex {
172     uint Size; ///< Data length (in bytes) of MIDI system exclusive message.
173     } Sysex;
174 schoenebeck 2559 /// Channel Pressure (aftertouch) event specifics
175     struct _ChannelPressure {
176 schoenebeck 2600 uint8_t Channel; ///< MIDI channel (0..15)
177 schoenebeck 2611 uint8_t Controller; ///< Should always be assigned to CTRL_TABLE_IDX_AFTERTOUCH.
178 schoenebeck 2559 uint8_t Value; ///< New aftertouch / pressure value for keys on that channel.
179     } ChannelPressure;
180     /// Polyphonic Note Pressure (aftertouch) event specifics
181     struct _NotePressure {
182 schoenebeck 2600 uint8_t Channel; ///< MIDI channel (0..15)
183 schoenebeck 2559 uint8_t Key; ///< MIDI note number where key pressure (polyphonic aftertouch) changed.
184     uint8_t Value; ///< New pressure value for note.
185     } NotePressure;
186 schoenebeck 246 } Param;
187 schoenebeck 412 EngineChannel* pEngineChannel; ///< Pointer to the EngineChannel where this event occured on, NULL means Engine global event (e.g. SysEx message).
188 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)
189 schoenebeck 53
190 schoenebeck 2879 inline void Init() {
191     Param.Note.ID = 0;
192     Param.Note.ParentNoteID = 0;
193     }
194 schoenebeck 293 inline int32_t FragmentPos() {
195     if (iFragmentPos >= 0) return iFragmentPos;
196     iFragmentPos = pEventGenerator->ToFragmentPos(TimeStamp);
197     if (iFragmentPos < 0) iFragmentPos = 0; // if event arrived shortly before the beginning of current fragment
198     return iFragmentPos;
199 schoenebeck 53 }
200 schoenebeck 293 inline void ResetFragmentPos() {
201     iFragmentPos = -1;
202     }
203 schoenebeck 2879 inline void CopyTimeFrom(const Event& other) {
204     TimeStamp = other.TimeStamp;
205     iFragmentPos = other.iFragmentPos;
206     }
207 schoenebeck 53 protected:
208     typedef EventGenerator::time_stamp_t time_stamp_t;
209     Event(EventGenerator* pGenerator, EventGenerator::time_stamp_t Time);
210 schoenebeck 906 Event(EventGenerator* pGenerator, int32_t FragmentPos);
211 schoenebeck 53 friend class EventGenerator;
212     private:
213     EventGenerator* pEventGenerator; ///< Creator of the event.
214     time_stamp_t TimeStamp; ///< Time stamp of the event's occurence.
215 schoenebeck 293 int32_t iFragmentPos; ///< Position in the current fragment this event refers to.
216 schoenebeck 53 };
217    
218 schoenebeck 2871 /**
219     * Used to sort timing relevant objects (i.e. events) into timing/scheduler
220     * queue. This class is just intended as base class and should be derived
221     * for its actual purpose (for the precise data type being scheduled).
222     */
223     class SchedulerNode : public RTAVLNode {
224     public:
225     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.
226    
227     /// Required operator implementation for RTAVLTree class.
228     inline bool operator==(const SchedulerNode& other) const {
229     return this->scheduleTime == other.scheduleTime;
230     }
231    
232     /// Required operator implementation for RTAVLTree class.
233     inline bool operator<(const SchedulerNode& other) const {
234     return this->scheduleTime < other.scheduleTime;
235     }
236     };
237    
238     /**
239     * Used to sort delayed MIDI events into a timing/scheduler queue. This
240     * object just contains the timing informations, the actual MIDI event is
241     * pointed by member variable @c itEvent.
242     */
243     class ScheduledEvent : public SchedulerNode {
244     public:
245     Pool<Event>::Iterator itEvent; ///< Points to the actual Event object being scheduled.
246     };
247    
248 schoenebeck 2594 class VMEventHandler;
249     class VMExecContext;
250    
251     /** @brief Real-time instrument script event.
252     *
253     * Encapsulates one execution instance of a real-time instrument script for
254     * exactly one script event handler (script event callback).
255 schoenebeck 2871 *
256     * This class derives from SchedulerNode for being able to be sorted efficiently
257     * by the script scheduler if the script was either a) calling the wait()
258     * script function or b) the script was auto suspended by the ScriptVM
259     * because the script was executing for too long. In both cases the
260     * scheduler has to sort the ScriptEvents in its execution queue according
261     * to the precise time the respective script execution instance needs to be
262     * resumed.
263 schoenebeck 2594 */
264 schoenebeck 2871 class ScriptEvent : public SchedulerNode {
265 schoenebeck 2594 public:
266 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.).
267     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.
268 schoenebeck 2594 VMEventHandler** handlers; ///< The script's event handlers (callbacks) to be processed (NULL terminated list).
269     VMExecContext* execCtx; ///< Script's current execution state (polyphonic variables and execution stack).
270     int currentHandler; ///< Current index in 'handlers' list above.
271     int executionSlices; ///< Amount of times this script event has been executed by the ScriptVM runner class.
272     };
273    
274 schoenebeck 2871 /**
275     * Insert given @a node into the supplied timing @a queue with a scheduled
276     * timing position given by @a fragmentPosBase and @a microseconds, where
277 schoenebeck 2879 * @a microseconds reflects the amount of microseconds in future from "now"
278 schoenebeck 2871 * where the node shall be scheduled, and @a fragmentPos identifies the
279     * sample point within the current audio fragment cycle which shall be
280     * interpreted by this method to be "now".
281     *
282     * The meaning of @a fragmentPosBase becomes more important the larger
283     * the audio fragment size, and vice versa it bcomes less important the
284     * smaller the audio fragment size.
285     *
286     * @param queue - destination scheduler queue
287     * @param node - node (i.e. event) to be inserted into the queue
288     * @param fragmentPosBase - sample point in current audio fragment to be "now"
289     * @param microseconds - timing of node from "now" (in microseconds)
290     */
291     template<typename T>
292     void EventGenerator::scheduleAheadMicroSec(RTAVLTree<T>& queue, T& node, int32_t fragmentPosBase, uint64_t microseconds) {
293     node.scheduleTime = uiTotalSamplesProcessed + fragmentPosBase + float(uiSampleRate) * (float(microseconds) / 1000000.f);
294     queue.insert(node);
295     }
296    
297 schoenebeck 53 } // namespace LinuxSampler
298    
299     #endif // __LS_EVENT_H__

  ViewVC Help
Powered by ViewVC