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