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