1 /*
2  * Copyright (C) 2018-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 "audio/port.h"
21 #include "audio/port_identifier.h"
22 #include "plugins/plugin_identifier.h"
23 #include "utils/hash.h"
24 #include "utils/objects.h"
25 #include "utils/string.h"
26 
27 void
port_identifier_init(PortIdentifier * self)28 port_identifier_init (
29   PortIdentifier * self)
30 {
31   memset (self, 0, sizeof (PortIdentifier));
32   self->schema_version =
33     PORT_IDENTIFIER_SCHEMA_VERSION;
34   plugin_identifier_init (&self->plugin_id);
35 }
36 
37 #if 0
38 PortIdentifier *
39 port_identifier_new (void)
40 {
41   PortIdentifier * self =
42     object_new (PortIdentifier);
43   self->schema_version =
44     PORT_IDENTIFIER_SCHEMA_VERSION;
45 
46   self->track_pos = -1;
47   plugin_identifier_init (&self->plugin_id);
48 
49   return self;
50 }
51 #endif
52 
53 /**
54  * Port group comparator function where @ref p1 and
55  * @ref p2 are pointers to Port.
56  */
57 int
port_identifier_port_group_cmp(const void * p1,const void * p2)58 port_identifier_port_group_cmp (
59   const void* p1, const void* p2)
60 {
61   const Port * control1 = *(const Port **)p1;
62   const Port * control2 = *(const Port **)p2;
63 
64   g_return_val_if_fail (IS_PORT (control1), -1);
65   g_return_val_if_fail (IS_PORT (control2), -1);
66 
67   /* use index for now - this assumes that ports
68    * inside port groups are declared in sequence */
69   return
70     control1->id.port_index -
71     control2->id.port_index;
72 
73 #if 0
74   return
75     (control1->id.port_group &&
76      control2->id.port_group) ?
77       strcmp (
78         control1->id.port_group,
79         control2->id.port_group) : 0;
80 #endif
81 }
82 
83 /**
84  * Copy the identifier content from \ref src to
85  * \ref dest.
86  *
87  * @note This frees/allocates memory on \ref dest.
88  */
89 void
port_identifier_copy(PortIdentifier * dest,const PortIdentifier * src)90 port_identifier_copy (
91   PortIdentifier *       dest,
92   const PortIdentifier * src)
93 {
94   g_return_if_fail (dest != src);
95   dest->schema_version = src->schema_version;
96   string_copy_w_realloc (
97     &dest->label, src->label);
98   string_copy_w_realloc (
99     &dest->sym, src->sym);
100   string_copy_w_realloc (
101     &dest->uri, src->uri);
102   string_copy_w_realloc (
103     &dest->comment, src->comment);
104   dest->owner_type = src->owner_type;
105   dest->type = src->type;
106   dest->flow = src->flow;
107   dest->flags = src->flags;
108   dest->flags2 = src->flags2;
109   plugin_identifier_copy (
110     &dest->plugin_id, &src->plugin_id);
111   string_copy_w_realloc (
112     &dest->ext_port_id, src->ext_port_id);
113   string_copy_w_realloc (
114     &dest->port_group, src->port_group);
115   dest->track_name_hash = src->track_name_hash;
116   dest->port_index = src->port_index;
117 }
118 
119 /**
120  * Returns if the 2 PortIdentifier's are equal.
121  */
122 bool
port_identifier_is_equal(const PortIdentifier * src,const PortIdentifier * dest)123 port_identifier_is_equal (
124   const PortIdentifier * src,
125   const PortIdentifier * dest)
126 {
127   bool eq =
128     string_is_equal (dest->label, src->label) &&
129     string_is_equal (dest->uri, src->uri) &&
130     string_is_equal (dest->comment, src->comment) &&
131     dest->owner_type == src->owner_type &&
132     dest->type == src->type &&
133     dest->flow == src->flow &&
134     dest->flags == src->flags &&
135     dest->flags2 == src->flags2 &&
136     dest->track_name_hash == src->track_name_hash &&
137     string_is_equal (
138       dest->port_group, src->port_group) &&
139     string_is_equal (
140       dest->ext_port_id, src->ext_port_id);
141   if (dest->owner_type == PORT_OWNER_TYPE_PLUGIN)
142     {
143       eq =
144         eq &&
145         plugin_identifier_is_equal (
146           &dest->plugin_id, &src->plugin_id);
147     }
148 
149   /* if LV2 (has symbol) check symbol match,
150    * otherwise check index match */
151   if (dest->sym)
152     {
153       eq =
154         eq &&
155         string_is_equal (dest->sym, src->sym);
156     }
157   else
158     {
159       eq =
160         eq &&
161         dest->port_index == src->port_index;
162     }
163 
164   return eq;
165 }
166 
167 /**
168  * To be used as GEqualFunc.
169  */
170 int
port_identifier_is_equal_func(const void * a,const void * b)171 port_identifier_is_equal_func (
172   const void * a,
173   const void * b)
174 {
175   return
176     port_identifier_is_equal (
177       (const PortIdentifier *) a,
178       (const PortIdentifier *) b);
179 }
180 
181 void
port_identifier_print_to_str(const PortIdentifier * self,char * buf,size_t buf_sz)182 port_identifier_print_to_str (
183   const PortIdentifier * self,
184   char *                 buf,
185   size_t                 buf_sz)
186 {
187   snprintf (
188     buf, buf_sz,
189     "[PortIdentifier %p]\nlabel: %s\n"
190     "sym: %s\nuri: %s\ncomment: %s\nowner type: %s\n"
191     "type: %s\nflow: %s\nflags: %d %d\n"
192     "port group: %s\next port id: %s\n"
193     "track name hash: %u\nport idx: %d",
194     self,
195     self->label, self->sym, self->uri, self->comment,
196     port_owner_type_strings[self->owner_type].str,
197     port_type_strings[self->type].str,
198     port_flow_strings[self->flow].str,
199     self->flags, self->flags2, self->port_group,
200     self->ext_port_id, self->track_name_hash,
201     self->port_index);
202 }
203 
204 void
port_identifier_print(const PortIdentifier * self)205 port_identifier_print (
206   const PortIdentifier * self)
207 {
208   size_t size = 2000;
209   char buf[size];
210   port_identifier_print_to_str (self, buf, size);
211   g_message ("%s", buf);
212 }
213 
214 bool
port_identifier_validate(PortIdentifier * self)215 port_identifier_validate (
216   PortIdentifier * self)
217 {
218   g_return_val_if_fail (
219     self->schema_version ==
220       PORT_IDENTIFIER_SCHEMA_VERSION &&
221     plugin_identifier_validate (&self->plugin_id),
222     false);
223   return true;
224 }
225 
226 unsigned int
port_identifier_get_hash(const void * self)227 port_identifier_get_hash (
228   const void * self)
229 {
230   void * state = hash_create_state ();
231   const PortIdentifier * id =
232     (const PortIdentifier *) self;
233   unsigned int hash = 0;
234   if (id->label)
235     hash = hash ^ g_str_hash (id->label);
236   if (id->sym)
237     hash = hash ^ g_str_hash (id->sym);
238   if (id->uri)
239     hash = hash ^ g_str_hash (id->uri);
240   hash = hash ^ g_int_hash (&id->owner_type);
241   hash = hash ^ g_int_hash (&id->type);
242   hash = hash ^ g_int_hash (&id->flow);
243   hash = hash ^ g_int_hash (&id->flags);
244   hash = hash ^ g_int_hash (&id->flags2);
245   hash = hash ^ g_int_hash (&id->unit);
246   hash =
247     hash ^
248     hash_get_for_struct_full (
249       state, &id->plugin_id,
250       sizeof (PluginIdentifier));
251   if (id->port_group)
252     hash = hash ^ g_str_hash (id->port_group);
253   if (id->ext_port_id)
254     hash = hash ^ g_str_hash (id->ext_port_id);
255   hash = hash ^ id->track_name_hash;
256   hash = hash ^ g_int_hash (&id->port_index);
257   hash_free_state (state);
258   return hash;
259 }
260 
261 PortIdentifier *
port_identifier_clone(const PortIdentifier * src)262 port_identifier_clone (
263   const PortIdentifier * src)
264 {
265   PortIdentifier * self =
266     object_new (PortIdentifier);
267   self->schema_version =
268     PORT_IDENTIFIER_SCHEMA_VERSION;
269 
270   port_identifier_copy (self, src);
271 
272   return self;
273 }
274 
275 void
port_identifier_free_members(PortIdentifier * self)276 port_identifier_free_members (
277   PortIdentifier * self)
278 {
279   g_free_and_null (self->label);
280   g_free_and_null (self->sym);
281   g_free_and_null (self->uri);
282   g_free_and_null (self->comment);
283   g_free_and_null (self->port_group);
284   g_free_and_null (self->ext_port_id);
285   object_set_to_zero (self);
286 }
287 
288 void
port_identifier_free(PortIdentifier * self)289 port_identifier_free (
290   PortIdentifier * self)
291 {
292   port_identifier_free_members (self);
293   object_zero_and_free (self);
294 }
295 
296 void
port_identifier_free_func(void * self)297 port_identifier_free_func (
298   void * self)
299 {
300   port_identifier_free (
301     (PortIdentifier *) self);
302 }
303