1 /* -----------------------------------------------------------------------------
2  *
3  * Giada - Your Hardcore Loopmachine
4  *
5  * -----------------------------------------------------------------------------
6  *
7  * Copyright (C) 2010-2020 Giovanni A. Zuliani | Monocasual
8  *
9  * This file is part of Giada - Your Hardcore Loopmachine.
10  *
11  * Giada - Your Hardcore Loopmachine is free software: you can
12  * redistribute it and/or modify it under the terms of the GNU General
13  * Public License as published by the Free Software Foundation, either
14  * version 3 of the License, or (at your option) any later version.
15  *
16  * Giada - Your Hardcore Loopmachine is distributed in the hope that it
17  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
18  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  * See the GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with Giada - Your Hardcore Loopmachine. If not, see
23  * <http://www.gnu.org/licenses/>.
24  *
25  * -------------------------------------------------------------------------- */
26 
27 
28 #include <cassert>
29 #include <FL/Fl.H>
30 #include "core/model/model.h"
31 #include "core/const.h"
32 #include "core/clock.h"
33 #include "core/mixer.h"
34 #include "core/midiEvent.h"
35 #include "core/plugins/pluginHost.h"
36 #include "core/sequencer.h"
37 #include "core/mixerHandler.h"
38 #include "core/conf.h"
39 #include "core/recManager.h"
40 #include "utils/log.h"
41 #include "gui/dialogs/sampleEditor.h"
42 #include "gui/dialogs/mainWindow.h"
43 #include "gui/dialogs/warnings.h"
44 #include "gui/elems/mainWindow/mainIO.h"
45 #include "gui/elems/mainWindow/mainTimer.h"
46 #include "gui/elems/basics/dial.h"
47 #include "gui/elems/mainWindow/keyboard/keyboard.h"
48 #include "gui/elems/mainWindow/keyboard/channel.h"
49 #include "gui/elems/sampleEditor/volumeTool.h"
50 #include "gui/elems/sampleEditor/pitchTool.h"
51 #include "gui/elems/sampleEditor/panTool.h"
52 #include "glue/sampleEditor.h"
53 #include "glue/plugin.h"
54 #include "glue/main.h"
55 #include "events.h"
56 
57 
58 extern giada::v::gdMainWindow* G_MainWin;
59 
60 
61 namespace giada {
62 namespace c {
63 namespace events
64 {
65 namespace
66 {
pushEvent_(m::mixer::Event e,Thread t)67 void pushEvent_(m::mixer::Event e, Thread t)
68 {
69 	bool res = true;
70 	if (t == Thread::MAIN)
71 		res = m::mixer::UIevents.push(e);
72 	else
73 	if (t == Thread::MIDI)
74 		res = m::mixer::MidiEvents.push(e);
75 	else
76 		assert(false);
77 
78 	if (!res)
79 		G_DEBUG("[events] Queue full!\n");
80 }
81 } // {anonymous}
82 
83 
84 /* -------------------------------------------------------------------------- */
85 /* -------------------------------------------------------------------------- */
86 /* -------------------------------------------------------------------------- */
87 
88 
pressChannel(ID channelId,int velocity,Thread t)89 void pressChannel(ID channelId, int velocity, Thread t)
90 {
91 	m::MidiEvent e;
92 	e.setVelocity(velocity);
93 	pushEvent_({ m::mixer::EventType::KEY_PRESS, 0, {0, channelId, 0, e} }, t);
94 }
95 
96 
releaseChannel(ID channelId,Thread t)97 void releaseChannel(ID channelId, Thread t)
98 {
99 	pushEvent_({ m::mixer::EventType::KEY_RELEASE, 0, {0, channelId} }, t);
100 }
101 
102 
killChannel(ID channelId,Thread t)103 void killChannel(ID channelId, Thread t)
104 {
105 	pushEvent_({ m::mixer::EventType::KEY_KILL, 0, {0, channelId} }, t);
106 }
107 
108 
109 /* -------------------------------------------------------------------------- */
110 
111 
setChannelVolume(ID channelId,float v,Thread t)112 void setChannelVolume(ID channelId, float v, Thread t)
113 {
114 	v = std::clamp(v, 0.0f, G_MAX_VOLUME);
115 
116 	pushEvent_({ m::mixer::EventType::CHANNEL_VOLUME, 0, { 0, channelId, 0, {v} } }, t);
117 
118 	sampleEditor::onRefresh(t == Thread::MAIN, [v](v::gdSampleEditor& e) { e.volumeTool->update(v); });
119 
120 	if (t != Thread::MAIN) {
121 		Fl::lock();
122 		G_MainWin->keyboard->getChannel(channelId)->vol->value(v);
123 		Fl::unlock();
124 	}
125 }
126 
127 
128 /* -------------------------------------------------------------------------- */
129 
130 
setChannelPitch(ID channelId,float v,Thread t)131 void setChannelPitch(ID channelId, float v,  Thread t)
132 {
133 	v = std::clamp(v, G_MIN_PITCH, G_MAX_PITCH);
134 
135 	pushEvent_({ m::mixer::EventType::CHANNEL_PITCH, 0, { 0, channelId, 0, {v} } }, t);
136 
137 	sampleEditor::onRefresh(t == Thread::MAIN, [v](v::gdSampleEditor& e) { e.pitchTool->update(v); });
138 }
139 
140 
141 /* -------------------------------------------------------------------------- */
142 
143 
sendChannelPan(ID channelId,float v)144 void sendChannelPan(ID channelId, float v)
145 {
146 	v = std::clamp(v, 0.0f, G_MAX_PAN);
147 
148 	/* Pan event is currently triggered only by the main thread. */
149 	pushEvent_({ m::mixer::EventType::CHANNEL_PAN, 0, { 0, channelId, 0, {v} } }, Thread::MAIN);
150 
151 	sampleEditor::onRefresh(/*gui=*/true, [v](v::gdSampleEditor& e) { e.panTool->update(v); });
152 }
153 
154 /* -------------------------------------------------------------------------- */
155 
156 
toggleMuteChannel(ID channelId,Thread t)157 void toggleMuteChannel(ID channelId, Thread t)
158 {
159 	pushEvent_({ m::mixer::EventType::CHANNEL_MUTE, 0, {0, channelId} }, t);
160 }
161 
162 
toggleSoloChannel(ID channelId,Thread t)163 void toggleSoloChannel(ID channelId, Thread t)
164 {
165 	pushEvent_({ m::mixer::EventType::CHANNEL_SOLO, 0, {0, channelId} }, t);
166 }
167 
168 
169 /* -------------------------------------------------------------------------- */
170 
171 
toggleArmChannel(ID channelId,Thread t)172 void toggleArmChannel(ID channelId, Thread t)
173 {
174 	pushEvent_({ m::mixer::EventType::CHANNEL_TOGGLE_ARM, 0, {0, channelId} }, t);
175 }
176 
177 
toggleReadActionsChannel(ID channelId,Thread t)178 void toggleReadActionsChannel(ID channelId, Thread t)
179 {
180 	pushEvent_({ m::mixer::EventType::CHANNEL_TOGGLE_READ_ACTIONS, 0, {0, channelId} }, t);
181 }
182 
183 
killReadActionsChannel(ID channelId,Thread t)184 void killReadActionsChannel(ID channelId, Thread t)
185 {
186 	pushEvent_({ m::mixer::EventType::CHANNEL_KILL_READ_ACTIONS, 0, {0, channelId} }, t);
187 }
188 
189 
190 /* -------------------------------------------------------------------------- */
191 
192 
sendMidiToChannel(ID channelId,m::MidiEvent e,Thread t)193 void sendMidiToChannel(ID channelId, m::MidiEvent e, Thread t)
194 {
195 	pushEvent_({ m::mixer::EventType::MIDI, 0, {0, channelId, 0, e} }, t);
196 }
197 
198 
199 /* -------------------------------------------------------------------------- */
200 
201 
toggleMetronome()202 void toggleMetronome()
203 {
204 	m::sequencer::toggleMetronome();
205 }
206 
207 
208 /* -------------------------------------------------------------------------- */
209 
210 
setMasterInVolume(float v,Thread t)211 void setMasterInVolume(float v, Thread t)
212 {
213 	pushEvent_({ m::mixer::EventType::CHANNEL_VOLUME, 0, { 0, m::mixer::MASTER_IN_CHANNEL_ID, 0, {v} }}, t);
214 
215 	if (t != Thread::MAIN) {
216 		Fl::lock();
217 		G_MainWin->mainIO->setInVol(v);
218 		Fl::unlock();
219 	}
220 }
221 
222 
setMasterOutVolume(float v,Thread t)223 void setMasterOutVolume(float v, Thread t)
224 {
225 	pushEvent_({ m::mixer::EventType::CHANNEL_VOLUME, 0, { 0, m::mixer::MASTER_OUT_CHANNEL_ID, 0, {v} }}, t);
226 
227 	if (t != Thread::MAIN) {
228 		Fl::lock();
229 		G_MainWin->mainIO->setOutVol(v);
230 		Fl::unlock();
231 	}
232 }
233 
234 
235 /* -------------------------------------------------------------------------- */
236 
237 
multiplyBeats()238 void multiplyBeats()
239 {
240 	main::setBeats(m::clock::getBeats() * 2, m::clock::getBars());
241 }
242 
243 
divideBeats()244 void divideBeats()
245 {
246 	main::setBeats(m::clock::getBeats() / 2, m::clock::getBars());
247 }
248 
249 
250 /* -------------------------------------------------------------------------- */
251 
252 
startSequencer(Thread t)253 void startSequencer(Thread t)
254 {
255 	pushEvent_({ m::mixer::EventType::SEQUENCER_START, 0 }, t);
256 	m::conf::conf.recTriggerMode = RecTriggerMode::NORMAL;
257 }
258 
259 
stopSequencer(Thread t)260 void stopSequencer(Thread t)
261 {
262 	pushEvent_({ m::mixer::EventType::SEQUENCER_STOP, 0 }, t);
263 }
264 
265 
toggleSequencer(Thread t)266 void toggleSequencer(Thread t)
267 {
268 	m::clock::isRunning() ? stopSequencer(t) : startSequencer(t);
269 }
270 
271 
rewindSequencer(Thread t)272 void rewindSequencer(Thread t)
273 {
274 	pushEvent_({ m::mixer::EventType::SEQUENCER_REWIND_REQ, 0 }, t);
275 }
276 
277 
278 /* -------------------------------------------------------------------------- */
279 
280 
toggleActionRecording()281 void toggleActionRecording()
282 {
283 	m::recManager::toggleActionRec(m::conf::conf.recTriggerMode);
284 }
285 
286 
toggleInputRecording()287 void toggleInputRecording()
288 {
289 	m::recManager::toggleInputRec(m::conf::conf.recTriggerMode);
290 }
291 
292 
293 /* -------------------------------------------------------------------------- */
294 
295 
296 #ifdef WITH_VST
setPluginParameter(ID pluginId,int paramIndex,float value,bool gui)297 void setPluginParameter(ID pluginId, int paramIndex, float value, bool gui)
298 {
299 	m::pluginHost::setPluginParameter(pluginId, paramIndex, value);
300 	c::plugin::updateWindow(pluginId, gui);
301 }
302 #endif
303 }}} // giada::c::events::
304