1 /*
2 * Copyright (C) 2020 Alexandros Theodotou <alex at zrythm dot org>
3 *
4 * This file is part of Zrythm
5 *
6 * Zrythm is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * Zrythm is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with Zrythm. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "actions/midi_mapping_action.h"
21 #include "audio/channel.h"
22 #include "audio/router.h"
23 #include "gui/backend/event.h"
24 #include "gui/backend/event_manager.h"
25 #include "gui/widgets/main_window.h"
26 #include "plugins/plugin.h"
27 #include "project.h"
28 #include "utils/flags.h"
29 #include "utils/objects.h"
30 #include "zrythm_app.h"
31
32 #include <glib/gi18n.h>
33
34 void
midi_mapping_action_init_loaded(MidiMappingAction * self)35 midi_mapping_action_init_loaded (
36 MidiMappingAction * self)
37 {
38 }
39
40 /**
41 * Creates a new action.
42 */
43 UndoableAction *
midi_mapping_action_new_enable(int idx,bool enable,GError ** error)44 midi_mapping_action_new_enable (
45 int idx,
46 bool enable,
47 GError ** error)
48 {
49 MidiMappingAction * self =
50 object_new (MidiMappingAction);
51 UndoableAction * ua = (UndoableAction *) self;
52 undoable_action_init (ua, UA_MIDI_MAPPING);
53
54 self->type =
55 enable ?
56 MIDI_MAPPING_ACTION_ENABLE :
57 MIDI_MAPPING_ACTION_DISABLE;
58 self->idx = idx;
59
60 return ua;
61 }
62
63 /**
64 * Creates a new action.
65 */
66 UndoableAction *
midi_mapping_action_new_bind(midi_byte_t * buf,ExtPort * device_port,Port * dest_port,GError ** error)67 midi_mapping_action_new_bind (
68 midi_byte_t * buf,
69 ExtPort * device_port,
70 Port * dest_port,
71 GError ** error)
72 {
73 MidiMappingAction * self =
74 object_new (MidiMappingAction);
75 UndoableAction * ua = (UndoableAction *) self;
76 undoable_action_init (ua, UA_MIDI_MAPPING);
77
78 self->type = MIDI_MAPPING_ACTION_BIND;
79 memcpy (self->buf, buf, 3 * sizeof (midi_byte_t));
80 if (device_port)
81 {
82 self->dev_port = ext_port_clone (device_port);
83 }
84 self->dest_port_id = dest_port->id;
85
86 return ua;
87 }
88
89 /**
90 * Creates a new action.
91 */
92 UndoableAction *
midi_mapping_action_new_unbind(int idx,GError ** error)93 midi_mapping_action_new_unbind (
94 int idx,
95 GError ** error)
96 {
97 MidiMappingAction * self =
98 object_new (MidiMappingAction);
99 UndoableAction * ua = (UndoableAction *) self;
100 undoable_action_init (ua, UA_MIDI_MAPPING);
101
102 self->type = MIDI_MAPPING_ACTION_UNBIND;
103 self->idx = idx;
104
105 return ua;
106 }
107
108 MidiMappingAction *
midi_mapping_action_clone(const MidiMappingAction * src)109 midi_mapping_action_clone (
110 const MidiMappingAction * src)
111 {
112 MidiMappingAction * self =
113 object_new (MidiMappingAction);
114 self->parent_instance = src->parent_instance;
115
116 self->idx = src->idx;
117 port_identifier_copy (
118 &self->dest_port_id, &src->dest_port_id);
119 if (src->dev_port)
120 {
121 self->dev_port =
122 ext_port_clone (src->dev_port);
123 }
124 memcpy (
125 self->buf, src->buf, 3 * sizeof (midi_byte_t));
126
127 return self;
128 }
129
130 /**
131 * Wrapper of midi_mapping_action_new_enable().
132 */
133 bool
midi_mapping_action_perform_enable(int idx,bool enable,GError ** error)134 midi_mapping_action_perform_enable (
135 int idx,
136 bool enable,
137 GError ** error)
138 {
139 UNDO_MANAGER_PERFORM_AND_PROPAGATE_ERR (
140 midi_mapping_action_new_enable,
141 error, idx, enable, error);
142 }
143
144 /**
145 * Wrapper of midi_mapping_action_new_bind().
146 */
147 bool
midi_mapping_action_perform_bind(midi_byte_t * buf,ExtPort * device_port,Port * dest_port,GError ** error)148 midi_mapping_action_perform_bind (
149 midi_byte_t * buf,
150 ExtPort * device_port,
151 Port * dest_port,
152 GError ** error)
153 {
154 UNDO_MANAGER_PERFORM_AND_PROPAGATE_ERR (
155 midi_mapping_action_new_bind,
156 error, buf, device_port, dest_port, error);
157 }
158
159 /**
160 * Wrapper of midi_mapping_action_new_unbind().
161 */
162 bool
midi_mapping_action_perform_unbind(int idx,GError ** error)163 midi_mapping_action_perform_unbind (
164 int idx,
165 GError ** error)
166 {
167 UNDO_MANAGER_PERFORM_AND_PROPAGATE_ERR (
168 midi_mapping_action_new_unbind,
169 error, idx, error);
170 }
171
172 static void
bind_or_unbind(MidiMappingAction * self,bool bind)173 bind_or_unbind (
174 MidiMappingAction * self,
175 bool bind)
176 {
177 if (bind)
178 {
179 Port * port =
180 port_find_from_identifier (
181 &self->dest_port_id);
182 self->idx = MIDI_MAPPINGS->num_mappings;
183 midi_mappings_bind_device (
184 MIDI_MAPPINGS, self->buf, self->dev_port,
185 port, F_NO_PUBLISH_EVENTS);
186 }
187 else
188 {
189 MidiMapping * mapping =
190 MIDI_MAPPINGS->mappings[self->idx];
191 memcpy (
192 self->buf, mapping->key,
193 3 * sizeof (midi_byte_t));
194 if (self->dev_port)
195 {
196 ext_port_free (self->dev_port);
197 }
198 if (mapping->device_port)
199 {
200 self->dev_port =
201 ext_port_clone (mapping->device_port);
202 }
203 self->dest_port_id = mapping->dest_id;
204 midi_mappings_unbind (
205 MIDI_MAPPINGS, self->idx,
206 F_NO_PUBLISH_EVENTS);
207 }
208 }
209
210 int
midi_mapping_action_do(MidiMappingAction * self,GError ** error)211 midi_mapping_action_do (
212 MidiMappingAction * self,
213 GError ** error)
214 {
215 switch (self->type)
216 {
217 case MIDI_MAPPING_ACTION_ENABLE:
218 midi_mapping_set_enabled (
219 MIDI_MAPPINGS->mappings[self->idx], true);
220 break;
221 case MIDI_MAPPING_ACTION_DISABLE:
222 midi_mapping_set_enabled (
223 MIDI_MAPPINGS->mappings[self->idx], false);
224 break;
225 case MIDI_MAPPING_ACTION_BIND:
226 bind_or_unbind (self, true);
227 break;
228 case MIDI_MAPPING_ACTION_UNBIND:
229 bind_or_unbind (self, false);
230 break;
231 default:
232 break;
233 }
234
235 EVENTS_PUSH (ET_MIDI_BINDINGS_CHANGED, NULL);
236
237 return 0;
238 }
239
240 /**
241 * Edits the plugin.
242 */
243 int
midi_mapping_action_undo(MidiMappingAction * self,GError ** error)244 midi_mapping_action_undo (
245 MidiMappingAction * self,
246 GError ** error)
247 {
248 switch (self->type)
249 {
250 case MIDI_MAPPING_ACTION_ENABLE:
251 midi_mapping_set_enabled (
252 MIDI_MAPPINGS->mappings[self->idx], false);
253 break;
254 case MIDI_MAPPING_ACTION_DISABLE:
255 midi_mapping_set_enabled (
256 MIDI_MAPPINGS->mappings[self->idx], true);
257 break;
258 case MIDI_MAPPING_ACTION_BIND:
259 bind_or_unbind (self, false);
260 break;
261 case MIDI_MAPPING_ACTION_UNBIND:
262 bind_or_unbind (self, true);
263 break;
264 default:
265 break;
266 }
267
268 EVENTS_PUSH (ET_MIDI_BINDINGS_CHANGED, NULL);
269
270 return 0;
271 }
272
273 char *
midi_mapping_action_stringize(MidiMappingAction * self)274 midi_mapping_action_stringize (
275 MidiMappingAction * self)
276 {
277 switch (self->type)
278 {
279 case MIDI_MAPPING_ACTION_ENABLE:
280 return g_strdup (_("MIDI mapping enable"));
281 break;
282 case MIDI_MAPPING_ACTION_DISABLE:
283 return g_strdup (_("MIDI mapping disable"));
284 break;
285 case MIDI_MAPPING_ACTION_BIND:
286 return g_strdup (_("MIDI mapping bind"));
287 break;
288 case MIDI_MAPPING_ACTION_UNBIND:
289 return g_strdup (_("MIDI mapping unbind"));
290 break;
291 default:
292 g_warn_if_reached ();
293 break;
294 }
295
296 g_return_val_if_reached (NULL);
297 }
298
299 void
midi_mapping_action_free(MidiMappingAction * self)300 midi_mapping_action_free (
301 MidiMappingAction * self)
302 {
303 object_free_w_func_and_null (
304 ext_port_free, self->dev_port);
305
306 object_zero_and_free (self);
307 }
308