1 /*
2  * Hydrogen
3  * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4  *
5  * http://www.hydrogen-music.org
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY, without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22 
23 #ifndef EVENT_QUEUE_H
24 #define EVENT_QUEUE_H
25 
26 #include <hydrogen/object.h>
27 #include <hydrogen/basics/note.h>
28 #include <cassert>
29 
30 /** Maximum number of events to be stored in the
31     H2Core::EventQueue::__events_buffer.*/
32 #define MAX_EVENTS 1024
33 
34 namespace H2Core
35 {
36 
37 /** Basic types of communication between the core part of Hydrogen and
38     its GUI.*/
39 enum EventType {
40 	/** Fallback event*/
41 	EVENT_NONE,
42 	EVENT_STATE,
43 	/** The current pattern changed during the processing of the
44 	 * AudioEngine with respect to the previous process cycle.
45 	 *
46 	 * It is handled by EventListener::patternChangedEvent().
47 	 */
48 	EVENT_PATTERN_CHANGED,
49 	EVENT_PATTERN_MODIFIED,
50 	/** Another pattern was selected via MIDI or the GUI without
51 	 * affecting the audio transport (e.g in Song::PATTERN_MODE when
52 	 * Preferences::m_bPatternModePlaysSelected is set to true). While
53 	 * the selection in the former case already happens in the GUI,
54 	 * this event will be used to tell it the selection was successful
55 	 * and had been done.
56 	 *
57 	 * Handled by EventListener::selectedPatternChangedEvent().
58 	 */
59 	EVENT_SELECTED_PATTERN_CHANGED,
60 	EVENT_SELECTED_INSTRUMENT_CHANGED,
61 	EVENT_PARAMETERS_INSTRUMENT_CHANGED,
62 	EVENT_MIDI_ACTIVITY,
63 	EVENT_XRUN,
64 	EVENT_NOTEON,
65 	EVENT_ERROR,
66 	/** Event indicating the triggering of the
67 	 * #m_pMetronomeInstrument.
68 	 *
69 	 * In audioEngine_updateNoteQueue() the pushing of this Event is
70 	 * decoupled from the creation and queuing of the corresponding
71 	 * Note itself.
72 	 *
73 	 * In Director it triggers a change in the displayed number,
74 	 * color, tag, and triggers Director::update(). In case the
75 	 * provided value is 3, instead of performing the changes above,
76 	 * the Director loads the metadata a the current Song.
77 	 *
78 	 * The associated values do correspond to the following actions:
79 	 * - 0: Beat at the beginning of a Pattern in
80 	 *      audioEngine_updateNoteQueue(). The corresponding Note will
81 	 *      be created with a pitch of 3 and velocity of 1.0.
82 	 *      Sets MetronomeWidget::m_state to
83 	 *      MetronomeWidget::METRO_ON and triggers
84 	 *      MetronomeWidget::updateWidget().
85 	 * - 1: Beat in the remainder of a Pattern in
86 	 *      audioEngine_updateNoteQueue(). The corresponding Note will
87 	 *      be created with a pitch of 0 and velocity of 0.8. In
88 	 *      addition, it will be also pushed by
89 	 *      Hydrogen::setPatternPos() without creating a Note.
90 	 *      Sets MetronomeWidget::m_state to
91 	 *      MetronomeWidget::METRO_FIRST and triggers
92 	 *      MetronomeWidget::updateWidget().
93 	 * - 2: Signals MetronomeWidget to neither update nor setting
94 	 *      MetronomeWidget::m_state.
95 	 * - 3: Tells the Director that a new Song was loaded and triggers
96 	 *      its Director::update().
97 	 *      Sets MetronomeWidget::m_state to
98 	 *      MetronomeWidget::METRO_ON and triggers
99 	 *      MetronomeWidget::updateWidget().
100 	 *
101 	 * Handled by EventListener::metronomeEvent().
102 	 */
103 	EVENT_METRONOME,
104 	EVENT_RECALCULATERUBBERBAND,
105 	EVENT_PROGRESS,
106 	EVENT_JACK_SESSION,
107 	EVENT_PLAYLIST_LOADSONG,
108 	EVENT_UNDO_REDO,
109 	EVENT_SONG_MODIFIED,
110 	EVENT_TEMPO_CHANGED,
111 	/**
112 	 * Event triggering HydrogenApp::updateSongEvent() whenever the
113 	 * Song was changed outside of the GUI, e.g. by session management
114 	 * or and OSC command.
115 	 *
116 	 * If the value of the event is
117 	 * - 0 - Hydrogen::m_pNextSong will be loaded.
118 	 * - 1 - triggered whenever the #Song was saved via the core part
119 	 *       (updated the title and status bar).
120 	 */
121 	EVENT_UPDATE_SONG,
122 	/**
123 	 * Triggering HydrogenApp::quitEvent() and enables a shutdown of
124 	 * the entire application via the command line.
125 	 */
126 	EVENT_QUIT
127 };
128 
129 /** Basic building block for the communication between the core of
130  * Hydrogen and its GUI.  The individual Events will be enlisted in
131  * the EventQueue singleton.*/
132 class Event
133 {
134 public:
135 	/** Specifies the context the event is create in and which
136 	    function should be triggered to handle it.*/
137 	EventType type;
138 	/** Additional information to describe the actual context of
139 	    the engine.*/
140 	int value;
141 };
142 
143 /** Object handling the communication between the core of Hydrogen and
144  * its GUI.
145  *
146  * Whenever a specific condition is met or occasion happens within the
147  * core part of Hydrogen (its engine), an Event will be added to the
148  * EventQueue singleton. The GUI checks the content of this queue on a
149  * regular basis using HydrogenApp::onEventQueueTimer(). The actual
150  * frequency is set in the constructor HydrogenApp::HydrogenApp() to
151  * 20 times per second. Now, whenever an Event of a certain EventType
152  * is encountered, the corresponding function in the EventListener
153  * will be invoked to respond to the condition of the engine. For
154  * details about the mapping of EventTypes to functions please see the
155  * documentation of HydrogenApp::onEventQueueTimer().*/
156 class EventQueue : public H2Core::Object
157 {
158 	H2_OBJECT
159 public:/**
160 	* If #__instance equals 0, a new EventQueue singleton will be
161 	 * created and stored in it.
162 	 *
163 	 * It is called in Hydrogen::create_instance().
164 	 */
165 	static void create_instance();
166 	/**
167 	 * Returns a pointer to the current EventQueue singleton
168 	 * stored in #__instance.
169 	 */
get_instance()170 	static EventQueue* get_instance() { assert(__instance); return __instance; }
171 	~EventQueue();
172 
173 	/**
174 	 * Queues the next event into the EventQueue.
175 	 *
176 	 * The event itself will be constructed inside the function
177 	 * and will be two properties: an EventType @a type and a
178 	 * value @a nValue. Since the event written to the queue most
179 	 * recently is indexed with #__write_index, this variable is
180 	 * incremented once and its modulo with respect to #MAX_EVENTS
181 	 * is calculated to determine the position of insertion into
182 	 * #__events_buffer.
183 	 *
184 	 * The modulo operation is necessary because #__write_index
185 	 * will be only incremented and does not respect the actual
186 	 * length of #__events_buffer itself.
187 	 *
188 	 * \param type Type of the event, which will be queued.
189 	 * \param nValue Value specifying the content of the new event.
190 	 */
191 	void push_event( const EventType type, const int nValue );
192 	/**
193 	 * Reads out the next event of the EventQueue.
194 	 *
195 	 * Since the event read out most recently is indexed with
196 	 * #__read_index, this variable is incremented once and its
197 	 * modulo with respect to #MAX_EVENTS is calculated to
198 	 * determine the event returned from #__events_buffer.
199 	 *
200 	 * The modulo operation is necessary because #__read_index
201 	 * will be only incremented and does not respect the actual
202 	 * length of #__events_buffer itself.
203 	 *
204 	 * \return Next event in line.
205 	 */
206 	Event pop_event();
207 
208 	struct AddMidiNoteVector {
209 		int m_column;       //position
210 		int m_row;          //instrument row
211 		int m_pattern;      // pattern number
212 		int m_length;
213 		float f_velocity;
214 		float f_pan_L;
215 		float f_pan_R;
216 		Note::Key nk_noteKeyVal;
217 		Note::Octave no_octaveKeyVal;
218 		bool b_isMidi;
219 		bool b_isInstrumentMode;
220 		bool b_noteExist;
221 	};
222 	std::vector<AddMidiNoteVector> m_addMidiNoteVector;
223 
224 private:
225 	/**
226 	 * Constructor of the EventQueue class.
227 	 *
228 	 * It fills all #MAX_EVENTS slots of the #__events_buffer with
229 	 * #H2Core::EVENT_NONE and assigns itself to #__instance. Called by
230 	 * create_instance().
231 	 */
232 	EventQueue();
233 	/**
234 	 * Object holding the current EventQueue singleton. It is
235 	 * initialized with nullptr, set in EventQueue(), and
236 	 * accessed via get_instance().
237 	 */
238 	static EventQueue *__instance;
239 
240 	/**
241 	 * Continuously growing number indexing the event, which has
242 	 * been read from the EventQueue most recently.
243 	 *
244 	 * It is incremented with each call to pop_event().
245 	 */
246 	unsigned int __read_index;
247 	/**
248 	 * Continuously growing number indexing the event, which has
249 	 * been written to the EventQueue most recently.
250 	 *
251 	 * It is incremented with each call to push_event().
252 	 */
253 	unsigned int __write_index;
254 	/**
255 	 * Array of all events contained in the EventQueue.
256 	 *
257 	 * Its length is set to #MAX_EVENTS and it gets initialized
258 	 * with #H2Core::EVENT_NONE in EventQueue().
259 	 */
260 	Event __events_buffer[ MAX_EVENTS ];
261 };
262 
263 };
264 
265 #endif
266