1 /*
2 * Copyright (C) 2020-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 "actions/port_connection_action.h"
21 #include "audio/port.h"
22 #include "audio/router.h"
23 #include "gui/backend/event.h"
24 #include "gui/backend/event_manager.h"
25 #include "project.h"
26 #include "utils/flags.h"
27 #include "utils/objects.h"
28 #include "zrythm_app.h"
29
30 #include <glib/gi18n.h>
31
32 void
port_connection_action_init_loaded(PortConnectionAction * self)33 port_connection_action_init_loaded (
34 PortConnectionAction * self)
35 {
36 /* no need */
37 }
38
39 /**
40 * Create a new action.
41 */
42 UndoableAction *
port_connection_action_new(PortConnectionActionType type,PortIdentifier * src_id,PortIdentifier * dest_id,float new_val,GError ** error)43 port_connection_action_new (
44 PortConnectionActionType type,
45 PortIdentifier * src_id,
46 PortIdentifier * dest_id,
47 float new_val,
48 GError ** error)
49 {
50 PortConnectionAction * self =
51 object_new (PortConnectionAction);
52 UndoableAction * ua = (UndoableAction *) self;
53 undoable_action_init (ua, UA_PORT_CONNECTION);
54
55 /* check for existing connection to get values */
56 const PortConnection * conn =
57 port_connections_manager_find_connection (
58 PORT_CONNECTIONS_MGR, src_id, dest_id);
59 if (conn)
60 self->connection = port_connection_clone (conn);
61 else
62 self->connection =
63 port_connection_new (
64 src_id, dest_id, 1.f, F_NOT_LOCKED,
65 F_ENABLE);
66 self->type = type;
67 self->val = new_val;
68
69 return ua;
70 }
71
72 PortConnectionAction *
port_connection_action_clone(const PortConnectionAction * src)73 port_connection_action_clone (
74 const PortConnectionAction * src)
75 {
76 PortConnectionAction * self =
77 object_new (PortConnectionAction);
78 self->parent_instance = src->parent_instance;
79
80 self->type = src->type;
81 self->connection =
82 port_connection_clone (src->connection);
83 self->val = src->val;
84
85 return self;
86 }
87
88 bool
port_connection_action_perform(PortConnectionActionType type,PortIdentifier * src_id,PortIdentifier * dest_id,float new_val,GError ** error)89 port_connection_action_perform (
90 PortConnectionActionType type,
91 PortIdentifier * src_id,
92 PortIdentifier * dest_id,
93 float new_val,
94 GError ** error)
95 {
96 UNDO_MANAGER_PERFORM_AND_PROPAGATE_ERR (
97 port_connection_action_new,
98 error, type, src_id, dest_id, new_val,
99 error);
100 }
101
102 static int
port_connection_action_do_or_undo(PortConnectionAction * self,bool _do,GError ** error)103 port_connection_action_do_or_undo (
104 PortConnectionAction * self,
105 bool _do,
106 GError ** error)
107 {
108 Port * src =
109 port_find_from_identifier (
110 self->connection->src_id);
111 Port * dest =
112 port_find_from_identifier (
113 self->connection->dest_id);
114 g_return_val_if_fail (src && dest, -1);
115 PortConnection * prj_connection =
116 port_connections_manager_find_connection (
117 PORT_CONNECTIONS_MGR,
118 self->connection->src_id,
119 self->connection->dest_id);
120
121 switch (self->type)
122 {
123 case PORT_CONNECTION_CONNECT:
124 case PORT_CONNECTION_DISCONNECT:
125 if ((self->type ==
126 PORT_CONNECTION_CONNECT && _do) ||
127 (self->type ==
128 PORT_CONNECTION_DISCONNECT && !_do))
129 {
130 if (!ports_can_be_connected (src, dest))
131 {
132 g_warning (
133 "ports cannot be connected");
134 return -1;
135 }
136 port_connections_manager_ensure_connect (
137 PORT_CONNECTIONS_MGR,
138 &src->id, &dest->id, 1.f,
139 F_NOT_LOCKED, F_ENABLE);
140
141 /* set base value if cv -> control */
142 if (src->id.type == TYPE_CV &&
143 dest->id.type == TYPE_CONTROL)
144 dest->base_value = dest->control;
145 }
146 else
147 {
148 port_connections_manager_ensure_disconnect (
149 PORT_CONNECTIONS_MGR,
150 &src->id, &dest->id);
151 }
152 router_recalc_graph (ROUTER, F_NOT_SOFT);
153 break;
154 case PORT_CONNECTION_ENABLE:
155 prj_connection->enabled = _do ? true : false;
156 break;
157 case PORT_CONNECTION_DISABLE:
158 prj_connection->enabled = _do ? false : true;
159 break;
160 case PORT_CONNECTION_CHANGE_MULTIPLIER:
161 {
162 float val_before =
163 prj_connection->multiplier;
164 prj_connection->multiplier = self->val;
165 self->val = val_before;
166 }
167 break;
168 default:
169 break;
170 }
171
172 EVENTS_PUSH (ET_PORT_CONNECTION_CHANGED, NULL);
173
174 return 0;
175 }
176
177 int
port_connection_action_do(PortConnectionAction * self,GError ** error)178 port_connection_action_do (
179 PortConnectionAction * self,
180 GError ** error)
181 {
182 return
183 port_connection_action_do_or_undo (
184 self, true, error);
185 }
186
187 int
port_connection_action_undo(PortConnectionAction * self,GError ** error)188 port_connection_action_undo (
189 PortConnectionAction * self,
190 GError ** error)
191 {
192 return
193 port_connection_action_do_or_undo (
194 self, false, error);
195 }
196
197 char *
port_connection_action_stringize(PortConnectionAction * self)198 port_connection_action_stringize (
199 PortConnectionAction * self)
200 {
201 switch (self->type)
202 {
203 case PORT_CONNECTION_CONNECT:
204 return g_strdup (_("Connect ports"));
205 break;
206 case PORT_CONNECTION_DISCONNECT:
207 return g_strdup (_("Disconnect ports"));
208 break;
209 case PORT_CONNECTION_ENABLE:
210 return g_strdup (_("Enable port connection"));
211 break;
212 case PORT_CONNECTION_DISABLE:
213 return g_strdup (_("Disable port connection"));
214 break;
215 case PORT_CONNECTION_CHANGE_MULTIPLIER:
216 return g_strdup (_("Change port connection"));
217 break;
218 default:
219 g_warn_if_reached ();
220 }
221 g_return_val_if_reached (NULL);
222 }
223
224 void
port_connection_action_free(PortConnectionAction * self)225 port_connection_action_free (
226 PortConnectionAction * self)
227 {
228 object_free_w_func_and_null (
229 port_connection_free, self->connection);
230
231 object_zero_and_free (self);
232 }
233