1 /*
2 * Copyright (C) 2019-2021 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 <stdlib.h>
21
22 #include "audio/automation_track.h"
23 #include "audio/port.h"
24 #include "audio/modulator_macro_processor.h"
25 #include "audio/modulator_track.h"
26 #include "audio/router.h"
27 #include "audio/track.h"
28 #include "gui/backend/event.h"
29 #include "gui/backend/event_manager.h"
30 #include "gui/widgets/main_window.h"
31 #include "project.h"
32 #include "utils/arrays.h"
33 #include "utils/dialogs.h"
34 #include "utils/flags.h"
35 #include "utils/mem.h"
36 #include "utils/objects.h"
37 #include "utils/object_utils.h"
38 #include "zrythm_app.h"
39
40 #include <gtk/gtk.h>
41 #include <glib/gi18n.h>
42
43 /**
44 * Inits the modulator track.
45 */
46 void
modulator_track_init(Track * self)47 modulator_track_init (
48 Track * self)
49 {
50 self->type = TRACK_TYPE_MODULATOR;
51 self->main_height = TRACK_DEF_HEIGHT / 2;
52
53 gdk_rgba_parse (&self->color, "#222222");
54 self->icon_name = g_strdup ("modulator");
55
56 const int max_macros = 8;
57 self->num_visible_modulator_macros = max_macros;
58 for (int i = 0; i < max_macros; i++)
59 {
60 self->modulator_macros[i] =
61 modulator_macro_processor_new (self, i);
62 }
63 self->num_modulator_macros = max_macros;
64
65 /* set invisible */
66 self->visible = false;
67 }
68
69 /**
70 * Creates the default modulator track.
71 */
72 Track *
modulator_track_default(int track_pos)73 modulator_track_default (
74 int track_pos)
75 {
76 Track * self =
77 track_new (
78 TRACK_TYPE_MODULATOR, track_pos,
79 _("Modulators"), F_WITHOUT_LANE);
80
81 return self;
82 }
83
84 /**
85 * Inserts and connects a Modulator to the Track.
86 *
87 * @param replace_mode Whether to perform the
88 * operation in replace mode (replace current
89 * modulator if true, not touching other
90 * modulators, or push other modulators forward
91 * if false).
92 */
93 void
modulator_track_insert_modulator(Track * self,int slot,Plugin * modulator,bool replace_mode,bool confirm,bool gen_automatables,bool recalc_graph,bool pub_events)94 modulator_track_insert_modulator (
95 Track * self,
96 int slot,
97 Plugin * modulator,
98 bool replace_mode,
99 bool confirm,
100 bool gen_automatables,
101 bool recalc_graph,
102 bool pub_events)
103 {
104 g_return_if_fail (
105 IS_TRACK (self) && IS_PLUGIN (modulator) &&
106 slot <= self->num_modulators);
107
108 if (replace_mode)
109 {
110 Plugin * existing_pl =
111 slot < self->num_modulators ?
112 self->modulators[slot] : NULL;
113 if (existing_pl)
114 {
115 /* confirm if another plugin exists */
116 if (confirm)
117 {
118 GtkDialog * dialog =
119 dialogs_get_overwrite_plugin_dialog (
120 GTK_WINDOW (MAIN_WINDOW));
121 int result =
122 gtk_dialog_run (dialog);
123 gtk_widget_destroy (GTK_WIDGET (dialog));
124
125 /* do nothing if not accepted */
126 if (result != GTK_RESPONSE_ACCEPT)
127 {
128 return;
129 }
130 }
131
132 /* free current plugin */
133 if (existing_pl)
134 {
135 modulator_track_remove_modulator (
136 self, slot, F_REPLACING,
137 F_DELETING_PLUGIN,
138 F_NOT_DELETING_TRACK,
139 F_NO_RECALC_GRAPH);
140 }
141 }
142
143 g_message (
144 "Inserting modulator %s at %s:%d",
145 modulator->setting->descr->name, self->name, slot);
146 if (slot == self->num_modulators)
147 {
148 array_double_size_if_full (
149 self->modulators, self->num_modulators,
150 self->modulators_size, Modulator *);
151 self->num_modulators++;
152 }
153 }
154 else
155 {
156 array_double_size_if_full (
157 self->modulators, self->num_modulators,
158 self->modulators_size, Modulator *);
159
160 /* push other modulators forward (make
161 * space for new modulator) */
162 self->num_modulators++;
163 for (int i = self->num_modulators - 1;
164 i > slot; i--)
165 {
166 self->modulators[i] =
167 self->modulators[i - 1];
168 g_message (
169 "setting modulator %s from slot %d "
170 "to slot %d",
171 self->modulators[i]->setting->descr->name,
172 i - 1, i);
173 plugin_set_track_and_slot (
174 self->modulators[i],
175 track_get_name_hash (self),
176 PLUGIN_SLOT_MODULATOR, i);
177 }
178 }
179
180 /* add the modulator */
181 self->modulators[slot] = modulator;
182 g_message (
183 "setting modulator %s to slot %d",
184 modulator->setting->descr->name, slot);
185
186 plugin_set_track_and_slot (
187 modulator,
188 track_get_name_hash (self),
189 PLUGIN_SLOT_MODULATOR,
190 slot);
191
192 if (gen_automatables)
193 {
194 plugin_generate_automation_tracks (
195 modulator, self);
196 }
197
198 if (pub_events)
199 {
200 EVENTS_PUSH (ET_MODULATOR_ADDED, modulator);
201 }
202
203 if (recalc_graph)
204 {
205 router_recalc_graph (ROUTER, F_NOT_SOFT);
206 }
207 }
208
209 /**
210 * Removes a plugin at pos from the track.
211 *
212 * @param replacing Whether replacing the modulator.
213 * If this is false, modulators after this slot
214 * will be pushed back.
215 * @param deleting_modulator
216 * @param deleting_track If true, the automation
217 * tracks associated with the plugin are not
218 * deleted at this time.
219 * @param recalc_graph Recalculate mixer graph.
220 */
221 void
modulator_track_remove_modulator(Track * self,int slot,bool replacing,bool deleting_modulator,bool deleting_track,bool recalc_graph)222 modulator_track_remove_modulator (
223 Track * self,
224 int slot,
225 bool replacing,
226 bool deleting_modulator,
227 bool deleting_track,
228 bool recalc_graph)
229 {
230 Plugin * plugin = self->modulators[slot];
231 g_return_if_fail (IS_PLUGIN (plugin));
232 g_return_if_fail (
233 plugin->id.track_name_hash ==
234 track_get_name_hash (self));
235
236 plugin_remove_ats_from_automation_tracklist (
237 plugin, deleting_modulator,
238 !deleting_track && !deleting_modulator);
239
240 g_message (
241 "Removing %s from %s:%d",
242 plugin->setting->descr->name, self->name, slot);
243
244 /* unexpose all JACK ports */
245 plugin_expose_ports (
246 plugin, F_NOT_EXPOSE, true, true);
247
248 /* if deleting plugin disconnect the plugin
249 * entirely */
250 if (deleting_modulator)
251 {
252 if (plugin_is_selected (plugin))
253 {
254 mixer_selections_remove_slot (
255 MIXER_SELECTIONS, plugin->id.slot,
256 PLUGIN_SLOT_MODULATOR, F_PUBLISH_EVENTS);
257 }
258
259 plugin_disconnect (plugin);
260 object_free_w_func_and_null (
261 plugin_free, plugin);
262 }
263
264 if (!replacing)
265 {
266 for (int i = slot;
267 i < self->num_modulators - 1; i++)
268 {
269 self->modulators[i] =
270 self->modulators[i + 1];
271 plugin_set_track_and_slot (
272 self->modulators[i],
273 track_get_name_hash (self),
274 PLUGIN_SLOT_MODULATOR, i);
275 }
276 self->num_modulators--;
277 }
278
279 if (recalc_graph)
280 {
281 router_recalc_graph (ROUTER, F_NOT_SOFT);
282 }
283 }
284